Qt 在MouseArea.onenterned中,检测原因是否只是*MouseArea*移动并位于光标下方

Qt 在MouseArea.onenterned中,检测原因是否只是*MouseArea*移动并位于光标下方,qt,input,qml,mouseevent,qtquick2,Qt,Input,Qml,Mouseevent,Qtquick2,在MouseArea.onenterned中,我能否检测到触发事件的原因是否只是MouseArea移动并位于光标下方,而不是相反 我想做这样的事情:(伪代码) 但这使得假设输入的将在鼠标eaeaeaposchange之后和在窗口之前被触发。我对这个假设没有信心 此外,当MouseArea的祖先移动时,或者当MouseArea通过锚定进行定位/调整大小时,它也不起作用。您可以检查自上次事件以来是否更改了mouseX,mouseY property int previousMouseX = mous

在MouseArea.onenterned中,我能否检测到触发事件的原因是否只是MouseArea移动并位于光标下方,而不是相反

我想做这样的事情:(伪代码)

但这使得假设输入的
将在
鼠标eaeaeaposchange
之后
窗口之前
被触发。我对这个假设没有信心


此外,当MouseArea的祖先移动时,或者当MouseArea通过锚定进行定位/调整大小时,它也不起作用。

您可以检查自上次事件以来是否更改了
mouseX
mouseY

property int previousMouseX = mouseX; // or use other values to init
property int previousMouseY = mouseY; // e.g., 0, x, parent.x, 
                                      // or set it from extern

onEntered() {
    if (mouseX != previousMouseX || mouseY != previousMouseY) {
       // TODO do something
        previousMouseX = mouseX;
        previousMouseY = mouseY;
    }
}
如果
mouseX
mouseY
相对于鼠标区域0,0,则可以使用
mapFromItem(null,0,0)
获取绝对值。

假设: 这只影响边缘情况,即光标和鼠标earea都在移动。
我在这里的假设是,光标的移动是在移动
MouseArea
之前处理的。我没有任何确切的证据证明这一点。只有我用下面的解决方案进行的测试表明


解决方案 第一个挑战是检测
鼠标earea
的移动。它可能会移动,而自身的
x
y
值不会改变,例如,如果其父对象正在移动。
为了解决这个问题,我将介绍两个属性
globalX
globalX
。然后我使用了来自的技巧

现在我要处理两个信号:
globalXChanged
globalYChanged

根据我的假设,在
mouseXChanged
mouseYChanged
之后,他们会被解雇。我将使用一个标志
isEntered
,确保在第一个被触发时,我只处理其中一个,方法是将其设置为
true

我将使用
globalMouseArea
上的光标位置来确定光标是否在
MouseArea
的范围内这需要,光标当时不在其他
MouseArea
中,或者至少我知道它

->有了这个,我已经成功地探测到了入口


第二个挑战是检测出口。这里我们有4个案例需要区分:

  • 光标进入和离开
    MouseArea
    ,因为它在移动
  • 由于
    MouseArea
  • 光标进入是因为
    MouseArea
    移动,离开是因为光标移动
  • 光标进入是因为它移动了,离开是因为
    MouseArea
    移动了
  • 第一个很容易处理。在它进入后,我们处理
    进入的
    ,当它离开时,我们处理
    退出的
    。但是在米奇提到的修复之后,我们不能再依赖它了

    因此,我们不会在光标移动或
    targetMouseArea
    移动时设置
    hoverEnabled:true
    并将光标位置映射到
    targetMouseArea
    ,并相应地进行操作

    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        id: root
        visible: true
        width: 400; height: 450
        MouseArea {
            id: globalMouseArea
            anchors.fill: parent
            hoverEnabled: true
            onClicked: ani.restart()
        }
    
        Rectangle {
            x: 300
            y: 300
            width: 50
            height: 50
            color: 'green'
        }
    
        Rectangle {
            id: rect
            width: 50
            height: 50
            color: 'red'
    
            Text {
                text: targetMouseArea.isEntered.toString()
            }
    
            MouseArea {
                id: targetMouseArea
                anchors.fill: parent
                signal enteredBySelfMovement
                signal enteredByMouseMovement
    
                onEnteredByMouseMovement: console.log('Cause: Mouse')
                onEnteredBySelfMovement: console.log('Cause: Self')
    
                property point globalPos: {
                    var c = Qt.point(0, 0)
                    var itm = this
                    for (; itm.parent !== null; itm = itm.parent) {
                        c.x += itm.x
                        c.y += itm.y
                    }
                    return c
                }
                property bool isEntered: false
    
                function checkCollision(sig) {
                    if ((globalPos.y < globalMouseArea.mouseY)
                        && (globalPos.y + height > globalMouseArea.mouseY)
                        && (globalPos.x < globalMouseArea.mouseX)
                        && (globalPos.x + width > globalMouseArea.mouseX)) {
                        if (!isEntered) { 
                            isEntered = true
                            sig()
                        }
                    }
                    else if (isEntered && !containsMouse) {
                        console.log(isEntered = false)
                    }
                }
    
                onGlobalPosChanged: {
                    checkCollision(enteredBySelfMovement)
                }
    
                Connections {
                    target: globalMouseArea
                    onPositionChanged: {
                        targetMouseArea.checkCollision(targetMouseArea.enteredByMouseMovement)
                    }
                }
            }
        }
    
        NumberAnimation {
            id: ani
            target: rect
            properties: 'x,y'
            from: 0
            to: 300
            running: true
            duration: 10000
        }
    }
    
    导入QtQuick 2.7
    导入QtQuick.Controls 2.0
    应用程序窗口{
    id:根
    可见:正确
    宽度:400;高度:450
    鼠耳{
    id:globalMouseArea
    锚定。填充:父级
    hoverEnabled:true
    onClicked:ani.restart()
    }
    长方形{
    x:300
    y:300
    宽度:50
    身高:50
    颜色:“绿色”
    }
    长方形{
    id:rect
    宽度:50
    身高:50
    颜色:“红色”
    正文{
    text:targetMouseArea.isEntered.toString()
    }
    鼠耳{
    id:targetMouseArea
    锚定。填充:父级
    自运动输入的信号
    MouseMovement输入的信号
    onenteredbymouseMotation:console.log('原因:鼠标')
    onEnteredBySelfMovement:console.log('原因:Self')
    globalPos酒店点:{
    变量c=Qt.点(0,0)
    var itm=此
    for(;itm.parent!==null;itm=itm.parent){
    c、 x+=itm.x
    c、 y+=itm.y
    }
    返回c
    }
    属性布尔值已居中:false
    函数检查冲突(sig){
    if((globalPos.yglobalMouseArea.mouseY)
    &&(globalPos.xglobalMouseArea.mouseX)){
    如果(!isEntered){
    isEntered=true
    sig()
    }
    }
    else if(isEntered&!containsMouse){
    console.log(isEntered=false)
    }
    }
    OnglobalPosted:{
    检查碰撞(由selfmovement输入)
    }
    联系{
    目标:环球大厦区
    已更改的位置:{
    targetMouseArea.checkCollision(targetMouseArea.enteredByMouseMovement)
    }
    }
    }
    }
    数字化{
    id:ani
    目标:rect
    属性:“x,y”
    起:0
    收件人:300
    跑步:对
    持续时间:10000
    }
    }
    

    遗留问题:当我们在
    targetMouseArea
    中单击时,只要按下按钮,我们就不会检测到离开。

    这不起作用。如果鼠标第一次进入,例如完全未知。否则,我们只会知道鼠标是否在与以前相同的位置越过边界,但我们不知道原因。您可以使用
    import QtQuick 2.7
    import QtQuick.Controls 2.0
    
    ApplicationWindow {
        id: root
        visible: true
        width: 400; height: 450
        MouseArea {
            id: globalMouseArea
            anchors.fill: parent
            hoverEnabled: true
            onClicked: ani.restart()
        }
    
        Rectangle {
            x: 300
            y: 300
            width: 50
            height: 50
            color: 'green'
        }
    
        Rectangle {
            id: rect
            width: 50
            height: 50
            color: 'red'
    
            Text {
                text: targetMouseArea.isEntered.toString()
            }
    
            MouseArea {
                id: targetMouseArea
                anchors.fill: parent
                signal enteredBySelfMovement
                signal enteredByMouseMovement
    
                onEnteredByMouseMovement: console.log('Cause: Mouse')
                onEnteredBySelfMovement: console.log('Cause: Self')
    
                property point globalPos: {
                    var c = Qt.point(0, 0)
                    var itm = this
                    for (; itm.parent !== null; itm = itm.parent) {
                        c.x += itm.x
                        c.y += itm.y
                    }
                    return c
                }
                property bool isEntered: false
    
                function checkCollision(sig) {
                    if ((globalPos.y < globalMouseArea.mouseY)
                        && (globalPos.y + height > globalMouseArea.mouseY)
                        && (globalPos.x < globalMouseArea.mouseX)
                        && (globalPos.x + width > globalMouseArea.mouseX)) {
                        if (!isEntered) { 
                            isEntered = true
                            sig()
                        }
                    }
                    else if (isEntered && !containsMouse) {
                        console.log(isEntered = false)
                    }
                }
    
                onGlobalPosChanged: {
                    checkCollision(enteredBySelfMovement)
                }
    
                Connections {
                    target: globalMouseArea
                    onPositionChanged: {
                        targetMouseArea.checkCollision(targetMouseArea.enteredByMouseMovement)
                    }
                }
            }
        }
    
        NumberAnimation {
            id: ani
            target: rect
            properties: 'x,y'
            from: 0
            to: 300
            running: true
            duration: 10000
        }
    }