There are two MouseAreas with two different responsibilities and one (green) is positioned partially on top of the other (red). I would like to change cursor's shape whenever red MA is hovered (even if it is under the green MA), and I would like green MA to react to press and nothing else.
Two MA's could be in different files so I don't want to make explicit dependencies between them like setting proper cursorShape in green whenever containsMouse in red changes. Is there a way to prevent the green MouseArea from handling cursor shape?
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
width: 200
height: 200
Rectangle { anchors.fill: parent; color: "yellow"; }
MouseArea {
width: 150
height: 150
hoverEnabled: true
cursorShape: Qt.OpenHandCursor
Rectangle { anchors.fill: parent; color: "red"; }
onPositionChanged: console.log("position", mouse.x, mouse.y)
onContainsMouseChanged: console.log("containsMouse", containsMouse)
}
MouseArea {
x: 50
y: 50
width: 150
height: 150
hoverEnabled: false
Rectangle { anchors.fill: parent; color: "green"; }
onPressed: console.log("Ahoj!")
}
}
There is no way to do this by MouseArea
properties or any other ready solution. MouseArea
always sets some cursor shape -- if cursorShape property is not specified than the default value is used (Qt.ArrowCursor
)
You can of course use mapToItem()
/mapFromItem()
to workaround this problem (as Mitch suggested). But there are other possibilities too:
You can temporary change visible
to false
of overlaying mouse area.
Alternatively if both MouseArea
are siblings, you can operate on z
property to obtain specific hierarchy of object suitable for your needs.
I don't think it's possible to do that, at least from within QML. The green mouse area doesn't have hoverEnabled
set to true, so you won't receive any position changes for it.
A better way of approaching this problem is to use a larger MouseArea
that fills the maximum area you're interested in, and use mapToItem() / mapFromItem() to translate the global mouse position to local coordinates for comparison against each mouse area:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: window
visible: true
width: 200
height: 200
Rectangle {
anchors.fill: parent
color: "yellow"
}
MouseArea {
id: globalMouseArea
anchors.fill: parent
hoverEnabled: true
}
MouseArea {
id: redMouseArea
width: 150
height: 150
cursorShape: containsMouse ? Qt.OpenHandCursor : Qt.ArrowCursor
enabled: false
readonly property bool containsMouse: {
var relativePos = mapFromItem(globalMouseArea, globalMouseArea.mouseX, globalMouseArea.mouseY);
return contains(Qt.point(relativePos.x, relativePos.y));
}
Rectangle {
anchors.fill: parent
color: "red"
}
}
Rectangle {
id: greenMouseArea
x: 50
y: 50
width: 150
height: 150
color: containsMouse ? "brown" : "green"
readonly property bool containsMouse: {
var relativePos = mapFromItem(globalMouseArea, globalMouseArea.mouseX, globalMouseArea.mouseY);
return contains(Qt.point(relativePos.x, relativePos.y));
}
Connections {
target: globalMouseArea
onPressed: if (greenMouseArea.containsMouse) greenMouseArea.pressed()
}
signal pressed
onPressed: console.log("Ahoj!")
}
}
As you can see, the green mouse area is no longer a mouse area. It seems that a mouse area that has a higher stacking order than another mouse area will block position changes for the lower mouse area, even if the higher one doesn't have hoverEnabled
set to true.
Also, note that it would be slightly more concise if it weren't for QTBUG-41452. Namely, you could shorten the containsMouse
expression:
readonly property bool containsMouse: contains(mapFromItem(globalMouseArea, globalMouseArea.mouseX, globalMouseArea.mouseY))
If you're concerned about the code duplication here, then you can use a function instead:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: window
visible: true
width: 200
height: 200
Rectangle {
anchors.fill: parent
color: "yellow"
}
MouseArea {
id: globalMouseArea
anchors.fill: parent
hoverEnabled: true
}
function containsMouse(item) {
var relativePos = globalMouseArea.mapToItem(item, globalMouseArea.mouseX, globalMouseArea.mouseY);
return item.contains(Qt.point(relativePos.x, relativePos.y));
}
MouseArea {
id: redMouseArea
width: 150
height: 150
cursorShape: window.containsMouse(redMouseArea) ? Qt.OpenHandCursor : Qt.ArrowCursor
enabled: false
Rectangle {
anchors.fill: parent
color: "red"
}
}
Rectangle {
id: greenMouseArea
x: 50
y: 50
width: 150
height: 150
color: containsMouse ? "brown" : "green"
readonly property bool containsMouse: window.containsMouse(greenMouseArea)
Connections {
target: globalMouseArea
onPressed: if (greenMouseArea.containsMouse) greenMouseArea.pressed()
}
signal pressed
onPressed: console.log("Ahoj!")
}
}
I used a property for the green mouse area, as it would otherwise call containsMouse()
twice, which is wasteful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With