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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.