[SOLVED] How do I get the mouse position in a flickable after flicking?
-
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
-
@momo I had a similar, perhaps even more tricky problem, because I combine a
Flickable
with aPincharea
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 -
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
-
@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!