QML MouseArea: onExited не запускается после программного перемещения мыши в MouseArea

Эта проблема возникает в Windows, но не в Linux. На других платформах не пробовал.

У меня есть собственный класс (код ниже), который использует QCursor чтобы установить положение мыши.

Проблема заключается в следующем коде (репо):

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.');
        }
    }
}

Шаги по воспроизведению проблемы:

  1. Наведите указатель мыши на окно. Курсор переместится в верхний левый угол экрана иonExited будет стрелять.
  2. Отпустите кнопку мыши. Курсор переместится в середину окна.
  3. Переместите мышь из окна.

onExitedдолжен срабатывать второй раз, когда пользователь выводит мышь из окна, но этого не происходит. Есть ли способ, которым я могу

  1. вызвать его огонь, или
  2. иначе определить, что мышь вышла из области мыши?

onPositionChanged все еще срабатывает, но я могу использовать это только для определения того, когда мышь приближается к краю MouseArea, а не когда он ушел.

Я пробовал наложить глобальный MouseArea сверху и прохождение всех событий как способ выполнить некоторую ручную проверку положения в особых случаях, но я не мог передать события наведения.


Класс для установки положения мыши:

#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);
}

Я регистрирую этот класс как тип с QML в своей основной функции:

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

Затем я могу импортировать его в QML и использовать.

1 ответ

Решение

В качестве обходного пути для вашей проблемы вы можете использовать таймер для сброса положения курсора мыши.

Либо в QML:

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

Или в вашем классе MouseHelper:

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

У меня это работает, если интервал таймера не слишком мал.

Другие вопросы по тегам