Home > Net >  Qt Quick hit-test in the Item tree
Qt Quick hit-test in the Item tree

Time:06-22

I have some items in the scene:

Rectangle {
    x: 20
    y: 20
    width: 20
    height: 20
    color: 'red'

    Rectangle {
        x: 5
        y: 10
        width: 5
        height: 5
        color: 'green'
    }
}

now I would like to know: given a (x, y) coordinate, which is the topmost visible item that renders something at that coordinate?

E.g.:

  • for (21, 21) that would be the red Rectangle
  • for (26, 32) that would be the green Rectangle
  • for (15, 15) that would be nothing

does Qt Quick offers a simple function to do this?

If not, consider the possibility to add MouseAreas that fill the rectangles. Can I synthesize a press event with specific (x, y) coordinate? This would be even better.

CodePudding user response:

I think what you need is amongst the methods of Qml Item . You should take a look at the childAt method or the visibleChildren property.

CodePudding user response:

Since Item.childAt(...) is broken in this regard, and it has a bug report opened 10 years ago and not yet fixed, I came up with this workaround:

function traverseItemTreeWithClipping(item, pt, f, rootItem) {
    rootItem = rootItem || item
    var p = item.mapFromItem(rootItem, pt)
    var inItemRect = p.x >= 0 && p.y >= 0 && p.x < item.width && p.y < item.height
    if(item.clip && !inItemRect) return
    f(item, p, inItemRect)
    for(var i = 0; i < item.children.length; i  )
        traverseItemTreeWithClipping(item.children[i], pt, f, rootItem)
}

function hitTest(rootItem, pt) {
    var result = undefined
    var z = -Infinity
    traverseItemTreeWithClipping(rootItem, pt, (item, p, inItemRect) => {
        if(item.visible && item.z >= z && inItemRect) {
            result = item
            z = item.z
        }
    })
    return result
}

which takes into account the z property of items, returning the truly visible Item.

  • Related