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!


  • Moderators

    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.



  • @sierdzio

    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?


  • Moderators

    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

Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.