I want to access my QML elements by ID from the main file but it is not working. In my test (case) environment I have 2 files:
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
Item {
Accounts {
id: accounts
}
Component.onCompleted: {
console.log(accounts);
console.log(accounts.accounts_pane);
console.log(accounts.list_area);
console.log(accounts.accounts_pane.list_area.list_column.list_identities.model);
}
}
Accounts.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
Pane {
id: accounts_pane
anchors {
fill: parent
}
Rectangle {
id: list_area
border.color: "black"
border.width: 2
anchors {
left: parent.left
right: parent.right
top: parent.top
bottom: parent.bottom
}
Column {
id: list_column
ListView {
id: list_identities
width: list_area.width
height: 200
model: ListModel {
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
}
delegate: Text {
text: name + ',' + number
}
}
}
}
}
So, from the main.qml file I want to change the model of the Accounts (different Company uses different accounts), and I need to do it with Javascript. (My model is a C++ class, registered within the QML engine but I will be using Javascript to switch different model objects). The notation to access the model, as I understand it, should be something like this:
accounts.accounts_pane.list_area.list_column.list_identities.model
However, when testing it, with console.log():
console.log(accounts);
console.log(accounts.accounts_pane);
console.log(accounts.list_area);
console.log(accounts.accounts_pane.list_area.list_column.list_identities.model);
I can't pass past the Pane {} element, which is defined in Accounts.qml. The output of qmlscene
shows me these errors:
hier $ qmlscene main.qml
qml: QQuickPane(0x13b85f0)
qml: undefined
qml: undefined
file:///QT_snippets/qmlscenes/hier/main.qml:13: TypeError: Cannot read property 'list_area' of undefined
How can you access QML elements by ID arbitrarily from the main.qml document?
The id AttributeEvery 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.
QML is the language; its JavaScript runtime is the custom V4 engine, since Qt 5.2; and Qt Quick is the 2D scene graph and the UI framework based on it. These are all part of the Qt Declarative module, while the technology is no longer called Qt Declarative.
A QtObject is a QML representation of the QObject element. This can be seen in Qt source code here where the QML base types are registered: ... void QQmlEnginePrivate::registerBaseTypes(const char *uri, int versionMajor, int versionMinor) { ... qmlRegisterType<QObject>(uri,versionMajor,versionMinor,"QtObject"); ...
Emitted after component "startup" has completed. This can be used to execute script code at startup, once the full QML environment has been established. The corresponding handler is onCompleted. It can be declared on any object. The order of running the onCompleted handlers is undefined.
Preferably you should only use the id to access objects in the same QML file. It is also possible to access objects via ids as long as you are in component scope that is nested inside the component that has the id, as long as it is not shadowed by anything with the same name. In short, ids are only accessible from the inside, but never from the outside, the latter being your usage scenario.
If you want to access elements from other QML files, they must be exposed as properties. Also, properties defined in the root QML file will be visible from the entire project, as long as an identically named property shadows it.
Think of every object in a QML file as a private, whereas properties are public. if you want to access one of those private objects, expose it as a property.
property Item someItem : _item
Item { id: _item }
In your case accounts_pane
is redundant, because it will be the same as accounts
- it is the same object.
If you expose list_identities
directly you don't need to expose all the previous objects in order to access it:
accounts.accounts_pane.list_area.list_column.list_identities.model // no need
accounts.list_identities.model // all you need
Additionally, you can expose specific properties of specific objects as aliases:
// in Accounts.qml
property alias model: list_identities.model
// then you can simply
accounts.model
Lastly, consider this approach to be wrong, you shouldn't need to expose everything for outside use, you should define an interface through which to control the internals of each QML component.
The interface of a Component contains all the top level properties it defines.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With