该文件称我们在一个文件中不能使用相同的ID.这意味着我们可以在不同的文件中拥有相同的ID,对吧?我不知道QML中ID的范围,所以我编写如下代码来测试它.
//a.qml
Item {
id: a_item
x:20;
y:b_item.x // cannot access this id
y:b1.x1 // can access
Item {
id:a1
x:20
Component.onCompleted : a1.x //this a1 is a.qml's a1 not the a1 in main.qml
}
}
//b.qml
Item {
id: b_item
x:20;
property int x1: 30;
}
//main.qml
Item {
a {
id:a1
Component.onCompleted : b1.x = 1 //can access
}
b {
id:b1
}
function() {
a_item.x = 1; // cannot access this id
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题:
1.
QML中ID的范围是什么?在我的测试中,结果显示Item无法访问其孩子及其兄弟的孩子的身份,但可以访问他的父母或兄弟,对吧?
2.
在同一ID在不同的文件只是我表现出我的代码,没有错误,我的工作.但我怎样才能区分它们.
规范的答案是:
ids 的范围是组件范围.
组件范围是:
QML文档中的每个QML组件都定义了逻辑范围.每个文档至少有一个根组件,但也可以有其他内联子组件.组件范围是组件中对象ID与组件根对象属性的并集.
对于范围究竟是什么以及如何最佳地利用它本身并不过分提供信息.更多信息:
在QML中,组件实例将其组件范围连接在一起以形成范围层次结构.组件实例可以直接访问其祖先的组件范围.
基本上,idqml文件中的每个文件都被实现,就像该源的根项的属性一样.除非它无法通过someobj.someId,只能通过someId.
这意味着,由于qml的动态范围,可以通过从根对象扩展的分支中存在的任何对象访问此id.
只要它没有被同名的id或阴影所遮蔽property.
a_item将在a.qml其根部Item增长的分支中存在的任何对象中可见.
它将不可见,main.qml因为该对象位于树的下方,a_item未定义.
在同一思路中,b1可以从中定义a.qml因为b1定义在main.qml哪里a.qml实例化.但是b_item从那里看不到.
事实上,由于a1并且b1定义main.qml了整个应用程序树的根,所以这两个ids将从应用程序的每个对象可见,只要它是对象树的一部分并且只要标识符不是阴影.请注意,它们不会从单例或无父对象中看到,因为它们不是应用程序对象树的一部分.
obj tree a1 b1 a_item b_item
main.qml D D X X
a.qm V V D X
Item a1 V V V X
b.qml V V X D
D - defined here, V - visible here, X - not available
Run Code Online (Sandbox Code Playgroud)
对于属性也是如此,尽管动态范围仅适用于为qml文件根元素定义的属性,不像ids是可见的,即使它们位于不同的子分支上,这就是为什么在这个答案的第一句中我把它作为"实现了该源的根项的属性":
Obj
Obj
Obj
id: objid
property objprop
CustomObj
Run Code Online (Sandbox Code Playgroud)
因此objid它将是可见的CustomObj,但objprop不会,因为它不是一个id而没有在根对象中定义.该id等同于这样做:
Obj
property objid : _objid
Obj
Obj
id: _objid
Run Code Online (Sandbox Code Playgroud)
id来自给定源的所有内容在qml源根对象的上下文中都是可见的,随后是最终将下拉到此上下文的所有其他内容,因为它查找无法解析"更高"上下文中的标识符.
最后,请记住微妙的陷阱 - id如果您确定应用程序将在兼容的上下文树中实例化对象,则只能跨源使用.
例如:
A.qml {
id: objA
B { } // objA will be visible to this object
}
main.qml
A {
B {} // objA will NOT be visible to this object
}
B {} // objA will NOT be visible to this object
Run Code Online (Sandbox Code Playgroud)
陷阱继续 - 上下文树出现在对象树之前 - 创建对象的上下文很重要,一旦设置就无法更改(根据上下文依赖性对重新定义设置某些限制).
// ObjA.qml
Item {
id: objA
Component {
id: cm
ObjB {}
}
function create() { cm.createObject(objA) }
}
// ObjB.qml
Item {
Component.onCompleted: console.log(objA)
}
// main.qml
Component {
id: cm
Rect {}
}
Obj {
anchors.fill: parent
MouseArea {
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
onClicked: {
if (mouse.button === Qt.LeftButton) {
cm.createObject(parent)
} else {
parent.create()
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
正如这个实际示例所示,即使在两种情况下,新创建的对象都是具有objA标识符的同一对象的父级,但是创建的对象main.qml无法解析它,因为它是在objA尚未定义的上下文中创建的,但它可以正常工作如果对象是在上下文中创建的objA,那么它即使在树上更高的地方也会被激活.
为了以更通用的方式,它在id源的根对象的上下文中变得可见,并且在每个后续子上下文中保持可见,直到它被具有相同名称的对象遮蔽.可见性无法将树向下到达id定义上下文之前存在的上下文.注意细微差别 - a_item指的是Itemwhile a1指的是a.而且,由于a1是可见里面a.qml它总是引用的一个例子a就是在main.qml,不管是哪个的情况下a,你可能会在,而a_item将涉及到不同对象的每个不同的实例a.a_item是"相对的",并且在每个不同的实例中都是不同的,a但是a1绝对的,并且总是指特定的实例a.这是因为a1是一个具体的实例,a_item而是一个类型/原型.
// Obj.qml
Item {
id: obj
Component.onCompleted: console.log(obj === oid)
}
// main.qml
Obj { } // false
Obj { id: oid } // true
Run Code Online (Sandbox Code Playgroud)
动态范围化ids非常有用,可以缩短实现变通方法以获取所需内容的时间.这也是为什么给出id描述性名称而不仅仅是一个非常好的主意main.
例如,如果你有一个manager管理一些数量的数量views,每个数量都包含objects在其中,你可以快速访问各自的相应数据view,object并且无需实现任何其他内容即可访问经理.manager必须遵循的原则是必须首先,然后每个都view应该在它的上下文中创建manager,不一定直接在其中,但在其中,每个都object应该在a的上下文中创建view.当然要注意不要掩盖事物.如果你打破这个规则,事情将无法正常解决.
View.qml { id: view }
manager
view1
object // view is view1
view2
object // view is view2
view3
object // view is view3
Run Code Online (Sandbox Code Playgroud)
当然,这只在特定目的设计中才有意义,在这些设计中,您知道上下文树的一般结构是什么样的.如果您正在制作几乎可以在任何地方使用的通用元素,那么您绝对不应该依赖于id跨源访问,并且您应该通过属性,别名和诸如此类的东西来实现更通用的使用界面.