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. Rectangle::contains() doesn't reflect radius
Forum Update on Monday, May 27th 2025

Rectangle::contains() doesn't reflect radius

Scheduled Pinned Locked Moved Solved QML and Qt Quick
4 Posts 2 Posters 251 Views
  • 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.
  • SeDiS Offline
    SeDiS Offline
    SeDi
    wrote on last edited by SeDi
    #1

    Hi,
    I have several circular "Buttons" (here: Rectangle{}s with radius of half their width, named "key1", .., "key4") that are part of a MultiPointTouchArea. I need them being able to detect being pressed simultaneously (it's gonna be a fingering trainer for brass instruments). So I detect the TouchPoints and check them for matches with my Rectangles using their item::contains() method.
    Screenshot here:

    Unfortunately, contains() returns true within the whole Rectangle's area, where it should return false in the corners (where "radius: width / 2" has clipped the Rectangle).

    Trying to set a containmentMask would bring me back to the lack of a genuinely circular item in qml.

    Any ideas? Here's my code so far:

    {
                            id: touchArea
                            property bool pressed1: point1.pressed1 || point2.pressed1 || point3.pressed1 || point4.pressed1
                            property bool pressed2: point1.pressed2 || point2.pressed2 || point3.pressed2 || point4.pressed2
                            property bool pressed3: point1.pressed3 || point2.pressed3 || point3.pressed3 || point4.pressed3
                            property bool pressed4: point1.pressed4 || point2.pressed4 || point3.pressed4 || point4.pressed4
                            anchors.fill: parent
                            touchPoints: [
                                TouchPoint {
                                    id: point1
                                    property bool pressed1: point1.pressed && key1.contains(Qt.point(point1.x-key1.x, point1.y-key1.y))
                                    property bool pressed2: point1.pressed && key2.contains(Qt.point(point1.x-key2.x, point1.y-key2.y))
                                    property bool pressed3: point1.pressed && key3.contains(Qt.point(point1.x-key3.x, point1.y-key3.y))
                                    property bool pressed4: point1.pressed && key4.contains(Qt.point(point1.x-key4.x, point1.y-key4.y))
                                },
                                TouchPoint {
                                    id: point2
                                    property bool pressed1: point2.pressed && key1.contains(Qt.point(point2.x-key1.x, point2.y-key1.y))
                                    property bool pressed2: point2.pressed && key2.contains(Qt.point(point2.x-key2.x, point2.y-key2.y))
                                    property bool pressed3: point2.pressed && key3.contains(Qt.point(point2.x-key3.x, point2.y-key3.y))
                                    property bool pressed4: point2.pressed && key4.contains(Qt.point(point2.x-key4.x, point2.y-key4.y))
                                },
                                TouchPoint {
                                    id: point3
                                    property bool pressed1: point3.pressed && key1.contains(Qt.point(point3.x-key1.x, point3.y-key1.y))
                                    property bool pressed2: point3.pressed && key2.contains(Qt.point(point3.x-key2.x, point3.y-key2.y))
                                    property bool pressed3: point3.pressed && key3.contains(Qt.point(point3.x-key3.x, point3.y-key3.y))
                                    property bool pressed4: point3.pressed && key4.contains(Qt.point(point3.x-key4.x, point3.y-key4.y))
                                },
                                TouchPoint {
                                    id: point4
                                    property bool pressed1: point4.pressed && key1.contains(Qt.point(point4.x-key1.x, point4.y-key1.y))
                                    property bool pressed2: point4.pressed && key2.contains(Qt.point(point4.x-key2.x, point4.y-key2.y))
                                    property bool pressed3: point4.pressed && key3.contains(Qt.point(point4.x-key3.x, point4.y-key3.y))
                                    property bool pressed4: point4.pressed && key4.contains(Qt.point(point4.x-key4.x, point4.y-key4.y))
                                }
    
                            ]
    
                            Row {
                                anchors.fill: parent
                                Rectangle {
                                    id: key1
                                    width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                    height: width
                                    radius: width / 2
                                    color: touchArea.pressed1 ? "red" : "yellow"
                                }
                                Rectangle {
                                    id: key2
                                    width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                    height: width
                                    radius: width / 2
                                    color: touchArea.pressed2 ? "red" : "yellow"
                                }
                                Rectangle {
                                    id: key3
                                    width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                    height: width
                                    radius: width / 2
                                    color: touchArea.pressed3 ? "red" : "yellow"
                                    containmentMask: Rectangle {
                                        anchors.fill: key3
                                        radius: width/2
                                        color: "green"
                                        
                                    }
                                }
                                Rectangle {
                                    visible: appwin.noOfKeys === 4
                                    id: key4
                                    width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                    height: width
                                    radius: width / 2
                                    color: touchArea.pressed4 ? "red" : "yellow"
                                }
                            }
                        }
    

    Kind regards,
    Sebastian!

    jeremy_kJ 1 Reply Last reply
    0
    • SeDiS SeDi

      Hi,
      I have several circular "Buttons" (here: Rectangle{}s with radius of half their width, named "key1", .., "key4") that are part of a MultiPointTouchArea. I need them being able to detect being pressed simultaneously (it's gonna be a fingering trainer for brass instruments). So I detect the TouchPoints and check them for matches with my Rectangles using their item::contains() method.
      Screenshot here:

      Unfortunately, contains() returns true within the whole Rectangle's area, where it should return false in the corners (where "radius: width / 2" has clipped the Rectangle).

      Trying to set a containmentMask would bring me back to the lack of a genuinely circular item in qml.

      Any ideas? Here's my code so far:

      {
                              id: touchArea
                              property bool pressed1: point1.pressed1 || point2.pressed1 || point3.pressed1 || point4.pressed1
                              property bool pressed2: point1.pressed2 || point2.pressed2 || point3.pressed2 || point4.pressed2
                              property bool pressed3: point1.pressed3 || point2.pressed3 || point3.pressed3 || point4.pressed3
                              property bool pressed4: point1.pressed4 || point2.pressed4 || point3.pressed4 || point4.pressed4
                              anchors.fill: parent
                              touchPoints: [
                                  TouchPoint {
                                      id: point1
                                      property bool pressed1: point1.pressed && key1.contains(Qt.point(point1.x-key1.x, point1.y-key1.y))
                                      property bool pressed2: point1.pressed && key2.contains(Qt.point(point1.x-key2.x, point1.y-key2.y))
                                      property bool pressed3: point1.pressed && key3.contains(Qt.point(point1.x-key3.x, point1.y-key3.y))
                                      property bool pressed4: point1.pressed && key4.contains(Qt.point(point1.x-key4.x, point1.y-key4.y))
                                  },
                                  TouchPoint {
                                      id: point2
                                      property bool pressed1: point2.pressed && key1.contains(Qt.point(point2.x-key1.x, point2.y-key1.y))
                                      property bool pressed2: point2.pressed && key2.contains(Qt.point(point2.x-key2.x, point2.y-key2.y))
                                      property bool pressed3: point2.pressed && key3.contains(Qt.point(point2.x-key3.x, point2.y-key3.y))
                                      property bool pressed4: point2.pressed && key4.contains(Qt.point(point2.x-key4.x, point2.y-key4.y))
                                  },
                                  TouchPoint {
                                      id: point3
                                      property bool pressed1: point3.pressed && key1.contains(Qt.point(point3.x-key1.x, point3.y-key1.y))
                                      property bool pressed2: point3.pressed && key2.contains(Qt.point(point3.x-key2.x, point3.y-key2.y))
                                      property bool pressed3: point3.pressed && key3.contains(Qt.point(point3.x-key3.x, point3.y-key3.y))
                                      property bool pressed4: point3.pressed && key4.contains(Qt.point(point3.x-key4.x, point3.y-key4.y))
                                  },
                                  TouchPoint {
                                      id: point4
                                      property bool pressed1: point4.pressed && key1.contains(Qt.point(point4.x-key1.x, point4.y-key1.y))
                                      property bool pressed2: point4.pressed && key2.contains(Qt.point(point4.x-key2.x, point4.y-key2.y))
                                      property bool pressed3: point4.pressed && key3.contains(Qt.point(point4.x-key3.x, point4.y-key3.y))
                                      property bool pressed4: point4.pressed && key4.contains(Qt.point(point4.x-key4.x, point4.y-key4.y))
                                  }
      
                              ]
      
                              Row {
                                  anchors.fill: parent
                                  Rectangle {
                                      id: key1
                                      width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                      height: width
                                      radius: width / 2
                                      color: touchArea.pressed1 ? "red" : "yellow"
                                  }
                                  Rectangle {
                                      id: key2
                                      width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                      height: width
                                      radius: width / 2
                                      color: touchArea.pressed2 ? "red" : "yellow"
                                  }
                                  Rectangle {
                                      id: key3
                                      width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                      height: width
                                      radius: width / 2
                                      color: touchArea.pressed3 ? "red" : "yellow"
                                      containmentMask: Rectangle {
                                          anchors.fill: key3
                                          radius: width/2
                                          color: "green"
                                          
                                      }
                                  }
                                  Rectangle {
                                      visible: appwin.noOfKeys === 4
                                      id: key4
                                      width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                      height: width
                                      radius: width / 2
                                      color: touchArea.pressed4 ? "red" : "yellow"
                                  }
                              }
                          }
      

      Kind regards,
      Sebastian!

      jeremy_kJ Offline
      jeremy_kJ Offline
      jeremy_k
      wrote on last edited by
      #2

      Query the parent item for the child key at each relevant point. If it exists, map the point to the key, and check if the resulting point is close enough to the key's center.

      import QtQuick 2.15
      import QtQuick.Window 2.15
      
      Window {
          id: window
          width: 640
          height: 480
          visible: true
      
          MultiPointTouchArea {
              id: touchArea
              anchors.fill: parent
      
              onTouchUpdated: {
                  var touched = new Set()
                  for (var i in touchPoints) {
                      var item = window.contentItem.childAt(touchPoints[i].x, touchPoints[i].y);
                      if (!item)
                          return;
                      var mapped = touchArea.mapToItem(item, touchPoints[i].x, touchPoints[i].y);
                      var distance = Math.sqrt((mapped.x - item.width/2)**2 + (mapped.y - item.height/2)**2);
                      if (distance < item.width / 2)
                          touched.add(item);
                  }
                  for (i in window.contentItem.children) {
                      if (window.contentItem.children[i] === touchArea)
                          continue;
                      else if (touched.has(window.contentItem.children[i]))
                          window.contentItem.children[i].touched = true;
                      else
                          window.contentItem.children[i].touched = false;
                  }
              }
          }
      
          Rectangle {
              property bool touched: false
      
              width: Math.min(parent.width/2, parent.height)
              height: width
              radius: width / 2
              border.width: 1
              border.color: "black"
              color: touched ? "red" : "yellow"
              anchors.verticalCenter: parent.verticalCented
              anchors.right: parent.horizontalCenter
          }
          Rectangle {
              property bool touched: false
      
              width: Math.min(parent.width/2, parent.height)
              height: width
              radius: width / 2
              border.width: 1
              border.color: "black"
              color: touched ? "red" : "yellow"
              anchors.verticalCenter: parent.verticalCented
              anchors.left: parent.horizontalCenter
          }
      }
      

      Asking a question about code? http://eel.is/iso-c++/testcase/

      1 Reply Last reply
      1
      • SeDiS Offline
        SeDiS Offline
        SeDi
        wrote on last edited by
        #3

        What a beautifully crafted solution. I've learned so many details from it (basics like the "in"-syntax in for-loops in JS or using a set()) ! Thanks a million!

        Here's my (slightly adapted) working code:

         MultiPointTouchArea {
                                id: touchArea
                                anchors.fill: parent
                                    onTouchUpdated: {
                                                var touched = new Set()
                                                for (var i in touchPoints) {
                                                    var item = keyRow.childAt(touchPoints[i].x, touchPoints[i].y);
                                                    if (!item) {
                                                        continue;
                                                    }
                                                    var mapped = touchArea.mapToItem(item, touchPoints[i].x, touchPoints[i].y);
                                                    var distance = Math.sqrt((mapped.x - item.width/2)**2 + (mapped.y - item.height/2)**2);
                                                    if (distance < item.width / 2) {
                                                        touched.add(item);
                                                    }
                                                }
                                                for (i in keyRow.children) {
                                                    if (keyRow.children[i].objectName.substr(0,3) === "key") {
                                                        if (touched.has(keyRow.children[i])) {
                                                            keyRow.children[i].touched = true;
                                                        } else {
                                                            keyRow.children[i].touched = false;
                                                        }
                                                    }
                                                }
                                    }
        
                                Row {
                                    anchors.fill: parent
                                    id: keyRow
                                    Rectangle {
                                        id: key1
                                        objectName: "key1"
                                        property bool touched: false
                                        width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                        height: width
                                        radius: width / 2
                                        color: touched ? "red" : "yellow"
                                    }
                                    Rectangle {
                                        id: key2
                                        objectName: "key2"
                                        property bool touched: false
                                        width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                        height: width
                                        radius: width / 2
                                        color: touched ? "red" : "yellow"
                                    }
                                    Rectangle {
                                        id: key3
                                        objectName: "key3"
                                        property bool touched: false
                                        width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                        height: width
                                        radius: width / 2
                                        color: touched ? "red" : "yellow"
                                    }
                                    Rectangle {
                                        id: key4
                                        objectName: "key4"
                                        visible: appwin.noOfKeys === 4
                                        property bool touched: false
                                        width: Math.min(parent.width / appwin.noOfKeys, parent.height)
                                        height: width
                                        radius: width / 2
                                        color: touched ? "red" : "yellow"
                                    }
                                }
                            }
        

        Brilliant. Cheers!!

        1 Reply Last reply
        0
        • jeremy_kJ Offline
          jeremy_kJ Offline
          jeremy_k
          wrote on last edited by
          #4

          Happy to hear it.

          If you expand from brass to something with more keys, a piano for example, it's probably more efficient to track the previously pressed set of keys rather than iterating through the entire set.

          Asking a question about code? http://eel.is/iso-c++/testcase/

          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