Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Custom c++ types exposed to QML

    Mobile and Embedded
    3
    4
    4388
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • D
      deion last edited by

      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@

      1 Reply Last reply Reply Quote 0
      • V
        vsorokin last edited by

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

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

        --
        Vasiliy

        1 Reply Last reply Reply Quote 0
        • D
          deion last edited by

          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

          1 Reply Last reply Reply Quote 0
          • C
            chriadam last edited by

            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.

            1 Reply Last reply Reply Quote 0
            • First post
              Last post