【问题标题】:QML MouseArea: onExited doesn't trigger after programmatically moving mouse into MouseAreaQML MouseArea:以编程方式将鼠标移动到 MouseArea 后不会触发 onExited
【发布时间】:2020-12-11 09:22:26
【问题描述】:

此问题发生在 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.');
        }
    }
}

重现问题的步骤:

  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 并使用它。

【问题讨论】:

  • 您显示的代码似乎是以编程方式进入 area2,而不是退出。我一定是错过了什么。
  • @JarMan 对不起!它以编程方式输入area2。问题是,我无法检测到用户何时将鼠标移出area2,因为onExited 事件仅在用户像往常一样将鼠标移入area2 时触发-我猜以编程方式移动它不会' t "count",所以它不知道跟踪onExited?。
  • @JoshuaWade 是的,在 linux 上没问题,我在 linux 和 windows 都试过,只在 windows 上发生。我会检查更多。点击后onEntered也不起作用
  • 经过挖掘这似乎是一个错误。 containsMouse 在发布事件后也返回 false 。您可能会发现下面回答的棘手问题来解决此问题。
  • 我无法在使用 Qt 5.12.4 的 Windows 上重现此问题。所以这似乎是一个回归错误。您是否考虑过创建bug report

标签: qt qml mousearea


【解决方案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); });
}

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

【讨论】:

  • 这种方法对于小的MouseAreas 来说似乎很不稳定。如果我单击,然后移动鼠标,然后释放,然后再次移动鼠标,如果我太快,第二个onRelease 将不会触发。我的MouseAreas 是 20 x 20 像素。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多