Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. [SOLVED] How do I get the mouse position in a flickable after flicking?
Forum Updated to NodeBB v4.3 + New Features

[SOLVED] How do I get the mouse position in a flickable after flicking?

Scheduled Pinned Locked Moved QML and Qt Quick
flickablemousearea
5 Posts 3 Posters 6.2k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • momoM Offline
    momoM Offline
    momo
    wrote on last edited by momo
    #1

    I have a Flickable which contains a MouseArea. One of the MouseArea's jobs is to keep track of the cursor position of the mouse and, for example, display this on the screen.

    Here's my problem: How can I correctly update the cursor position after flicking?

    Here's the (simplified) MouseArea:

    MouseArea {
        id: myMouseArea
        property point cursorPos
        property bool cursorPosActive : false
        function updateCursorPos() { // doesn't work!!
            // here: mouseX/Y are not up-to-date !!
            cursorPos = Qt.point(mouseX, mouseY)
        }
        anchors.fill: parent
        hoverEnabled: true
        onClicked: {  // MouseEvent OK
            cursorPos = Qt.point(mouse.x, mouse.y)
        }
        onEntered: {  // here: mouseX/Y OK?
            cursorPos = Qt.point(mouseX, mouseY)
            cursorPosActive = true
        }
        onExited: { cursorPosActive = false }
        onPositionChanged: {  // MouseEvent OK
            cursorPos = Qt.point(mouse.x, mouse.y)
        }
        onWheel: {  // WheelEvent OK
            cursorPos = Qt.point(wheel.x, wheel.y)
            wheel.accepted = false; // pass to Flickable
        }
    }
    

    It looks comprehensive, but if I flick with the mouse wheel (otherwise keeping the mouse still!), the mouseX and mouseY values are still old values from the most previous mouse move (or click). That means that calling updateCursorPos(), e.g. by detecting movementEnded() in the Flickable, does not work as hoped:

    onMovementEnded : { myMouseArea.updateCursorPos() }

    [BTW: The WheelEvent from the wheel() signal correctly passes the cursor position in mouse.x and mouse.y, but the position in mouseX and mouseY were even older, i.e. it was not updated by the WheelEvent, probably because I needed to set accepted=false.]

    Is there a workaround to determine this "new" mouse position?

    More to the point: Is this a bug? Should flicking a MouseArea under the mouse infer an update of mouseX and mouseY? Or at least result in positionChanged() signals? Or is this a (desired) performance issue/limitation?

    Thanks for any help you can give! - momo

    Not all those who wander are lost.
    Deep roots are not killed by the frost.

    1 Reply Last reply
    0
    • momoM Offline
      momoM Offline
      momo
      wrote on last edited by
      #2

      No replies yet to my first forum question. Anyone out there who can answer this?

      Not all those who wander are lost.
      Deep roots are not killed by the frost.

      W 1 Reply Last reply
      0
      • momoM momo

        No replies yet to my first forum question. Anyone out there who can answer this?

        W Offline
        W Offline
        wumpus
        wrote on last edited by
        #3

        @momo I had a similar, perhaps even more tricky problem, because I combine a Flickable with a Pincharea to also zoom into the map. This "map" is actually composed out of png-files with 1024x1024 px, which are arranged by means of two repeaters - one for the columns and inside of that another one for the rows.

        Maybe the following JavaScript snippet helps you:

        function calcXandY(x, y) {
            var x_new = (x + r_num * 1024 * pinchArea.zoomFactor) / pinchArea.zoomFactor * Globals.MOUSESCALING
            var y_new = (y + c_num * 1024 * pinchArea.zoomFactor) / pinchArea.zoomFactor * Globals.MOUSESCALING
            return [x_new,y_new]
        }
        function processMouseClicked(mouse) {
            markerDialog.visible = false
            console.log("c_num:", c_num, "r_num:", r_num, "mouseX:", mouse.x, "mouseY:", mouse.y);
            var realXY = calcXandY(mouse.x, mouse.y)
            var station = eventModel.stationForTouchArea(realXY[0], realXY[1], Globals.LANG) 
            if (station === "undefined") {
                console.log("No station found")
                markerDialog.visible = false
            }
            else {
                stationListView.model = eventModel.entriesForStation(station, Globals.LANG)
                markerDialog.setStationLabelText(station)
                markerDialog.x = stationListView.model[0].x * pinchArea.zoomFactor / Globals.MOUSESCALING - Globals.MARKERXOFFSET
                markerDialog.y = stationListView.model[0].y * pinchArea.zoomFactor / Globals.MOUSESCALING - markerDialog.height + Globals.MARKERYOFFSET
              stationListView.changed();
              markerDialog.visible = true
        }
        

        Sorry for the Globals stuff and be aware that this is surely not efficient code. Anyway, I would be glad if it helped.

        Best,
        wumpus

        1 Reply Last reply
        0
        • N Offline
          N Offline
          nedo99
          wrote on last edited by
          #4

          If the size of the flickable is bigger than your screen then mouseX and mouseY are relative to the screen size not the flickable. If you still want to get relative to the flickable then you would have to combine onMovementEnded with contentX and contentY properties from flickable.

          After flicking your x and y position should be x = contentX + mouseX and the same for y.

          Hope this helps.

          Regards

          1 Reply Last reply
          2
          • momoM Offline
            momoM Offline
            momo
            wrote on last edited by momo
            #5

            @nedo99: A big thanks for the tip! That in fact solved my problem, but maybe not in the way you might have thought! I finally got it to work this way:

            MouseArea {
                id: myMouseArea
                property point cursorPos
                property bool cursorPosActive : false
            
                // new code to handle flicking
                property point startFlickContentRef: Qt.point(0, 0)
                property point startFlickMousePos: Qt.point(mouseX, mouseY)
                property bool flicking: false
                function setStartFlickMousePos(x,y) {
                    // "prepare" for flicking whenever we have a legitimate mouse pos...
                    if (!flicking)  // ...but are not actually flicking!
                        startFlickMousePos = Qt.point(x,y)
                }
                function startFlick(refPt) {
                    // Note: startFlick() might be called multiple times before endFlick() is called...
                    if (!flicking) {  // ...so this is an important check!
                        startFlickContentRef = refPt
                        flicking = true
                    }
                }
                function endFlick(refPt) {
                    if (flicking) {
                        var diffX = refPt.x - startFlickContentRef.x
                        var diffY = refPt.y - startFlickContentRef.y
                        statBar.cursorPos = 
                            Qt.point(startFlickMousePos.x + diffX,
                                     startFlickMousePos.y + diffY)
                        flicking = false
                    }
                }
            
                anchors.fill: parent
                hoverEnabled: true
                onClicked: {  // MouseEvent OK
                    cursorPos = Qt.point(mouse.x, mouse.y)
                    setStartFlickMousePos(mouse.x, mouse.y)
                }
                onEntered: {  // here: mouseX/Y OK?
                    cursorPos = Qt.point(mouseX, mouseY)
                    setStartFlickMousePos(mouseX, mouseY)
                    cursorPosActive = true
                }
                onExited: { cursorPosActive = false }
                onPositionChanged: {  // MouseEvent OK
                    cursorPos = Qt.point(mouse.x, mouse.y)
                    setStartFlickMousePos(mouse.x, mouse.y)
                }
                onWheel: {  // WheelEvent OK
                    cursorPos = Qt.point(wheel.x, wheel.y)
                    setStartFlickMousePos(wheel.x, wheel.y)
                    wheel.accepted = false; // pass to Flickable
                }
            }
            

            Then I added the following code to my Flickable:

                onFlickStarted: {
                    myMouseArea.startFlick(Qt.point(contentX, contentY))
                }
                onFlickEnded: {
                    myMouseArea.endFlick(Qt.point(contentX, contentY))
                }
            

            Note that it turned out to be important to use onFlickStarted/Ended instead of onMovementStarted/Ended. Also it's important to update the startFlickMousePos at every opportunity, because at the point where I normally would want to set it (in startFlick()), I might not have a valid mouseX and mouseY (that was the reason for this post in the first place!).

            Again thanks! Together we are strong!

            Not all those who wander are lost.
            Deep roots are not killed by the frost.

            1 Reply Last reply
            1

            • Login

            • Login or register to search.
            • First post
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved