QML MouseArea: onExited doesn't trigger after programmatically moving mouse into MouseArea

Aug 22 2020

This issue happens on Windows, but not on Linux. I haven't tried any other platforms.

I have a custom class (code below) that uses QCursor to set the mouse position.

The issue is with the following code (repo):

import QtQuick 2.15
import QtQuick.Window 2.15

// Custom C++ class, implementation below
import io.github.myProject.utilities.mousehelper 1.0

Window {
    visible: true
    width: 800
    height: 600

    MouseHelper { id: mouseHelper }

    MouseArea {
        id: mouseArea
        hoverEnabled: true
        anchors.fill: parent
        property var p

        onPressed: {
            p = mouseArea.mapToGlobal(
                mouseArea.width * 0.5, mouseArea.height * 0.5);
            mouseHelper.setCursorPosition(0, 0);
        }

        onReleased: {
            mouseHelper.setCursorPosition(p.x, p.y);
        }

        onExited: {
            console.log('This should happen twice, but it only happens once.');
        }
    }
}

Steps to reproduce the issue:

  1. Mouse down on the window. The cursor will move to the top-left of the screen, and onExited will fire.
  2. Release the mouse button. The cursor will jump to the middle of the window.
  3. Move the mouse out of the window.

onExited should fire a second time when the user moves the mouse out of the window, but it doesn't. Is there some way I can either

  1. cause it to fire, or
  2. otherwise detect that the mouse has moved out of the mouse area?

onPositionChangednadal strzela, ale mogę tego użyć tylko do wykrycia, kiedy mysz jest blisko krawędzi MouseArea, a nie kiedy opuściła.

Próbowałem nałożyć glob MouseAreana górę i przepuścić wszystkie zdarzenia jako sposób na ręczne sprawdzanie pozycji w specjalnych przypadkach, ale nie mogłem przepuścić zdarzeń najechania kursorem.


Klasa do ustawiania pozycji myszy:

#ifndef MOUSEHELPER_H
#define MOUSEHELPER_H

#include <QObject>
#include <QCursor>

class MouseHelper : public QObject {
    Q_OBJECT
public:
    explicit MouseHelper(QObject *parent = nullptr);

    Q_INVOKABLE void setCursorPosition(int x, int y);

signals:

public slots:
};

#endif // MOUSEHELPER_H
#include "mousehelper.h"
#include <QGuiApplication>

MouseHelper::MouseHelper(QObject *parent) : QObject(parent) {}

void MouseHelper::setCursorPosition(int x, int y) {
    QCursor::setPos(x, y);
}

Rejestruję tę klasę jako typ z QML w mojej głównej funkcji:

int main(int argc, char *argv[]) {
    // ...
    qmlRegisterType<MouseHelper>("io.github.myProject.utilities.mousehelper",
                                 1, 0, "MouseHelper");
}

Mogę następnie zaimportować go do QML i używać.

Odpowiedzi

5 ptr Aug 24 2020 at 13:49

Aby obejść problem, możesz użyć timera, aby zresetować pozycję kursora myszy.

Albo w QML:

MouseArea {
...
    Timer {
        id: timer
        interval: 10
        repeat: false
        onTriggered: {
            mouseHelper.setCursorPosition(mouseArea.p.x, mouseArea.p.y)
        }
    }
    
    onReleased: {
        timer.start()
    }
...
}

Lub w klasie MouseHelper:

#include <QTimer>
...
void MouseHelper::setCursorPosition(int x, int y) {
    QTimer::singleShot(10, this, [x, y]() { QCursor::setPos(x, y); });
}

U mnie to działa, jeśli interwał timera nie jest zbyt mały.