Why my scrollbars are not updating their total scroll size when content size changes?
-
I'm trying to create a view, representing an a4 page which may be scrolled, and in which the user may zoom in or out.
I created a prototype for a such view, available in the below code:
import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Window 2.15 import QtQuick.Shapes 1.15 ApplicationWindow { // advanced properties property int m_PageWidth: 794//2480 property int m_PageHeight: 1123//3508 // common properties id: ctPageView objectName: "ctPageView" visible: true width: 800 height: 600 /** * Page viewport */ Rectangle { // common properties id: rcPageViewport objectName: "rcPageViewport" anchors.fill: parent clip: true /** * Page mouse area */ MouseArea { // advanced properties property var m_Target: parent property int m_PrevX: 0 property int m_PrevY: 0 property real m_ScaleFactor: 1 property bool m_Panning: false // common properties id: maPage objectName: "maPage" anchors.fill: parent hoverEnabled: true /// called when mouse wheel was rolled above page onWheel: function(mouseWheel) { if (mouseWheel.modifiers & Qt.ControlModifier) { let offset = mouseWheel.angleDelta.y * 0.001; m_ScaleFactor += offset; //rcPageContent.pageScaleChanged(m_ScaleFactor); return; } mouseWheel.accepted = true; } } Rectangle { id: rcPageContainer objectName: "rcPageContainer" x: (rcPageViewport.width < width) ? -sbHorz.position * width : 0 y: (rcPageViewport.height < height) ? -sbVert.position * height : 0 width: m_PageWidth * maPage.m_ScaleFactor height: m_PageHeight * maPage.m_ScaleFactor transform: Scale { origin.x: 0 origin.y: 0 xScale: maPage.m_ScaleFactor yScale: maPage.m_ScaleFactor } Rectangle { x: 0 y: 0 width: 100 height: 80 color: "red" } Rectangle { x: m_PageWidth - width y: 0 width: 100 height: 80 color: "green" } Rectangle { x: 0 y: m_PageHeight - height width: 100 height: 80 color: "blue" } Rectangle { x: m_PageWidth - width y: m_PageHeight - height width: 100 height: 80 color: "yellow" } } /** * Horizontal scrollbar */ ScrollBar { // common properties id: sbHorz hoverEnabled: true active: hovered || pressed orientation: Qt.Horizontal size: rcPageViewport.width / rcPageContainer.width anchors.left: parent.left anchors.right: parent.right anchors.bottom: parent.bottom anchors.rightMargin: sbVert.width } /** * Vertical scrollbar */ ScrollBar { // common properties id: sbVert hoverEnabled: true active: hovered || pressed orientation: Qt.Vertical size: rcPageViewport.height / rcPageContainer.height anchors.top: parent.top anchors.right: parent.right anchors.bottom: parent.bottom anchors.bottomMargin: sbHorz.height } /// called when page viewport width changed onWidthChanged: { sbHorz.size = rcPageViewport.width / rcPageContainer.width sbHorz.position = Math.min(Math.max(sbHorz.position, 0.0), 1.0 - (sbHorz.size)); } /// called when page viewport height changed onHeightChanged: { sbVert.size = rcPageViewport.height / rcPageContainer.height sbVert.position = Math.min(Math.max(sbVert.position, 0.0), 1.0 - (sbVert.size)); } } }
With this code, I can scroll the page, as well as zoom in or out when I roll the mouse wheel. However, every time I change the zoom level, the scroll size is not updated, despite of all my efforts to update the page content size.
To zoom the page, I use the
transform
property of myRectangle
component, and I know that this property doesn't affect the width and height of the rectangle. However I also explicitly change the page content width and height, but despite of that, the scrollbars doesn't update the scroll total size.I also tried to use a
Flickable
view, in order to let Qt take care of he scrollbars, however a such component interfere strongly with myMouseArea
, and I need it to perform very important operations that I cannot do without (not joined in the above sample code). For that reason I don't want to use aFlickable
here.What I'm I doing wrong in the above code, and how should I modify it to keep my scroll size up to date while I change the zoom level? Or what is the correct way to implement a zoom onto a scrollable view in qml?
-
@jeanmilost
Your logic seems to be correct.
What you have to do is to move the re-calculation of Scrollbar size & position to the RectanglercPageContainer
because you are applying scale for that.Rectangle { id: rcPageContainer objectName: "rcPageContainer" ... /// called when page viewport width changed onWidthChanged: { sbHorz.size = rcPageViewport.width / rcPageContainer.width sbHorz.position = Math.min(Math.max(sbHorz.position, 0.0), 1.0 - (sbHorz.size)); } /// called when page viewport height changed onHeightChanged: { sbVert.size = rcPageViewport.height / rcPageContainer.height sbVert.position = Math.min(Math.max(sbVert.position, 0.0), 1.0 - (sbVert.size)); } }