QML MouseArea:プログラムでマウスをMouseAreaに移動した後、onExitedがトリガーされない

Aug 22 2020

この問題は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ユーザーがマウスをウィンドウの外に移動すると、2回目に起動するはずですが、起動しません。私ができる方法はありますか

  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にインポートして使用できます。

回答

5 ptr Aug 24 2020 at 13:49

問題の回避策として、タイマーを使用してマウスカーソルの位置をリセットできます。

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

これは、タイマーの間隔が小さすぎない場合に機能します。