QML MouseArea: onExited non si attiva dopo aver spostato il mouse in modo programmatico in MouseArea

Aug 22 2020

Questo problema si verifica su Windows, ma non su Linux. Non ho provato altre piattaforme.

Ho una classe personalizzata (codice sotto) che utilizza QCursorper impostare la posizione del mouse.

Il problema è con il seguente codice ( 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.');
        }
    }
}

Passaggi per riprodurre il problema:

  1. Mouse in basso sulla finestra. Il cursore si sposterà in alto a sinistra dello schermo e onExitedsi attiverà.
  2. Rilascia il pulsante del mouse. Il cursore salterà al centro della finestra.
  3. Sposta il mouse fuori dalla finestra.

onExiteddovrebbe attivarsi una seconda volta quando l'utente sposta il mouse fuori dalla finestra, ma non lo fa. C'è un modo in cui posso farlo anch'io

  1. farlo sparare, o
  2. altrimenti rileva che il mouse è uscito dall'area del mouse?

onPositionChangedsi attiva ancora, ma posso usarlo solo per rilevare quando il mouse è vicino al bordo del MouseArea, non quando è uscito.

Ho provato a sovrapporre un globale MouseAreain cima e a passare tutti gli eventi come un modo per eseguire un controllo manuale della posizione dei casi speciali, ma non sono riuscito a passare gli eventi al passaggio del mouse.


La classe per impostare la posizione del mouse:

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

Registro questa classe come tipo con QML nella mia funzione principale:

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

Posso quindi importarlo in QML e usarlo.

Risposte

5 ptr Aug 24 2020 at 13:49

Per ovviare al tuo problema puoi utilizzare un timer per reimpostare la posizione del cursore del mouse.

O in QML:

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

O nella tua classe MouseHelper:

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

Questo funziona per me se l'intervallo del timer non è troppo piccolo.