The document said we cannot have the same ID in one file. That means we can have the same id in different file,right? I don't know the scope of ID in QML,so i write the code as following to test it.
//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
}
}
My question:
1.
What is the scope of ID in QML? In my test, the result shows that Item cannot access the id of its childen and his brother 's chilren, but can access his parent or brother, right?
2.
the same id in different file just i show in my code, no error and i worked. But how can i differentiate them.
The canonical answer would be:
And the component scope is:
Which itself is not overly informative on what the scope exactly is and how can you make optimal use of it. A tad more informative:
Basically, each
id
in a qml file is implemented sort of like a property of that source's root item. Except it cannot be accessed viasomeobj.someId
, only viasomeId
.Which means that this id can be accessed by any object that exists in the branch that extends from the root object thanks to qml's dynamic scoping.
That is as long as it is not shadowed by an identically named
id
orproperty
.a_item
will be visible ina.qml
as well as any object that exists in the branch its rootItem
grows.It won't be visible from
main.qml
as that object is further down the tree, wherea_item
is not defined.In the same line of thought,
b1
can be accessed froma.qml
becauseb1
is defined inmain.qml
which is wherea.qml
is instantiated. Butb_item
will not be visible from there.In fact, since
a1
andb1
are defined inmain.qml
which is the root of the entire application tree, those twoid
s will be visible from every object of the application, as long as it is a part of the object tree and as long as the identifiers are not shadowed. Note that they will not be visible from singletons or parent-less objects, as those are not part of the application object tree.The same is true for properties, although dynamic scoping only works for properties that are defined for the qml file root element, unlike
id
s which are visible even if they are on a different sub-branch, which is why in the first sentence of this answer I put it as "implemented sort of a property of that source's root item":So
objid
will be visible inCustomObj
, butobjprop
will not be, since it is not an id and not defined in the root object. Theid
is identical to doing this:All
id
s from a given sources are visible in the qml source root object's context and subsequently everything else that will eventually drop down to this context as it lookup fails to resolve the identifier in the "higher" contexts.Finally, keep in mind the subtle trap - it is only possible to use
id
s across sources if you know for certain that your application will instantiate the objects in a compatible context tree.For example:
The trap continues - context tree comes before object tree - the context in which an object is created matters, and cannot be changed once set (puts certain limits on reparenting depending on context dependencies).
As this practical example illustrates, even though in both cases the newly created object is parented to the same object that has the
objA
identifier, the object created inmain.qml
cannot resolve it, because it is created in a context whereobjA
is still not defined, but it works if the object is created in the context ofobjA
, and it will work even if it is burred even higher up the tree.To put it in a more generic way, an
id
becomes visible in the context of the source's root object and remains visible in every subsequent sub-context until it is shadowed by an identically named object. Visibility cannot reach down the tree to contexts that exist before the context theid
is defined in. Note the subtle difference -a_item
refers to anItem
whereasa1
refers to ana
. And sincea1
is visible insidea.qml
it will always refer to that one instance ofa
that is inmain.qml
, regardless of which instance ofa
you might be in, whereasa_item
will refer to a different object for each different instance ofa
.a_item
is "relative" and will be different in every different instance ofa
buta1
is absolute and will always refer to a specific instance ofa
. This is the case becausea1
is a concrete instance whereasa_item
is a type / prototype.Dynamic scoping of
id
s can be quite useful and cut the time it takes to implement a workaround to get access to the stuff you need. Which is also why it is a very good idea to give theid
descriptive names rather than justmain
.For example, if you have a
manager
that manages a number ofviews
, each with a number ofobjects
in them, you can quickly get access the respectiveview
for eachobject
and also get access to the manager without having to implement any additional stuff. The rule of thumb is that themanager
must come first, then eachview
should be created in the context of themanager
, not necessarily directly in it, but in it nonetheless, and eachobject
should be created in the context of aview
. And of course take care not to shadow over things. If you break that rule things will not resolve properly.Naturally, this makes sense only in specific purpose designs where you know what the general structure of the context tree is gonna be like. If you are making generic elements that may go just about anywhere, you should absolutely not be relying on accessing
id
s across sources, and you should implement a more generic usage interface via properties, aliases and whatnot.