1

I'm programming a small PoC in QML. In a couple of places in my code I need to bind to/query global mouse position (say, mouse position in a scene or game window). Even in cases where mouse is outside of MouseAreas that I've defined so far.

Looking around, the only way to do it seems to be having whole screen covered with another MouseArea, most likely with hovering enabled. Then I also need to deal with semi-manually propagating (hover) events to underlying mouseAreas..

Am I missing something here? This seems like a pretty common case - is there a simpler/more elegant way to achieve it?

EDIT: The most problematic case seems to be while dragging outside a MouseArea. Below is a minimalistic example (it's using V-Play components and a mouse event spy from derM's answer). When I click the image and drag outside the MouseArea, mouse events are not coming anymore so the position cannot be updated unless there is a DropArea below.

The MouseEventSpy is taken from here in response to one of the answers. It is only modified to include the position as parameters to the signal.

import VPlay 2.0
import QtQuick 2.0
import MouseEventSpy 1.0

GameWindow {
    id: gameWindow
    activeScene: scene
    screenWidth: 960
    screenHeight: 640

    Scene {
        id: scene
        anchors.fill: parent

        Connections {
            target: MouseEventSpy
            onMouseEventDetected: {
                console.log(x)
                console.log(y)
            }
        }

        Image {
            id: tile
            x: 118
            y: 190
            width: 200
            height: 200
            source: "../assets/vplay-logo.png"
            anchors.centerIn: parent

            Drag.active: mausA.drag.active
            Drag.dragType: Drag.Automatic

            MouseArea {
                id: mausA
                anchors.fill: parent
                drag.target: parent
            }
        }
    }
}
evilkonrex
  • 255
  • 2
  • 10

3 Answers3

2

You can install a eventFilter on the QGuiApplication, where all mouse events will pass through.

How to do this is described here

In the linked solution, I drop the information about the mouse position when emitting the signal. You can however easily retrieve the information by casting the QEvent that is passed to the eventFilter(...)-method into a QMouseEvent and add it as parameters to the signal.

In the linked answer I register it as singleton available in QML and C++ so you can connect to the signal where ever needed.


As it is provided in the linked answer, the MouseEventSpy will only handle QMouseEvents of various types. Once you start dragging something, there won't be QMouseEvents but QDragMoveEvents e.t.c. Therefore you need to extend the filter method, to also handle those.

bool MouseEventSpy::eventFilter(QObject* watched, QEvent* event)
{
    QEvent::Type t = event->type();
    if (t == QEvent::MouseButtonDblClick
            || t == QEvent::MouseButtonPress
            || t == QEvent::MouseButtonRelease
            || t == QEvent::MouseMove) {
        QMouseEvent* e = static_cast<QMouseEvent*>(event);
        emit mouseEventDetected(e->x(), e->y());
    }

    if (t == QEvent::DragMove) {
        QDragMoveEvent* e = static_cast<QDragMoveEvent*>(event);
        emit mouseEventDetected(e->pos().x(), e->pos().y());
    }
    return QObject::eventFilter(watched, event);
}

You can then translate the coordinates to what ever you need to (Screen, Window, ...)

  • I've tried with modification of your approach, but unfortunately it doesn't work for a following case - I have a MouseArea onscreen, I press on it and start dragging. Once mouse leaves this mouse area the mouse move events stop coming, so no other item gets the mouse position updates.. – evilkonrex Nov 23 '17 at 20:56
  • Can you post that code? I don't have those issues. Ofc. if the mouse leaves the application, it won't receive events. – derM - not here for BOT dreams Nov 23 '17 at 21:43
0

As you have only a couple of places where you need to query global mouse position, I would suggest you to use mapToGlobal or mapToItem methods.

Andrii
  • 1,788
  • 11
  • 20
  • Problem is that I sometimes need to check mouse position when mouse is outside of currently existing mouseAreas. And in this case (seems that) I'm not getting any mouse movement events that would allow me to update current mouse position. – evilkonrex Nov 23 '17 at 10:05
0

I believe you can get cursor's coordinates from C++ side. Take a look on answer on this question. The question doesn't related to your problem but the solution works as well.

On my side I managed to get global coordinates by directly calling mousePosProvider.cursorPos() without any MouseArea.

Neilana
  • 104
  • 1
  • 6
  • This seems to work very well for querying, but one cannot bind to it. Problematic case that I have (as added to original post) is when I drag out of MouseArea - in this case no mouse move event is received and there is nothing to update current mouse position. – evilkonrex Nov 23 '17 at 22:38