Here I have a rectangle that is the parent and a child rectangle. The child rectangle has a MouseArea
that allows you to swipe the child rectangle. Now, I want to have a button on the parent rectangle (under the child rectangle and MouseArea
) and I want to click that button even if the child rectangle is covering the button. Here is an example"
import QtQuick 2.15
import QtQuick.Window 2.0
import QtQuick.Controls 2.15
Window {
visible: true
width: 800
height: 800
Rectangle {
id: root
anchors.fill: parent
color: "yellow"
Button {
id: button1
x: 314
y: 182
text: qsTr("Button")
onClicked: console.log("Hello")
}
Rectangle {
id: panel
width: parent.width
height: parent.height * 0.8
radius: 20
color: "orange"
opacity: 0.2
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: panel
drag.minimumY: 0
drag.maximumY: 0
drag.minimumX: -panel.width
drag.maximumX: 0
onReleased: {
//if the panel is swiped more than 30% it will hide
//else it will go back to the original position
//this makes a pretty nice effect :)
if (panel.x < -panel.width * 0.3) {
//we need to make sure that a state change happens to
//fire the transition animation
root.state = "show"
root.state = "hide"
}
else {
root.state = "hide"
root.state = "show"
}
}
}
}
Rectangle {
id: button
width: 45
height: width
radius: 5
color: "lightblue"
anchors.bottom: parent.bottom
anchors.left: parent.left
MouseArea {
anchors.fill: parent
onClicked: {
root.state = root.state === "show" ? "hide" : "show"
}
}
}
state: "show"
states: [
State {
name: "hide"
PropertyChanges { target: panel; x: -panel.width }
},
State {
name: "show"
PropertyChanges { target: panel; x: 0 }
}
]
transitions: Transition {
NumberAnimation {
target: panel
property: "x"
duration: 1000
easing.type: Easing.OutCubic
}
}
}
}
How can I click on the button without swiping the child rectangle?
CodePudding user response:
First you need to detect in mouseArea if drag is active or not, and if drag is not active then detect if point where mouse press event is triggered is also inside the button1 below the panel. You can do that by using Item
's mapToItem method. If that is the case then you can set button1 pressed
visualization manually on.
Then when released
event is triggered you detect if you are still inside the button1 and emit special signal e.g. buttonBelowClicked
. That signal needs to be connected to button1 clicked
signal via signal chaining.
Note that you need to reset button1 pressed visualization always in mouseArea onReleased because you might have started panel dragging from the top of the button1 and button shows pressed visualization but then dragging gets enabled...
Window {
visible: true
width: 800
height: 800
Rectangle {
id: root
anchors.fill: parent
color: "yellow"
Button {
id: button1
x: 314
y: 182
text: qsTr("Button")
onClicked: console.log("Hello")
Component.onCompleted: mouseArea.buttonBelowClicked.connect(clicked)
}
Rectangle {
id: panel
width: parent.width
height: parent.height * 0.8
radius: 20
color: "orange"
opacity: 0.2
MouseArea {
id: mouseArea
signal buttonBelowClicked
anchors.fill: parent
drag.target: panel
drag.minimumY: 0
drag.maximumY: 0
drag.minimumX: -panel.width
drag.maximumX: 0
onPressed: {
if (!drag.active) {
if (isPointInsideButton1(mouse.x, mouse.y)) {
button1.down = true
}
}
}
onReleased: {
if (!drag.active) {
if (isPointInsideButton1(mouse.x, mouse.y)) {
buttonBelowClicked()
}
} else {
if (panel.x < -panel.width * 0.3) {
root.state = "show"
root.state = "hide"
}
else {
root.state = "hide"
root.state = "show"
}
}
button1.down = undefined
}
function isPointInsideButton1(x, y) {
const mapped = panel.mapToItem(button1, x, y)
if (button1.contains(Qt.point(mapped.x, mapped.y))) {
return true
}
return false
}
}
}
Rectangle {
id: button
width: 45
height: width
radius: 5
color: "lightblue"
anchors.bottom: parent.bottom
anchors.left: parent.left
MouseArea {
anchors.fill: parent
onClicked: {
root.state = root.state === "show" ? "hide" : "show"
}
}
}
state: "show"
states: [
State {
name: "hide"
PropertyChanges { target: panel; x: -panel.width }
},
State {
name: "show"
PropertyChanges { target: panel; x: 0 }
}
]
transitions: Transition {
NumberAnimation {
target: panel
property: "x"
duration: 1000
easing.type: Easing.OutCubic
}
}
}
}
CodePudding user response:
the simplest solution is to place button1 below panel. Like this
Rectangle {
id: panel
width: parent.width
height: parent.height * 0.8
radius: 20
color: "orange"
opacity: 0.2
MouseArea {
id: mouseArea
anchors.fill: parent
drag.target: panel
drag.minimumY: 0
drag.maximumY: 0
drag.minimumX: -panel.width
drag.maximumX: 0
onReleased: {
//if the panel is swiped more than 30% it will hide
//else it will go back to the original position
//this makes a pretty nice effect :)
if (panel.x < -panel.width * 0.3) {
//we need to make sure that a state change happens to
//fire the transition animation
root.state = "show"
root.state = "hide"
}
else {
root.state = "hide"
root.state = "show"
}
}
}
}
Button {
id: button1
x: 314
y: 182
text: qsTr("Button")
onClicked: console.log("Hello")
}