Moving contents on MouseArea hover
-
Hi there!
On this screenshot I have a big image (3840x2160) in a small window (640x480) and those dark spots on the sides. Moving the mouse inside these areas should move the picture either to the left or to the right until either the right or the left border of the image hits the corresponding border of the window. The speed of the movement should depend on how close the mouse is to the border of the window.
I got this code now:
import QtQuick 2.4 import QtQuick.Controls 1.3 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 ApplicationWindow { title: qsTr("Hello World") width: 640 height: 480 visible: true Image { id: image width: 3840 height: 2160 sourceSize: Qt.size(3840, 2160) source: "qrc:/image.jpg" } Rectangle { id: leftIndicator width: 64 anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom color: Qt.rgba(0,0,0,0.25) } Rectangle { id: rightIndicator width: 64 anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom color: Qt.rgba(0,0,0,0.25) } MouseArea { anchors.fill: leftIndicator hoverEnabled: true onEntered: { while(containsMouse) { /* this is an Infinite loop */ } } } MouseArea { anchors.fill: rightIndicator hoverEnabled: true } }
I thought that when the mouse enters the MouseArea it should change the pictures position until it reaches it's end (the pictures transformation should not be bigger than the difference between the width of the window and the width of the whole picture) while the mouse is hovering that area.
I end up having an infinite loop blocking the update of the the mouse position and the containsMouse property. The whole application becomes unresponsive.
Could somebody tell me how this problem could be solved correctly?
Thank you in advance!
-
This is what I would do. In implrementation of onEntered, start a Timer. In the timer's onTriggered slot, push the flickable. You can modify how often the view is pushed by modifying the timer's interval.
-
Now I got it, thank you!
here is the code:import QtQuick 2.4 import QtQuick.Controls 1.3 import QtQuick.Window 2.2 ApplicationWindow { title: qsTr("Flickable") width: 1024 height: 768 visible: true Flickable { id: flickable anchors.fill: parent interactive: true contentWidth: image.width contentHeight: image.height flickableDirection: Flickable.HorizontalFlick boundsBehavior: Flickable.StopAtBounds Image { id: image width: 3840 height: 768 sourceSize: Qt.size(3840, 768) source: "qrc:/image.jpg" } } MouseArea { id: leftTrigger width: 256 anchors.left: parent.left anchors.top: parent.top anchors.bottom: parent.bottom hoverEnabled: true Timer { id: moveLeftTimer interval: 1 repeat: true onTriggered: { if(flickable.contentX - (parent.width - parent.mouseX) / 32 > 0) { flickable.contentX -= (parent.width - parent.mouseX) / 32 } else { flickable.contentX = 0 } } } onEntered: { moveLeftTimer.start() } onExited: { moveLeftTimer.stop() } } MouseArea { id: rightTrigger width: 256 anchors.right: parent.right anchors.top: parent.top anchors.bottom: parent.bottom hoverEnabled: true Timer { id: moveRightTimer interval: 1 repeat: true onTriggered: { if(flickable.contentX + parent.mouseX / 32 < flickable.contentWidth - flickable.width) { flickable.contentX += parent.mouseX / 32 } else { flickable.contentX = flickable.contentWidth - flickable.width } } } onEntered: { moveRightTimer.start() } onExited: { moveRightTimer.stop() } } }
Still I think this is rather a hack than a clean solution, because of the weak animation performance due to the 1 millisecond timer interval (micro stuttering)
There must be a better solution to this, don't you think so?
-
OK, here are my suggestions:
- use Flickable's flick() method link. It should work better than your solution, be more fluid and natural-looking
- 1ms timer resolution is completely useless: QtQuick updates the screen (paints a new frame) every 16.6 ms to achieve constant 60 Hz refresh rate. So you are wasting time and CPU power by invoking it 16 times more often than the software can pain it ;-) I'd suggest setting it to at least 16ms, but in reality I would probably use 50-100ms and tweak it to look good using flick() method mentioned above