folibis
folibis

Reputation: 12854

Wrong coordinates white getting real position of item relative to its parent

I have simple scene with only 2 Rectangles. The difference is that first one uses absolute coordinates and second one uses anchors. In this case both of rectangles are placed on the same place. But I get different coordinates at all.

import QtQuick 2.4
import QtQuick.Window 2.2

Window {
    visible: true
    width: 600
    height: 600
    Rectangle {
        id: rec1
        x: 200
        y: 200
        width: 200
        height: 200
        color: "green"
        opacity: 0.5
        Component.onCompleted: console.log("rec1: " + rec1.x + "," + rec1.y);
    }

    Rectangle {
        id: rec2
        anchors.centerIn: parent
        width: 200
        height: 200
        color: "blue"
        opacity: 0.5
        Component.onCompleted: console.log("rec2: " + rec2.x + "," + rec2.y);
    }
}

The output:

qml: rec2: -100,-100
qml: rec1: 200,200

Yes, I know that it's not really "wrong" result, but how can I get real item coordinates relative to its parent for both of rectangles, i.e. (200,200)?

Upvotes: 4

Views: 3315

Answers (2)

BaCaRoZzo
BaCaRoZzo

Reputation: 7692

The documentation of Item proposes the mapToItem function:

Maps the point (x, y) or rect (x, y, width, height), which is in this item's coordinate system, to item's coordinate system, and returns an object with x and y (and optionally width and height) properties matching the mapped coordinate.

If item is a null value, this maps the point or rect to the coordinate system of the root QML view.

Since the coordinate must be in item' system, the correct way to call the function in your case would be:

<item_id>.mapToItem(<parent_id>, 0, 0)

where (0, 0) is the origin of <item_id> coordinates system.

Since in this case the parent is not an Item itself, we can exploit the null version of the method described by documentation and write:

<item_id>.mapToItem(null, 0, 0)

That's the theory. However, in this particular case (as noted by others), the layout management has not set the coordinate properties yet and thus the methods fail. That seems to be related to the non-consistent state in which items fall during initialisation. Indeed, if we use the function in the onDestruction handler, i.e. when we are sure that initialisation has finished, they give the expected results. See your modified code below:

import QtQuick 2.4
import QtQuick.Window 2.2
import QtQuick.Controls 1.3

Window  {
    visible: true
    width: 600
    height: 600

    Rectangle {
        id: rec1
        x: 200
        y: 200
        width: 200
        height: 200
        color: "green"
        opacity: 0.5
    }

    Rectangle {
        id: rec2
        width: 200
        height: 200
        anchors.centerIn: parent

        color: "blue"
        opacity: 0.5
    }

    Component.onCompleted: {
        console.info("NOPE! :(")
        var cords = rec1.mapToItem(null, 0, 0)
        console.info("rec1: " + cords.x + "  " + cords.y)
        cords = rec2.mapToItem(null, 0, 0)
        console.info("rec2: " + cords.x + "  " + cords.y)
    }

    Component.onDestruction: {
        console.info("YES! :)")
        var cords = rec1.mapToItem(null, 0, 0)
        console.info("rec1: " + cords.x + "  " + cords.y)
        cords = rec2.mapToItem(null, 0, 0)
        console.info("rec2: " + cords.x + "  " + cords.y)
        cords = rec2.mapToItem(null, 100, 100)      // (100, 100) of second rec is...
        console.info("rec2: " + cords.x + "  " + cords.y)   // correctly (300, 300)  !!
    }
}

Output:

qml: NOPE! :(
qml: rec1: 200  200
qml: rec2: -100  -100
qml: YES! :)
qml: rec1: 200  200
qml: rec2: 200  200
qml: rec2: 300  300

Upvotes: 3

Mateusz Drost
Mateusz Drost

Reputation: 1191

Both rectangles have same coordinates but on different time:

import QtQuick 2.4
import QtQuick.Window 2.2

Window {
    visible: true
    width: 600
    height: 600
    Rectangle {
        id: rec1
        x: 200
        y: 200
        width: 200
        height: 200
        color: "green"
        opacity: 0.5
        Component.onCompleted: console.log("rec1: " + rec1.x + "," + rec1.y);
    }

    Rectangle {
        id: rec2
        anchors.centerIn: parent
        width: 200
        height: 200
        color: "blue"
        opacity: 0.5
        Component.onCompleted: console.log("rec2: " + rec2.x + "," + rec2.y);
        onXChanged: console.log("rec2.x: " + rec2.x);
        onYChanged: console.log("rec2.y: " + rec2.y);
    }
}

Upvotes: 2

Related Questions