Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt: accessing elements arbitrarily by ID in QML

Tags:

qt

qt5

qml

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:

  1. main.qml , this is the file from which I want to access by ID
  2. Accounts.qml, this is the file where my element is defined

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?

like image 706
Nulik Avatar asked Dec 30 '16 00:12

Nulik


People also ask

What is ID in QML?

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.

What is difference between Qt and QML?

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.

What is QObject in QML?

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"); ...

What is component onCompleted in QML?

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.


1 Answers

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.

like image 135
dtech Avatar answered Sep 18 '22 14:09

dtech