问题描述
我想跟踪一个对象的全局位置(或相对于它的一个祖先)并将其绑定到其他项目的位置.
I would like to track a global position of an object (or relative to one of it's ancestors) and bind it to some other item's position.
我正在考虑使用 mapFromItem
如下:
I was thinking about using mapFromItem
as follows:
SomeObject {
x: ancestor.mapFromItem(trackedObject, trackedObject.x, 0).x
y: ancestor.mapFromItem(trackedObject, 0, trackedObject.y).y
}
这种方法的问题在于 mapFromItem
被评估一次并且不会随着它的参数之一更新而更新.此外,映射有时会返回由我无法在代码中跟踪的偏移量改变的新位置(但这不是手头的问题).
The problem with this approach is that the mapFromItem
is evaluated once and doesn't update as one of it's arguments gets updated. Moreover the mapping sometimes returns the new position altered by an offset I'm unable to track in the code (but that's not the matter at hand).
我的第二个想法是通过实现一个函数来计算全局位置,该函数将递归求和偏移量,在提供的祖先处停止(类似于calculateOffsetFrom(ancestor)
).仍然这只是一个函数,就我而言,它不会随着祖先位置之一的变化而重新评估(除非在该函数中,我会将调用它绑定到 onXChanged
为沿途的每个祖先发出信号,这似乎是一个肮脏的解决方案).
My second idea was to calculate the global position by implementing a function that would recursively sum the offsets, stopping at the provided ancestor (something like calculateOffsetFrom(ancestor)
). Still this is just a function and as far as I'm concerned it won't get re-evaluated as one of the ancestors position changes (unless, in that function, I'll bind calling it to the onXChanged
signal for each one of the ancestors along the way, which seems like a dirty solution).
所以最后我给我打算跟踪的对象添加了属性,然后绑定到它们:
So in the end I've added properties to the object I intend to track and then I bind to them:
TrackedObject {
property real offsetX: x + parent.x + parent.parent.x + parent.parent.parent.x ...
property real offsetY: y + parent.y + parent.parent.y + parent.parent.parent.y ...
}
SomeObject {
x: trackedObject.globalX
y: trackedObject.globalY
}
但好吧……是的……这个根本没有缩放,而且很丑.
But well... yeah... this one doesn't scale at all and is as ugly as it gets.
有人知道如何以更简洁的方式解决这个问题吗?
Does anyone have any idea how this problem might be solved in a cleaner way?
就我而言,在这种情况下我不能使用锚点.SomeObject
组件是一个自定义组件,绘制一条从一个点到另一个点的贝塞尔曲线(它将连接两个 TrackedObjects
).为此,我需要坐标之间的差异.如果我是对的,锚不提供任何计算它们之间距离的方法.
As far as I'm concerned I can't use anchors in this case. The SomeObject
component is a custom component drawing a bezier curve from one point to another (it will connect two TrackedObjects
). For that I need the difference between the coordinates. If I'm correct anchors don't provide any way of calculating the distance between them.
推荐答案
这是一个难点,但这是我在我的一个项目中使用的技巧:使蓝色矩形位于另一个父项中而不是绿色矩形移动,保持与它对齐,当绿色矩形移动时以及黄色矩形(绿色矩形父)移动时:
This is a hard point, but here is the hack i used in one of my projects : to make blue rect which is in another parent than green rect move, to stay aligned with it, when green rect moves but also when yellow rect (green rect parent) moves :
import QtQuick 2.0;
Rectangle {
id: window;
width: 800;
height: 480;
property bool globalBit : true;
function updatePos (item_orig, item_dest, bit) {
var pos_abs = window.mapFromItem (item_orig.parent, item_orig.x, item_orig.y);
return window.mapToItem (item_dest.parent, pos_abs.x, pos_abs.y);
}
Rectangle {
id: rectYellow;
width: 400;
height: 300;
x: 300;
y: 200;
color: "yellow";
onXChanged: { globalBit = !globalBit; }
onYChanged: { globalBit = !globalBit; }
MouseArea {
drag {
target: rectYellow;
minimumX: 0;
minimumY: 0;
maximumX: (rectYellow.parent.width - rectYellow.width);
maximumY: (rectYellow.parent.height - rectYellow.height);
}
anchors.fill: parent;
}
Rectangle {
id: rectGreen;
x: 100;
y: 100;
width: 50;
height: 50;
color: "green";
MouseArea {
drag {
target: rectGreen;
minimumX: 0;
minimumY: 0;
maximumX: (rectGreen.parent.width - rectGreen.width);
maximumY: (rectGreen.parent.height - rectGreen.height);
}
anchors.fill: parent;
}
}
}
Rectangle {
id: rectBlue;
x: pos.x + 50;
y: pos.y + 50;
width: 50;
height: 50;
color: "blue";
property var pos : updatePos (rectGreen, rectBlue, globalBit);
}
}
诀窍是使用 mapfromItem 和 mapToItem 将所有坐标带回第一个共同祖先,并强制重新评估函数,只需放置一个传递给计算函数的全局布尔标志,然后每次地图上的可移动元素移动时,您都会反转......您不必将它放在每个地方,只需将其放在可以移动且位于祖先项目内的项目的父项上.
The trick is to bring all coordinates back to the first common ancestor, using both mapfromItem and mapToItem, and to force the function to be re-evaluated, just put a global boolean flag that you pass to the computing function, and that you invert each time a movable element on your map moves... You don't have to put it every where, just on parents of items that can move and are inside the ancestor item.
所以它有效,你的位置永远是正确的,而且它具有很强的可扩展性并且不会添加太多代码.
So it works, your positions will always be right, and it's quite scalable and doesn't add much code.
这篇关于QML - 跟踪组件的全局位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!