ContainsMouse 在父更改时给出了错误的值

ContainsMouse gives incorrect value on parent change

在 QML 中,当 mouse is currently inside the mouse area. Unfortunately, this is not always the case. In the following code, the red square turns blue when the MouseArea within it contains the mouse (ContainsMouse is true). However, if you hit the control key while the square is blue, when the square is reparented to the Window's contentItem, the containsMouse property is not updated (as indicated by the text in the middle of the square). The square will still be blue even though it doesn't contain the mouse anymore. Is there anyway to tell the MouseArea to refresh it's containsMouse property?

时,MouseArea 的 containsMouse 属性 应该 return 为真

代码如下:

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    width: 800
    height: 500
    visible: true

    Rectangle {
        id: square
        width: 200
        height: 200
        focus: true
        color: my_mouse_area.containsMouse ? "blue" : "red"

        MouseArea {
            id: my_mouse_area
            anchors.fill: parent
            hoverEnabled: true
            onClicked: {
                my_mouse_area.x = 200
            }
        }

        Text {
            anchors.centerIn: parent
            text: my_mouse_area.containsMouse + ""
            font.pixelSize: 20
        }

        Keys.onPressed: {
            if(event.key === Qt.Key_Control){
                second_window.show()
                square.parent = second_window.contentItem
            }
        }
    }

    Window {
        id: second_window
        width: 400
        height: 400
        visible: false
    }
}

我想出的解决方案是使用定时器,但间隔为零,因此闪烁为零。您可以尝试将间隔设置为更高的值,以查看发生了什么。诀窍是使用“visible: !tmr.running”设置依赖于计时器 运行 的矩形可见性,并在矩形的父级更改后立即启动计时器。

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    width: 800
    height: 500
    visible: true

    Rectangle {
        id: square
        width: 200
        height: 200
        focus: true
        color: my_mouse_area.containsMouse ? "blue" : "red"

        visible: !tmr.running

        Timer {
             id: tmr
             interval: 0
        }

        MouseArea {
            id: my_mouse_area
            anchors.fill: parent
            hoverEnabled: true
            onClicked: {
                my_mouse_area.x = 200
            }
        }

        Text {
            anchors.centerIn: parent
            text: my_mouse_area.containsMouse + ""
            font.pixelSize: 20
        }

        Keys.onPressed: {
            if(event.key === Qt.Key_Control){
                second_window.show()
                square.parent = second_window.contentItem
                tmr.start()
            }
        }
    }

    Window {
        id: second_window
        width: 400
        height: 400
        visible: false
    }
}

我不喜欢我的第一个解决方案,所以我做了另一个更复杂的解决方案,但这不是一个纯粹的 QML 解决方案。诀窍在于,在更改父级时,您应该调用一个 C++ 方法,在该方法中将鼠标移动事件发送回鼠标区域,这样它将重新评估悬停的 aka containsMouse 布尔值。这是一个更好的解决方案,但仍然是一种解决方法。

确保您有一个简单的 QObject 派生 class,例如 MyObject,使用以下 Q_INVOKABLE 方法:

class MyObject : public QObject
{
    Q_OBJECT

    //
    // constuctor and whatnot
    //

    Q_INVOKABLE void sendMouseMoveEventTo(QObject* item)
    {
        QEvent* e = new QEvent(QEvent::MouseMove);
        QCoreApplication::sendEvent(item, e);
    }
};

在 main.cpp 中创建它的一个实例,并设置为上下文 属性,这样您就可以从 QML 访问它:

MyObject myObject;
engine.rootContext()->setContextProperty("myObject", &myObject);

最后在 QML 矩形中添加:

onParentChanged: {
    myObject.sendMouseMoveEventTo(my_mouse_area)
}