Home > Mobile >  Can't click button below a MouseArea
Can't click button below a MouseArea

Time:09-25

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")
  }
  • Related