QML - what is the id and how does it work?

2019-08-02 18:43发布

Consider this project structure:

MyComponent.qml:

Item {
    id: innerId
}

Usage.qml:

MyComponent {
    id: outerId
}

At first glance it seems like this creates a single object that has 2 different id's simultaneously. But that's impossible, if id is to be considered a property.

To me it seems that an id is not so much a property of an object as it is a property of an object declaration. Is that true?

It would explain how I can refer to the object as innerId in MyComponent.qml and as outerId in Usage.qml yet have it be the same object in both places.

1条回答
三岁会撩人
2楼-- · 2019-08-02 19:21

The id is only visible inside that qml file. The id is not a property, but a special attribute. Don't let the syntax fool you, it was just intended to be in line with qml's idioms, it may look like a property but it is something different altogether.

The id Attribute

Every QML object type has exactly one id attribute. This attribute is provided by the language itself, and cannot be redefined or overridden by any QML object type.

A value may be assigned to the id attribute of an object instance to allow that object to be identified and referred to by other objects. This id must begin with a lower-case letter or an underscore, and cannot contain characters other than letters, numbers and underscores.

Technically, it may appear both ids reference the same object, but that's not the case, the innerId references the Item instance in MyComponent.qml, and the outerId references the MyComponetn instance in Usage.qml. In practice, if you console.log(id) from MyComponetn and Usage you will get the same object instance, since the MyComponent {} instance is just another name for that Item from MyComponent.qml.

The id is not a property, and it can only be access from inside that file, if you need to expose some object to be visible from the outside, you need to do this:

Item { // Something.qml
  property Item innerItem : innerId
  Item {
    id: innerId
  }
}

To me it seems that an id is not so much a property of an object as it is a property of an object declaration. Is that true?

The id is used to refer to an instance of some qml type in the current qml file. If by "object declaration" you mean an instance, then yes, it is true. IMO "object" is a ambiguous, as an object can be a lot of things, an object can be a type, an instance, a property, a function, a JS object... In this regard I think the "Every QML object type has exactly one id attribute" from the documentation is not worded properly.

The id only applies to qml type instances, properties and functions work in a different way, and are accessible from the outside.

If you need to make an analogy to what it's used for, an id might be seen as something similar to a private class member - it is only visible inside the type, and if you need to expose it to the outside - you need to make an accessor for it.

it seems like this creates a single object that has 2 different id's simultaneously

This is not true, as you won't be able to address MyComponent with innerId, so no, it doesn't have 2 different ids, it doesn't have any ids. The id does not really belong to the object, it is just associated to it in the current source file. As mentioned above, the two ids will be referring to the same object, but the object doesn't have two ids.

An analogy to how it works (and I don't mean the actual implementation) would be something similar to references in C++. You can have multiple references to the same object, in different places and with different names. In qml you don't have to write names for instances like in C++, but if you want to refer to an object the usual approach is to use an id, although depending on the object tree you can use the parent property as well. It is not recommended to go overboard with ids in big qml files, as that could degrade performance.

Also, note that unlike ids, you can very much "override" functions and properties, and the behavior is kind of iffy as elaborated in this question, for example, if you override an int property with a string property, the object will end up having that property twice, but if you iterate the object, you will not find one int and one string, but the string twice.

查看更多
登录 后发表回答