Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Qt QML click under the bounding box
Qt 6.11 is out! See what's new in the release blog

Qt QML click under the bounding box

Scheduled Pinned Locked Moved Solved QML and Qt Quick
2 Posts 2 Posters 524 Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • V Offline
    V Offline
    Vildnex
    wrote on last edited by
    #1

    I'm trying to do the following.

    enter image description here

    So far the only solution I found is to create my button from C++ and to use setMask. Is there any other way in order to achieve the same results but just using QML?

    My shape button:

    import QtQuick 2.0
    import QtQuick.Shapes 1.14
    
    
    
    Item {
        id: sideButtonID
        property alias mouseX: mouseArea.mouseX
        property alias mouseY: mouseArea.mouseY
        readonly property bool pressed: containsMouse && mouseArea.pressed
    
        property point topLeftOffset: Qt.point(0, 0)
        property point topRightOffset: Qt.point(0, 0)
        property point bottomRightOffset: Qt.point(0, 0)
        property point bottomLeftOffset: Qt.point(0, 0)
    
        property var colorPressed: "green"
        property var colorSelected: "red"
        property var colorUnselected: "darkorange"
    
        signal clicked
    
        property var coordinate: generateButtonShapeCoordinates(x,y,width,height)
        property point topLeft: coordinate.topLeft
        property point topRight: coordinate.topRight
        property point bottomRight: coordinate.bottomRight
        property point bottomLeft: coordinate.bottomLeft
    
    
        function generateButtonShapeCoordinates(x, y, width, height){
    
            var topLeft = Qt.point(x-width/2 - topLeftOffset.x, y-height-topLeftOffset.y)
            var topRight = Qt.point(x+width/2-topRightOffset.x, y-height-topRightOffset.y)
            var bottomRight = Qt.point(x+width/2-bottomRightOffset.x, y-bottomRightOffset.y)
            var bottomLeft = Qt.point(x - width/2-bottomLeftOffset.x, y-bottomLeftOffset.y)
    
            return {
                topLeft : topLeft,
                topRight : topRight,
                bottomRight : bottomRight,
                bottomLeft : bottomLeft
            };
        }
    
        function inside(point, polygon) {
            // ray-casting algorithm based on
            // http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
            var x = point[0], y = point[1];
    
            var inside = false;
            for (var i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
                var xi = polygon[i][0], yi = polygon[i][1];
                var xj = polygon[j][0], yj = polygon[j][1];
    
                var intersect = ((yi > y) != (yj > y))
                        && (x < (xj - xi) * (y - yi) / (yj - yi) + xi);
                if (intersect) inside = !inside;
            }
    
            return inside;
        }
    
        property bool containsMouse: {
            var topLeft = Qt.point(0-topLeftOffset.x, 0-topLeftOffset.y)
            var topRigh = Qt.point(width-topRightOffset.x, 0-topRightOffset.y)
            var bottomRight = Qt.point(width-bottomRightOffset.x, height-bottomRightOffset.y)
            var bottomLeft = Qt.point(0-bottomLeftOffset.x, height-bottomLeftOffset.y)
    
            var polygon = [[topLeft.x,topLeft.y],[topRigh.x,topRigh.y],[bottomRight.x,bottomRight.y],[bottomLeft.x,bottomLeft.y]]
            var point = [mouseX, mouseY]
    
            return inside(point, polygon)
        }
    
        MouseArea {
            id: mouseArea
            anchors.fill: parent
            hoverEnabled: true
            acceptedButtons: Qt.LeftButton | Qt.RightButton
            onClicked: if (sideButtonID.containsMouse) sideButtonID.clicked()
        }
        Shape {
            antialiasing: true
            vendorExtensionsEnabled: true
            asynchronous: true
            anchors.centerIn: parent
    
    
            ShapePath {
                id: shapepathId
    
                strokeWidth: -1
                fillColor: sideButtonID.pressed ? sideButtonID.colorPressed : (sideButtonID.containsMouse ? sideButtonID.colorSelected : sideButtonID.colorUnselected)
                startX: sideButtonID.topLeft.x; startY: sideButtonID.topLeft.y
                PathLine { x: sideButtonID.topRight.x; y: sideButtonID.topRight.y }
                PathLine { x: sideButtonID.bottomRight.x; y: sideButtonID.bottomRight.y }
                PathLine { x: sideButtonID.bottomLeft.x; y: sideButtonID.bottomLeft.y }
            }
            Component.onCompleted: {
                console.log("TopLeft: "+sideButtonID.topLeft)
                console.log("TopRight: "+sideButtonID.topRight)
                console.log("BottomLeft: "+sideButtonID.bottomLeft)
                console.log("BottomRight: "+sideButtonID.bottomRight)
            }
        }
    }
    

    The usage of my button:

    SideButtons {
        z: 100
        id: sideButtonID
        width: 130
        height: 248
        anchors.verticalCenterOffset: 9
        anchors.horizontalCenterOffset: -255
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.verticalCenter: parent.verticalCenter
        bottomRightOffset: Qt.point(100,0)
        onClicked: {
            print("X: "+mouseX)
            print("Y: "+mouseY)
            print("clicked")
        }
    }
    

    Some of the options that I've heard so far but there are not good in my case.

    1. using an image with a transparent background (sure but I'm going to have the same problem)
    2. creating a C++ class which will inherit QAbstractButton (I would prefer to avoid as much as I can usage of C++ in the Ui side)
    3. usage of a Shape in combination with MouseArea (I'm doing this already but I am encountering the bounding box problem.

    Is there any other way which I don't know yet about?

    1 Reply Last reply
    0
    • sierdzioS Offline
      sierdzioS Offline
      sierdzio
      Moderators
      wrote on last edited by
      #2

      usage of a Shape in combination with MouseArea (I'm doing this already but I am encountering the bounding box problem.

      You've got it almost right. In MouseArea's event handler, do not accept events which should be propagated further to your image buttons below. Example code:

      MouseArea {
        propagateComposedEvents: true
        onClicked: {
          if (clickIsInsideShape) {
            doSomeAction;
          } else {
            mouse.accepted = false;
            return;
          }
        }
      }
      

      Docs: https://doc.qt.io/qt-5/qml-qtquick-mousearea.html#clicked-signal

      (Z(:^

      1 Reply Last reply
      1

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved