在MouseArea.onEntered中,检测是否只是*MouseArea*移动到光标下的原因
In MouseArea.onEntered, detect if the cause is only that the *MouseArea* moved and came to be under the cursor
在MouseArea.onEntered中,我可以检测事件触发的原因是否只是 MouseArea 移动并位于光标下,而不是反过来?
我想到了这样做:(伪代码)
MouseArea {
// ...
property bool positionDirty = false
Connections {
target: window
onAfterRendering: {
positionDirty = false;
}
}
onMouseAreaPosChanged: {
positionDirty = true;
}
onEntered: {
if(positionDirty) {
positionDirty = false;
return;
}
// handle event here
}
}
但这假设 entered
将在 mouseAreaPosChanged
之后被解雇,在 之前 window.afterRendering
。我对这个假设没有信心。
此外,当 MouseArea 的 祖先 移动时,或者当 MouseArea 通过锚定 positioned/sized 时,它不起作用。
您可以查看自上次活动以来 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)
来获取绝对值。
假设:
This only affects the edge case, that both, the cursor and the MouseArea
are moving.
My Assumption here is, that the movement of the cursor is handled before the movement of the MouseArea
. I don't have any definite proof for this. Only my test with the solution below, suggests that.
解决方案
第一个挑战是检测 MouseArea
的移动。可能是它移动了,但它自己的 x
和 y
值没有改变,例如如果它 parent 在移动。
为了解决这个问题,我将引入两个属性 globalX
和 globalX
。然后我使用 this answer on how to track a gobal position of an object.
中的技巧
现在我要处理两个信号:globalXChanged
和 globalYChanged
。
根据我的假设,他们在 mouseXChanged
和 mouseYChanged
之后被解雇了。我将使用标志 isEntered
来确保,如果第一个被解雇,我只处理其中一个,将其设置为 true
。
我将使用 globalMouseArea
上的光标位置来确定光标是否在 MouseArea
的范围内。 这需要,当时光标不在其他MouseArea
,至少我知道
-> 至此我已经成功检测到入口了
第二个挑战是检测出口。这里我们有4种情况来区分:
- 光标进入和离开
MouseArea
因为它在移动。
- 光标进入和离开
MouseArea
是因为MouseArea
的移动
- 光标进入是因为
MouseArea
移动,离开是因为光标移动
- 光标进入是因为它移动,随着
MouseArea
移开而离开。
第一个很容易处理。在它进入后我们处理 entered
,当它离开时我们处理 exited
。但是在 Mitch 提到的修复之后,我们不能再依赖它了。
所以我们不会设置hoverEnabled: true
并将光标的位置映射到targetMouseArea
,只要光标移动,或者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
}
}
遗留问题:当我们在targetMouseArea
内点击时,只要按下一个按钮,我们就检测不到遗留。
在MouseArea.onEntered中,我可以检测事件触发的原因是否只是 MouseArea 移动并位于光标下,而不是反过来?
我想到了这样做:(伪代码)
MouseArea {
// ...
property bool positionDirty = false
Connections {
target: window
onAfterRendering: {
positionDirty = false;
}
}
onMouseAreaPosChanged: {
positionDirty = true;
}
onEntered: {
if(positionDirty) {
positionDirty = false;
return;
}
// handle event here
}
}
但这假设 entered
将在 mouseAreaPosChanged
之后被解雇,在 之前 window.afterRendering
。我对这个假设没有信心。
此外,当 MouseArea 的 祖先 移动时,或者当 MouseArea 通过锚定 positioned/sized 时,它不起作用。
您可以查看自上次活动以来 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)
来获取绝对值。
假设:
This only affects the edge case, that both, the cursor and the
MouseArea
are moving.
My Assumption here is, that the movement of the cursor is handled before the movement of theMouseArea
. I don't have any definite proof for this. Only my test with the solution below, suggests that.
解决方案
第一个挑战是检测 MouseArea
的移动。可能是它移动了,但它自己的 x
和 y
值没有改变,例如如果它 parent 在移动。
为了解决这个问题,我将引入两个属性 globalX
和 globalX
。然后我使用 this answer on how to track a gobal position of an object.
现在我要处理两个信号:globalXChanged
和 globalYChanged
。
根据我的假设,他们在 mouseXChanged
和 mouseYChanged
之后被解雇了。我将使用标志 isEntered
来确保,如果第一个被解雇,我只处理其中一个,将其设置为 true
。
我将使用 globalMouseArea
上的光标位置来确定光标是否在 MouseArea
的范围内。 这需要,当时光标不在其他MouseArea
,至少我知道
-> 至此我已经成功检测到入口了
第二个挑战是检测出口。这里我们有4种情况来区分:
- 光标进入和离开
MouseArea
因为它在移动。 - 光标进入和离开
MouseArea
是因为MouseArea
的移动
- 光标进入是因为
MouseArea
移动,离开是因为光标移动 - 光标进入是因为它移动,随着
MouseArea
移开而离开。
第一个很容易处理。在它进入后我们处理 entered
,当它离开时我们处理 exited
。但是在 Mitch 提到的修复之后,我们不能再依赖它了。
所以我们不会设置hoverEnabled: true
并将光标的位置映射到targetMouseArea
,只要光标移动,或者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
}
}
遗留问题:当我们在targetMouseArea
内点击时,只要按下一个按钮,我们就检测不到遗留。