Home > Blockchain >  How to use mapToItem inside my Custom Item? (QML, Qt)
How to use mapToItem inside my Custom Item? (QML, Qt)

Time:10-11

I am trying to use the maptoItem() function, it works when I use it inside the main.qml but not when used directly inside my custom item.qml and I have no idea why?

main.qml

Item{
    id:root_toggle
    width: parent.width
    height: parent.height
 //... code here Column Item etc that changes the y,x position of ToggleAbleItem
ToggleAbleItem{
                id:second_toggle_item

                Text {
                    id:fsdfsd
                    text: "text2"
                    color: "blue"
                    font.pixelSize: 24
                }
                Component.onCompleted: {
                    var l = second_toggle_item.mapToItem(root_toggle, 0, 0)
                    console.log(l)
                }

            }
  }
  //... code here

Console log correctly prints [debug] expression for onCompleted (qrc:/main.qml:182) - QPointF(0, 42)

ToggleAbleItem.qml

Item{
id: id_toggleable_item
implicitHeight: childrenRect.height
implicitWidth: childrenRect.width
readonly property point absolute_position: id_toggleable_item.mapToItem(root_toggle, 0, 0) 

Component.onCompleted: {
      console.log(absolute_position)
    }

}

Console log prints wrong values [debug] expression for onCompleted (qrc:/ToggleFunctionality/ToggleAbleItem.qml:53) - QPointF(0, 0)

Can someone explain to me why it is mapping one time correctly and the other time not?

I used the exact same item and id.

EDIT 1:

The goal is not to use parent since it can be the 6th child etc...

I have also tried to set property Item my_root_item: root_toggle inside ToggleAbleItem.qml and then I tried it also on main.qml

CodePudding user response:

So it is basically a matter of binding evaluation. When the ToggleableItem is created and the absolutePosition property is evaluated the positioning of the item has not been done yet and because the bound statement isn't connected to any geometry property of the Item that would trigger a reevaluation the property keeps its initial value of (0,0).

One solution would be to add the toggleableItem.y in front of the binding expression so that the binding is always reevaluated if the y property changes. Basically, make the binding dependent on a geometric property that changes when the item is re-positioned.

The other solution would be to create a function absolutePositionFunc() which gets called after the positioning is done whenever you need to get the absolute position.

import QtQuick

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Item {
        id: rootToggle
        anchors.fill: parent

        Column {
            ToggleableItem {
                id: toggleItem1
                rootItem: rootToggle
                color: "red"

                Component.onCompleted: console.log("toggle item #1", toggleItem1.mapToItem(rootToggle, 0, 0))
            }

            ToggleableItem {
                id: toggleItem2
                rootItem: rootToggle
                color: "green"

                Component.onCompleted: console.log("toggle item #2", toggleItem2.mapToItem(rootToggle, 0, 0))
            }

            onPositioningComplete: {
                console.log(toggleItem1.absolutePosition,
                            toggleItem1.absoultePositionFunc())
                console.log(toggleItem2.absolutePosition,
                            toggleItem2.absoultePositionFunc())
            }
        }
    }
}

ToggleableItem.qml

import QtQuick

Rectangle {
    id: toggleableItem
    required property Item rootItem
    readonly property point absolutePosition: {
        toggleableItem.y // geometric property in binding to trigger re-evaluation
        return toggleableItem.mapToItem(toggleableItem.rootItem, 0, 0)
    }

    function absolutePositionFunc() {
        return toggleableItem.mapToItem(toggleableItem.rootItem, 0, 0)
    }

    width: 100
    height: 40

    Component.onCompleted: console.log("absoulte position",
                                       toggleableItem.absolutePosition)
}

CodePudding user response:

Have a look at my comments on your question. This is the solution using the parent property. Again, don't use ids across different files.

import QtQuick

Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    Item {
        id: rootToggle
        anchors.fill: parent

        ToggleableItem {
            id: secondToggleItem
            x: 50
            y: 50

            Text {
                text: "text2"
                color: "blue"
                font.pixelSize: 24
            }

            Component.onCompleted: console.log(secondToggleItem.mapToItem(rootToggle, 0, 0))
        }
    }
}

ToggleableItem.qml

import QtQuick

Item {
    id: idToggleableItem
    implicitHeight: childrenRect.height
    implicitWidth: childrenRect.width

    readonly property point absolutePosition: idToggleableItem.mapToItem(parent, 0, 0)

    Component.onCompleted: console.log(idToggleableItem.absolutePosition)
}

CodePudding user response:

I had to assign the value after completion inside the Component.onCompleted() function and then the value is no more 0. I also choosed the mapFromItem() function instead of the mapToItem() and called it from the root.

Component.onCompleted: {
      absolute_position = root_toggle.mapFromItem(id_toggleable_item, childrenRect.x,childrenRect.y);
}

I know it works but If anybody has an explanation for this so I can finally fully understand QML I would still be grateful!

  • Related