QML MouseArea:以编程方式将鼠标移入 MouseArea 后,onExited 不会触发

Jos*_*ica 3 qt qml mousearea

此问题发生在 Windows 上,但不会发生在 Linux 上。其他平台我没试过。

我有一个QCursor用于设置鼠标位置的自定义类(下面的代码)。

问题在于以下代码(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.');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

重现问题的步骤:

  1. 将鼠标放在窗口上。光标将移动到屏幕的左上角,并onExited会触发。
  2. 释放鼠标按钮。光标会跳到窗口中间。
  3. 将鼠标移出窗口。

onExited当用户将鼠标移出窗口时应该第二次触发,但它没有。有什么办法可以

  1. 导致它着火,或
  2. 否则检测鼠标已移出鼠标区域?

onPositionChanged仍然会触发,但我只能使用它来检测鼠标何时接近 边缘,而MouseArea不是何时离开。

我尝试MouseArea在顶部覆盖一个全局并传递所有事件作为进行一些手动特殊情况位置检查的一种方式,但我无法传递悬停事件。


设置鼠标位置的类:

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.');
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
#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
Run Code Online (Sandbox Code Playgroud)

我在主函数中使用 QML 将此类注册为类型:

#include "mousehelper.h"
#include <QGuiApplication>

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

void MouseHelper::setCursorPosition(int x, int y) {
    QCursor::setPos(x, y);
}
Run Code Online (Sandbox Code Playgroud)

然后我可以在 QML 中导入它并使用它。

ptr*_*ptr 5

作为您问题的解决方法,您可以使用计时器来重置鼠标光标的位置。

在 QML 中:

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

或者在你的 MouseHelper 类中:

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

如果计时器的间隔不太小,这对我有用。