How to translate a QQuickItem's position into its new parent

655 views Asked by At

I have 2 QQuickItems like below which I can fetch on C++ side using the QMLEngine like this.

QQuickItem * quick_item_1 = m_qml_engine->rootObjects()[0]->findChild<QQuickItem*>("quickitem1");
QQuickItem * quick_item_2 = m_qml_engine->rootObjects()[0]->findChild<QQuickItem*>("quickitem2");

Note: quick_item_1's immediate parent is different & quick_item_2's immediate parent is also different. But they both are drawn on the same application window into different immediate parents.

I am drawing both of them offscreen on a different QQuickItem. Let's call it new_parent_surface. I draw both these items on new_parent_surface by changing their parent to new_parent_surface like this.

quick_item_1->setParentItem(new_parent_surface);
quick_item_2->setParentItem(new_parent_surface);

This works fine for the objective of drawing them on a new parent QQuickItem. I get the both quick_item_1 & quick_item_2 drawn on new_parent_surface. Even though new_parent_surface is not drawn on UI, but if I take a snapshot using grabToImage of new_parent_surface, I can see the 2 items drawn on them. Fine till here.

However the positioning of quick_item_1 & quick_item_2 is not correct. I want to position them similar to the way they were positioned their original parent item. I can do some percentage math & try positioning them the same way as they were drawn on their original parent but isn't there a QQQuickItem or Qt API to translate this positioning to a new parent?

I tried to look into QQuickItem's mapping APIs like mapToItem & trying them out like this.

quick_item_2->mapToItem(new_parent_surface, quick_item_2->position());

But the positioning is still not correct.

So, how can I map a QQuickItem's position into its new parent QQuickItem after doing a setParentItem?

1

There are 1 answers

0
folibis On

Items position is always relative to its parent. And position of the parent is relative to its parent and and so on. But you always can get both relative or global position. QML has lots of coordination translation function. Here is small example that could explain the issue:

import QtQuick 2.7
import QtQuick.Window 2.0
import QtQuick.Controls 2.1

Window {
    id:container
    width: 800
    height: 800
    visible: true

    Component {
        id: rect
        Rectangle {
            property bool imParent: false
            x: 50 + Math.round(Math.random() * 550)
            y: 50 + Math.round(Math.random() * 550)
            width: 100 + Math.round(Math.random() * 100)
            height: 100 + Math.round(Math.random() * 100)
            color: Qt.rgba(Math.random(),Math.random(),Math.random(),1);
            Drag.active: dragArea.drag.active
            MouseArea {
                id: dragArea
                anchors.fill: parent
                drag.target: parent
            }
            Text {
                anchors.centerIn: parent
                text: imParent ? "I'm parent" : "Drag me"
                color: "white"
            }
        }
    }

    Rectangle {
        id: blk
        x: 10
        y: 10
        z: 100
        parent: null
        height: 50
        width: 50
        radius: 5
        border.color: "white"
        color: "black"

    }

    Repeater {
        id: reptr
        model: 5
        property int pos: 0
        Loader {
            id: loader
            sourceComponent: rect
            onLoaded: {
                if(blk.parent == null) {
                    blk.parent = loader.item;
                    loader.item.imParent = true;
                }
            }
        }
    }

    Row {
        anchors.horizontalCenter: container.contentItem.horizontalCenter
        spacing: 2
        Button {
            text: "Reparent relative to parent"
            onClicked: {
                reptr.pos ++;
                if(reptr.pos >= reptr.model) {
                    reptr.pos = 0;
                }
                var item = reptr.itemAt(reptr.pos).item;
                blk.parent.imParent = false;
                blk.parent = item;
                blk.parent.imParent = true;
            }
        }
        Button {
            text: "Reparent relative to scene"
            onClicked: {
                reptr.pos ++;
                if(reptr.pos >= reptr.model) {
                    reptr.pos = 0;
                }
                var item = reptr.itemAt(reptr.pos).item;
                var coord = blk.mapToGlobal(blk.x, blk.y);
                blk.parent.imParent = false;
                blk.parent = item;
                blk.parent.imParent = true;
                coord = blk.mapFromGlobal(coord.x, coord.y);
                blk.x = coord.x;
                blk.y = coord.y;
            }
        }
    }
}