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 bo
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);
}
}
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 item
s 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