Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Custom c++ types exposed to QML



  • Hi all,

    Im my c++ code I have a class AppEngine that has an instance member, userSettings of type UserSettings.
    The USerSettings class has Q_PROPERTY -ies like QString serverAddr, etc.
    I expose the userSettings object to C++ like this:
    In C++:

    @ QDeclarativeContext* ctxt = qmlViewer->rootContext(); // qmlViewer is of type QmlApplicationViewer which inherits from QDeclarativeView
    ctxt->setContextProperty("userSettings", &this->m_userSettings);
    @

    In QML I just referenced the userSettings variable and its properties:

    @console.log("!!! userSettings: conntype = " + userSettings.connectionType);@

    All is well; however I wanted to expose just a single object to QML, in my case the AppEngine object, and access the userSettings from QML using something like appEngine.userSettings.connectionType

    For this I declared my UserSettings type as a metaobject, I declared the instance userSettings member as a Q_PROPERTY in AppEngine class; however in QML when I try to access appEngine.userSettings.connectionType the connectionType is 'undefined'; It worked before as I used userSettings directly, without embedding it in appEngine, but I think it's more elegant to have one single root object exposed to QML and sub-objects accessed from this root object.

    Below is copy-paste from the relevant code:

    UserSettings.h

    @
    #ifndef USER_SETTINGS_H
    #define USER_SETTINGS_H

    #include <QObject>
    #include <QMetaType>

    typedef enum ConnectionType {
    CONN_INET = 0,
    CONN_BLUETOOTH = 1
    } ConnectionType;

    class QString;

    class UserSettings : public QObject
    {
    Q_OBJECT
    Q_PROPERTY(int connectionType
    READ connectionType
    WRITE setConnectionType
    NOTIFY connectionTypeChanged)
    …etc, omitted other properties, post was becoming longer than 6000 chars
    friend class AppEngine;

    public:
    UserSettings();
    UserSettings(const UserSettings& settings);
    UserSettings& operator=(const UserSettings& settings);
    virtual ~UserSettings();
    bool operator==(const UserSettings& rhs) const;
    bool operator!=(const UserSettings& rhs) const;

    // m_connectionType property
    void setConnectionType(int aConnectionType) {
        if (m_connectionType != aConnectionType) {
            m_connectionType = (ConnectionType) aConnectionType;
            emit connectionTypeChanged();
        }
    }
    int connectionType() const {
        return m_connectionType;
    }
    
    // m_inetServerAddr property
    void setInetServerAddr(const QString &aInetServerAddr) {
        if (m_inetServerAddr != aInetServerAddr) {
            m_inetServerAddr = aInetServerAddr;
            emit inetServerAddrChanged();
        }
    }
    QString inetServerAddr() const {
        return m_inetServerAddr;
    }
    
    // m_tcpPort property
    void setTcpPort(int aTcpPort) {
        if (m_tcpPort != aTcpPort) {
            m_tcpPort = aTcpPort;
            emit tcpPortChanged();
        }
    }
    int tcpPort() const {
        return m_tcpPort;
    }
    
    // m_btServerAddr property
    void setBtServerAddr(const QString &aBtServerAddr) {
        if (m_btServerAddr != aBtServerAddr) {
            m_btServerAddr = aBtServerAddr;
            emit btServerAddrChanged();
        }
    }
    QString btServerAddr() const {
        return m_btServerAddr;
    }
    
    // m_btServerName property
    void setBtServerName(const QString &aBtServerName) {
        if (m_btServerName != aBtServerName) {
            m_btServerName = aBtServerName;
            emit btServerNameChanged();
        }
    }
    QString btServerName() const {
        return m_btServerName;
    }
    

    signals:
    void connectionTypeChanged();
    void inetServerAddrChanged();
    void tcpPortChanged();
    void btServerAddrChanged();
    void btServerNameChanged();

    private:
    // Data:
    ConnectionType m_connectionType;
    QString m_inetServerAddr;
    int m_tcpPort;
    QString m_btServerAddr;
    QString m_btServerName;

    private:
    static void LoadSettings(UserSettings* settings);
    static void SaveSettings(const UserSettings* settings);
    };

    Q_DECLARE_METATYPE(UserSettings)

    #endif//USER_SETTINGS_H
    @

    AppEngine.h

    @
    #ifndef APP_ENGINE_H
    #define APP_ENGINE_H

    #include <QtGui/QApplication>
    #include <QCamera>
    #include "UserSettings.h"

    …etc

    class AppEngine : public QApplication
    {
    Q_OBJECT
    Q_PROPERTY(UserSettings userSettings
    READ userSettings)

    public:
    AppEngine(int &argc, char *argv);
    virtual ~AppEngine();
    void setUpQML(QmlApplicationViewer
    qmlViewer);
    UserSettings userSettings() const;
    ... etc
    private:
    // Data:
    UserSettings m_userSettings;
    ...etc
    }
    @

    AppEngine.cpp:
    @
    AppEngine::AppEngine(int &argc, char **argv):
    QApplication(argc, argv),
    ...etc
    {
    qRegisterMetaType<UserSettings>();
    UserSettings::LoadSettings(&m_userSettings);
    ...etc
    }

    void AppEngine::setUpQML(QmlApplicationViewer* qmlViewer)
    {
    QObject* rootObjMainQml = qmlViewer->rootObject();
    QDeclarativeContext* ctxt = qmlViewer->rootContext();
    ctxt->setContextProperty("appEngine", this);
    ...etc
    }

    UserSettings AppEngine::userSettings() const {
    return m_userSettings;
    }

    @

    And in QML (SettingsDlg.qml):
    @

    function show() {
        console.log("!!! userSettings: conntype = " + appEngine.userSettings.connectionType + "; inetServerAddr=" + appEngine.userSettings.inetServerAddr + "; tcpPort=" + appEngine.userSettings.tcpPort + "; btServerAddr=" + appEngine.userSettings.btServerAddr + "; btServerName=" + appEngine.userSettings.btServerName);
        connTypeList.selectedIdx = -1;
    

    ...etc
    }
    @

    And this is what I'm getting in console:
    @!!! userSettings: conntype = undefined; inetServerAddr=undefined; tcpPort=undefined; btServerAddr=undefined; btServerName=undefined@



  • in AppEngine.h
    @public:
    ....
    Q_INVOKABLE UserSettings userSettings() const;@

    in Qml:
    @appEngine.userSettings().connectionType
    ... etc@



  • Thanks Vass,

    I modified QML:
    @console.log("!!! userSettings: conntype = " + appEngine.userSettings().connectionType);@

    if in AppEngine.h I keep:

    @ Q_PROPERTY(UserSettings userSettings
    READ userSettings)
    @

    and modify the declaration @UserSettings userSettings() const;@ to @Q_INVOKABLE UserSettings userSettings() const;@
    I get the following error at run-time:
    TypeError: Result of expression 'appEngine.userSettings' [QVariant(UserSettings)] is not a function.

    If I remove in AppEngine.h:
    @ Q_PROPERTY(UserSettings userSettings
    READ userSettings)
    @
    and keep only @Q_INVOKABLE UserSettings userSettings() const;@

    I get the following:
    !!! userSettings: conntype = undefined

    Getting closer to resolving this, but not yet :D

    Thanks,
    Ionut



  • UserSettings derives from QObject? Then you want your property type (or invokable function return type) to be a UserSettings pointer. Passing a QObject in a QVariant (and between QML and C++, all types are marshalled into QVariants) probably isn't going to work as you hope.


Log in to reply