Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt
  • Unsolved
Collapse
qtws26_logo

The Qt Event of the Year: Qt World Summit 2026

Save Your Spot >
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Accessing members of a class defined within another class
Qt 6.12 LTS is out! See what's new in the release blog

Accessing members of a class defined within another class

Scheduled Pinned Locked Moved Solved QML and Qt Quick
12 Posts 4 Posters 1.3k Views 2 Watching
  • 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.
  • _ Offline
    _ Offline
    _-Peter-_
    wrote on last edited by
    #1

    Hi Everyone,
    I've been struggling to get the "proof of concept" code at the bottom to work as I want and hoping to get some help.

    The use case is that I'll have a c++ back end processing raw values from an input stream and I want to access these values from the QML UI like this
    Text {text: qsTr("Value 1:" + backend.Value1.Value + " " + backend.Value1.Units)}
    Text {text: qsTr("Value 2:" + backend.Value2.Value + " " + backend.Value2.Units)}

    The code below is just trying to get the QML / C++ interface working before developing the backend.

    I also realise that each Value is being instantiated with the same values but I've been progressively working through the errors thrown during compile and execution and haven't got to sorting this bit.

    The code below compiles but throws "TypeError: Cannot read property 'Value' of undefined" for the two text lines in main.qml.

    Following this example https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html I can get the functionality I want for a single value when it's not a member of another class. While I could create a separate class for each value I wouldn't be following good object orientated practice particularly as I have about 60 different values to access from QML.

    As much as I've read the documents on Integrating QML and C++ and tried various versions of the code below, I've got no idea how to get QML to access the members of the Value class.

    Appreciate any help and direction.
    Peter

    backend.h

    #ifndef BACKEND_H
    #define BACKEND_H
    
    #include <QObject>
    #include <QString>
    
    class Value : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(qreal Value READ getValue NOTIFY valueChanged)
        Q_PROPERTY(QString Units READ getUnits CONSTANT)
    
    public:
        explicit Value(QObject *parent = nullptr);
        // Value(QString _units, qreal _scale);
        Value(QString _units, qreal _scale);
    
        qreal getValue();
        QString getUnits();
        void newRawValue(qreal _rawValue);
    
    signals:
        void valueChanged();
    
    private:
        QString units = ""; //prefer to be const
        qreal rawValue = 0;
        qreal scale = 0; //prefer to be const
    };
    
    class BackEnd : public QObject
    {
        Q_OBJECT
    
    public:
        explicit BackEnd(QObject *parent = nullptr);
    
        Value Value1;// = Value("km",3);
        Value Value2;// = Value("hr",4);
    };
    
    #endif // BACKEND_H
    

    backend.ccp

    #include "backend.h"
    
    Value::Value(QObject *parent) : QObject(parent){
    }
    //Value::Value(QString _units, qreal _scale){
    //    units = _units;
    //    scale = _scale;
    //}
    qreal Value :: getValue(){return rawValue*scale;}
    
    QString Value :: getUnits(){return units;}
    
    void Value :: newRawValue(qreal _rawValue){
        rawValue = _rawValue;
        emit valueChanged();
    }
    
    BackEnd::BackEnd(QObject *parent) : QObject(parent){
    }
    

    main.cpp

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    
    #include "backend.h"
    
    int main(int argc, char *argv[])
    {
        QGuiApplication app(argc, argv);
    
        qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
        return app.exec();
    }
    

    main.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    
    import io.qt.examples.backend 1.0
    
    Window {
        visible: true
        width: 640
        height: 480
    
        BackEnd {id: backend}
    
        Text {text: qsTr("Value 1:" + backend.Value1.Value + " " + backend.Value1.Units)}
        Text {text: qsTr("Value 2:" + backend.Value2.Value + " " + backend.Value2.Units)}
    }
    
    
    J.HilkJ jeremy_kJ 2 Replies Last reply
    0
    • _ _-Peter-_

      Hi Everyone,
      I've been struggling to get the "proof of concept" code at the bottom to work as I want and hoping to get some help.

      The use case is that I'll have a c++ back end processing raw values from an input stream and I want to access these values from the QML UI like this
      Text {text: qsTr("Value 1:" + backend.Value1.Value + " " + backend.Value1.Units)}
      Text {text: qsTr("Value 2:" + backend.Value2.Value + " " + backend.Value2.Units)}

      The code below is just trying to get the QML / C++ interface working before developing the backend.

      I also realise that each Value is being instantiated with the same values but I've been progressively working through the errors thrown during compile and execution and haven't got to sorting this bit.

      The code below compiles but throws "TypeError: Cannot read property 'Value' of undefined" for the two text lines in main.qml.

      Following this example https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html I can get the functionality I want for a single value when it's not a member of another class. While I could create a separate class for each value I wouldn't be following good object orientated practice particularly as I have about 60 different values to access from QML.

      As much as I've read the documents on Integrating QML and C++ and tried various versions of the code below, I've got no idea how to get QML to access the members of the Value class.

      Appreciate any help and direction.
      Peter

      backend.h

      #ifndef BACKEND_H
      #define BACKEND_H
      
      #include <QObject>
      #include <QString>
      
      class Value : public QObject
      {
          Q_OBJECT
          Q_PROPERTY(qreal Value READ getValue NOTIFY valueChanged)
          Q_PROPERTY(QString Units READ getUnits CONSTANT)
      
      public:
          explicit Value(QObject *parent = nullptr);
          // Value(QString _units, qreal _scale);
          Value(QString _units, qreal _scale);
      
          qreal getValue();
          QString getUnits();
          void newRawValue(qreal _rawValue);
      
      signals:
          void valueChanged();
      
      private:
          QString units = ""; //prefer to be const
          qreal rawValue = 0;
          qreal scale = 0; //prefer to be const
      };
      
      class BackEnd : public QObject
      {
          Q_OBJECT
      
      public:
          explicit BackEnd(QObject *parent = nullptr);
      
          Value Value1;// = Value("km",3);
          Value Value2;// = Value("hr",4);
      };
      
      #endif // BACKEND_H
      

      backend.ccp

      #include "backend.h"
      
      Value::Value(QObject *parent) : QObject(parent){
      }
      //Value::Value(QString _units, qreal _scale){
      //    units = _units;
      //    scale = _scale;
      //}
      qreal Value :: getValue(){return rawValue*scale;}
      
      QString Value :: getUnits(){return units;}
      
      void Value :: newRawValue(qreal _rawValue){
          rawValue = _rawValue;
          emit valueChanged();
      }
      
      BackEnd::BackEnd(QObject *parent) : QObject(parent){
      }
      

      main.cpp

      #include <QGuiApplication>
      #include <QQmlApplicationEngine>
      
      #include "backend.h"
      
      int main(int argc, char *argv[])
      {
          QGuiApplication app(argc, argv);
      
          qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");
      
          QQmlApplicationEngine engine;
          engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
      
          return app.exec();
      }
      

      main.qml

      import QtQuick 2.12
      import QtQuick.Window 2.12
      
      import io.qt.examples.backend 1.0
      
      Window {
          visible: true
          width: 640
          height: 480
      
          BackEnd {id: backend}
      
          Text {text: qsTr("Value 1:" + backend.Value1.Value + " " + backend.Value1.Units)}
          Text {text: qsTr("Value 2:" + backend.Value2.Value + " " + backend.Value2.Units)}
      }
      
      
      J.HilkJ Offline
      J.HilkJ Offline
      J.Hilk
      Moderators
      wrote on last edited by
      #2

      @_-Peter-_ thats so not possible, because your Value class is not a trivial type.
      I think if you would fully register the class with the meta system you might have more luck accessing the direct member. But, the far easier option would be the following:

      public:
          explicit BackEnd(QObject *parent = nullptr);
      
          QINVOKABLE QVariant getValue1() {return QVariant::fromValue(Value1);} 
          Value Value1;// = Value("km",3);
          Value Value2;// = Value("hr",4)
      
      Text {text: qsTr("Value 1:" + backend.getValue1().Value + " " + backend.getValue1().Units)}
      

      Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


      Q: What's that?
      A: It's blue light.
      Q: What does it do?
      A: It turns blue.

      GrecKoG _ 2 Replies Last reply
      0
      • J.HilkJ J.Hilk

        @_-Peter-_ thats so not possible, because your Value class is not a trivial type.
        I think if you would fully register the class with the meta system you might have more luck accessing the direct member. But, the far easier option would be the following:

        public:
            explicit BackEnd(QObject *parent = nullptr);
        
            QINVOKABLE QVariant getValue1() {return QVariant::fromValue(Value1);} 
            Value Value1;// = Value("km",3);
            Value Value2;// = Value("hr",4)
        
        Text {text: qsTr("Value 1:" + backend.getValue1().Value + " " + backend.getValue1().Units)}
        
        GrecKoG Offline
        GrecKoG Offline
        GrecKo
        Qt Champions 2018
        wrote on last edited by
        #3

        Your bakend object doesn't have any exposed properties named Value1 and Value2.
        Use Q_PROPERTY to expose them like you did in your Value class.

        _ 1 Reply Last reply
        0
        • J.HilkJ J.Hilk

          @_-Peter-_ thats so not possible, because your Value class is not a trivial type.
          I think if you would fully register the class with the meta system you might have more luck accessing the direct member. But, the far easier option would be the following:

          public:
              explicit BackEnd(QObject *parent = nullptr);
          
              QINVOKABLE QVariant getValue1() {return QVariant::fromValue(Value1);} 
              Value Value1;// = Value("km",3);
              Value Value2;// = Value("hr",4)
          
          Text {text: qsTr("Value 1:" + backend.getValue1().Value + " " + backend.getValue1().Units)}
          
          _ Offline
          _ Offline
          _-Peter-_
          wrote on last edited by
          #4

          @J-Hilk Thanks for the response. When I add the line in I get the errors "incomplete result type 'QVariant' in function definition" and "incomplete type 'QVariant' named in nested name specifier"

          class BackEnd : public QObject
          {
              Q_OBJECT
          
          public:
              explicit BackEnd(QObject *parent = nullptr);
          
              Q_INVOKABLE QVariant getValue1(){return QVariant::fromValue(Value1);}
              Value Value1();// = Value("km",3);
              Value Value2;// = Value("hr",4);
          };
          
          J.HilkJ 1 Reply Last reply
          0
          • GrecKoG GrecKo

            Your bakend object doesn't have any exposed properties named Value1 and Value2.
            Use Q_PROPERTY to expose them like you did in your Value class.

            _ Offline
            _ Offline
            _-Peter-_
            wrote on last edited by
            #5

            @GrecKo I had given that a go but got the parse warning " Warning: Property declaration Value1 has no READ accessor function or associated MEMBER variable. The property will be invalid." and compiling ends.

            I tried to a few different variations but got the same error.

            class BackEnd : public QObject
            {
                Q_OBJECT
                Q_PROPERTY(qreal Value1.Value READ Value1.getValue NOTIFY Value1.valueChanged)
                Q_PROPERTY(QString Value1.Units READ Value1.getUnits CONSTANT)
                Q_PROPERTY(qreal Value2.Value READ Value2.getValue NOTIFY Value2.valueChanged)
                Q_PROPERTY(QString Value2.Units READ Value2.getUnits CONSTANT)
            
            public:
                explicit BackEnd(QObject *parent = nullptr);
            
                Value Value1;// = Value("km",3);
                Value Value2;// = Value("hr",4);
            };
            
            1 Reply Last reply
            0
            • _ _-Peter-_

              @J-Hilk Thanks for the response. When I add the line in I get the errors "incomplete result type 'QVariant' in function definition" and "incomplete type 'QVariant' named in nested name specifier"

              class BackEnd : public QObject
              {
                  Q_OBJECT
              
              public:
                  explicit BackEnd(QObject *parent = nullptr);
              
                  Q_INVOKABLE QVariant getValue1(){return QVariant::fromValue(Value1);}
                  Value Value1();// = Value("km",3);
                  Value Value2;// = Value("hr",4);
              };
              
              J.HilkJ Offline
              J.HilkJ Offline
              J.Hilk
              Moderators
              wrote on last edited by
              #6

              @_-Peter-_ said in Accessing members of a class defined within another class:

              "incomplete type 'QVariant'

              you should know this!

              #include <QVariant>


              Be aware of the Qt Code of Conduct, when posting : https://forum.qt.io/topic/113070/qt-code-of-conduct


              Q: What's that?
              A: It's blue light.
              Q: What does it do?
              A: It turns blue.

              _ 1 Reply Last reply
              1
              • J.HilkJ J.Hilk

                @_-Peter-_ said in Accessing members of a class defined within another class:

                "incomplete type 'QVariant'

                you should know this!

                #include <QVariant>

                _ Offline
                _ Offline
                _-Peter-_
                wrote on last edited by
                #7

                @J-Hilk Doh! M)

                Now I get a "static assertion failed" during compile and directed to use the Q_DECLARE_METATYPE macro.

                Will read the docs for the Q_DECLARE_METATYPE macro.

                1 Reply Last reply
                1
                • _ _-Peter-_

                  Hi Everyone,
                  I've been struggling to get the "proof of concept" code at the bottom to work as I want and hoping to get some help.

                  The use case is that I'll have a c++ back end processing raw values from an input stream and I want to access these values from the QML UI like this
                  Text {text: qsTr("Value 1:" + backend.Value1.Value + " " + backend.Value1.Units)}
                  Text {text: qsTr("Value 2:" + backend.Value2.Value + " " + backend.Value2.Units)}

                  The code below is just trying to get the QML / C++ interface working before developing the backend.

                  I also realise that each Value is being instantiated with the same values but I've been progressively working through the errors thrown during compile and execution and haven't got to sorting this bit.

                  The code below compiles but throws "TypeError: Cannot read property 'Value' of undefined" for the two text lines in main.qml.

                  Following this example https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html I can get the functionality I want for a single value when it's not a member of another class. While I could create a separate class for each value I wouldn't be following good object orientated practice particularly as I have about 60 different values to access from QML.

                  As much as I've read the documents on Integrating QML and C++ and tried various versions of the code below, I've got no idea how to get QML to access the members of the Value class.

                  Appreciate any help and direction.
                  Peter

                  backend.h

                  #ifndef BACKEND_H
                  #define BACKEND_H
                  
                  #include <QObject>
                  #include <QString>
                  
                  class Value : public QObject
                  {
                      Q_OBJECT
                      Q_PROPERTY(qreal Value READ getValue NOTIFY valueChanged)
                      Q_PROPERTY(QString Units READ getUnits CONSTANT)
                  
                  public:
                      explicit Value(QObject *parent = nullptr);
                      // Value(QString _units, qreal _scale);
                      Value(QString _units, qreal _scale);
                  
                      qreal getValue();
                      QString getUnits();
                      void newRawValue(qreal _rawValue);
                  
                  signals:
                      void valueChanged();
                  
                  private:
                      QString units = ""; //prefer to be const
                      qreal rawValue = 0;
                      qreal scale = 0; //prefer to be const
                  };
                  
                  class BackEnd : public QObject
                  {
                      Q_OBJECT
                  
                  public:
                      explicit BackEnd(QObject *parent = nullptr);
                  
                      Value Value1;// = Value("km",3);
                      Value Value2;// = Value("hr",4);
                  };
                  
                  #endif // BACKEND_H
                  

                  backend.ccp

                  #include "backend.h"
                  
                  Value::Value(QObject *parent) : QObject(parent){
                  }
                  //Value::Value(QString _units, qreal _scale){
                  //    units = _units;
                  //    scale = _scale;
                  //}
                  qreal Value :: getValue(){return rawValue*scale;}
                  
                  QString Value :: getUnits(){return units;}
                  
                  void Value :: newRawValue(qreal _rawValue){
                      rawValue = _rawValue;
                      emit valueChanged();
                  }
                  
                  BackEnd::BackEnd(QObject *parent) : QObject(parent){
                  }
                  

                  main.cpp

                  #include <QGuiApplication>
                  #include <QQmlApplicationEngine>
                  
                  #include "backend.h"
                  
                  int main(int argc, char *argv[])
                  {
                      QGuiApplication app(argc, argv);
                  
                      qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd");
                  
                      QQmlApplicationEngine engine;
                      engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
                  
                      return app.exec();
                  }
                  

                  main.qml

                  import QtQuick 2.12
                  import QtQuick.Window 2.12
                  
                  import io.qt.examples.backend 1.0
                  
                  Window {
                      visible: true
                      width: 640
                      height: 480
                  
                      BackEnd {id: backend}
                  
                      Text {text: qsTr("Value 1:" + backend.Value1.Value + " " + backend.Value1.Units)}
                      Text {text: qsTr("Value 2:" + backend.Value2.Value + " " + backend.Value2.Units)}
                  }
                  
                  
                  jeremy_kJ Offline
                  jeremy_kJ Offline
                  jeremy_k
                  wrote on last edited by jeremy_k
                  #8

                  This is strictly practical advice. If this is an intellectual exercise, please ignore. All sorts of interesting things happen when the rules aren't followed.

                  @_-Peter-_ said in Accessing members of a class defined within another class:

                  Q_PROPERTY(qreal Value1.Value READ Value1.getValue NOTIFY Value1.valueChanged)
                  

                  In QML, not solely of custom, . is a token separator, and a token starting with an upper-case letter is a type.

                  https://doc.qt.io/qt-6/qtqml-documents-definetypes.html#naming-custom-qml-object-types:

                  It must begin with an uppercase letter.

                  Ignoring this leads to headaches. If the goal is working code rather than exploring the limits of the framework, do not use . or strings starting with upper case letters in property names.

                  @_-Peter-_ said in Accessing members of a class defined within another class:

                  backend.h

                  [...]
                  

                  backend.ccp

                  [...]
                  

                  Only tangentially connected, but defining separate .h, .cpp, and main.cpp files for an example makes the code harder to follow for a forum post. My not at all humble opinion is that everything should be inlined to focus on compilation units rather than files.

                  Asking a question about code? http://eel.is/iso-c++/testcase/

                  _ 1 Reply Last reply
                  0
                  • jeremy_kJ jeremy_k

                    This is strictly practical advice. If this is an intellectual exercise, please ignore. All sorts of interesting things happen when the rules aren't followed.

                    @_-Peter-_ said in Accessing members of a class defined within another class:

                    Q_PROPERTY(qreal Value1.Value READ Value1.getValue NOTIFY Value1.valueChanged)
                    

                    In QML, not solely of custom, . is a token separator, and a token starting with an upper-case letter is a type.

                    https://doc.qt.io/qt-6/qtqml-documents-definetypes.html#naming-custom-qml-object-types:

                    It must begin with an uppercase letter.

                    Ignoring this leads to headaches. If the goal is working code rather than exploring the limits of the framework, do not use . or strings starting with upper case letters in property names.

                    @_-Peter-_ said in Accessing members of a class defined within another class:

                    backend.h

                    [...]
                    

                    backend.ccp

                    [...]
                    

                    Only tangentially connected, but defining separate .h, .cpp, and main.cpp files for an example makes the code harder to follow for a forum post. My not at all humble opinion is that everything should be inlined to focus on compilation units rather than files.

                    _ Offline
                    _ Offline
                    _-Peter-_
                    wrote on last edited by
                    #9

                    @jeremy_k Thanks for the advice.

                    1 Reply Last reply
                    0
                    • _ Offline
                      _ Offline
                      _-Peter-_
                      wrote on last edited by
                      #10

                      After almost turning software problems into a hardware problem a few times, I finally got it to work as I intended.

                      With the addition of Q_INVOKABLE as suggested by @J-Hilk and the removal of the Value(QObject *parent) constructor, it all works.

                      Final code for prosperity below:
                      backend.h

                      #ifndef BACKEND_H
                      #define BACKEND_H
                      
                      #include <QObject>
                      #include <QString>
                      #include <QVariant>
                      
                      
                      class Value : public QObject
                      {
                          Q_OBJECT
                          Q_PROPERTY(qreal value READ getValue NOTIFY valueChanged)
                          Q_PROPERTY(QString units READ getUnits CONSTANT)
                      
                      public:
                          Value(QString _units, qreal _scale);
                          ~Value();
                      
                          qreal getValue() const;
                          QString getUnits() const;
                          void newRawValue(qreal _rawValue);
                      
                      signals:
                          void valueChanged();
                      
                      private:
                          const QString units;
                          qreal rawValue = 1;
                          const qreal scale;
                      };
                      
                      class BackEnd : public QObject
                      {
                          Q_OBJECT
                      
                      public:
                          explicit BackEnd(QObject *parent = nullptr);
                      
                          Q_INVOKABLE QVariant getValue1(){return QVariant::fromValue(value1);}
                          Q_INVOKABLE QVariant getValue2(){return QVariant::fromValue(value2);}
                      
                      private:
                          Value *value1 = new Value("km",3);
                          Value *value2 = new Value("hr",4);
                      };
                      
                      #endif // BACKEND_H
                      

                      backend.cpp

                      #include "backend.h"
                      
                      Value::Value(QString _units, qreal _scale): units(_units), scale(_scale){}
                      
                      Value::~Value(){}
                      
                      qreal Value :: getValue() const {return rawValue*scale;}
                      
                      QString Value :: getUnits()const {return units;}
                      
                      void Value :: newRawValue(qreal _rawValue){
                          if(rawValue == _rawValue)
                              return;
                      
                          rawValue = _rawValue;
                          emit valueChanged();
                      }
                      
                      BackEnd :: BackEnd(QObject *parent) : QObject(parent){
                      }
                      

                      main.cpp

                      #include <QGuiApplication>
                      #include <QQmlApplicationEngine>
                      
                      #include "backend.h"
                      
                      int main(int argc, char *argv[])
                      {
                          QGuiApplication app(argc, argv);
                      
                          qmlRegisterType<BackEnd>("backend", 1, 0, "BackEnd");
                      
                          QQmlApplicationEngine engine;
                          engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
                      
                          return app.exec();
                      }
                      

                      main.qml

                      import QtQuick 2.12
                      import QtQuick.Window 2.12
                      
                      import backend 1.0
                      
                      Window {
                          visible: true
                          width: 640
                          height: 480
                      
                          BackEnd {id: backend}
                      
                          Text {text: qsTr("Value 1: " + backend.getValue1().value + " " + backend.getValue1().units)}
                          Text {y: 20;text: qsTr("Value 2: " + backend.getValue2().value + " " + backend.getValue2().units)}
                      }
                      
                      GrecKoG 1 Reply Last reply
                      1
                      • _ _-Peter-_ has marked this topic as solved on
                      • _ _-Peter-_

                        After almost turning software problems into a hardware problem a few times, I finally got it to work as I intended.

                        With the addition of Q_INVOKABLE as suggested by @J-Hilk and the removal of the Value(QObject *parent) constructor, it all works.

                        Final code for prosperity below:
                        backend.h

                        #ifndef BACKEND_H
                        #define BACKEND_H
                        
                        #include <QObject>
                        #include <QString>
                        #include <QVariant>
                        
                        
                        class Value : public QObject
                        {
                            Q_OBJECT
                            Q_PROPERTY(qreal value READ getValue NOTIFY valueChanged)
                            Q_PROPERTY(QString units READ getUnits CONSTANT)
                        
                        public:
                            Value(QString _units, qreal _scale);
                            ~Value();
                        
                            qreal getValue() const;
                            QString getUnits() const;
                            void newRawValue(qreal _rawValue);
                        
                        signals:
                            void valueChanged();
                        
                        private:
                            const QString units;
                            qreal rawValue = 1;
                            const qreal scale;
                        };
                        
                        class BackEnd : public QObject
                        {
                            Q_OBJECT
                        
                        public:
                            explicit BackEnd(QObject *parent = nullptr);
                        
                            Q_INVOKABLE QVariant getValue1(){return QVariant::fromValue(value1);}
                            Q_INVOKABLE QVariant getValue2(){return QVariant::fromValue(value2);}
                        
                        private:
                            Value *value1 = new Value("km",3);
                            Value *value2 = new Value("hr",4);
                        };
                        
                        #endif // BACKEND_H
                        

                        backend.cpp

                        #include "backend.h"
                        
                        Value::Value(QString _units, qreal _scale): units(_units), scale(_scale){}
                        
                        Value::~Value(){}
                        
                        qreal Value :: getValue() const {return rawValue*scale;}
                        
                        QString Value :: getUnits()const {return units;}
                        
                        void Value :: newRawValue(qreal _rawValue){
                            if(rawValue == _rawValue)
                                return;
                        
                            rawValue = _rawValue;
                            emit valueChanged();
                        }
                        
                        BackEnd :: BackEnd(QObject *parent) : QObject(parent){
                        }
                        

                        main.cpp

                        #include <QGuiApplication>
                        #include <QQmlApplicationEngine>
                        
                        #include "backend.h"
                        
                        int main(int argc, char *argv[])
                        {
                            QGuiApplication app(argc, argv);
                        
                            qmlRegisterType<BackEnd>("backend", 1, 0, "BackEnd");
                        
                            QQmlApplicationEngine engine;
                            engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
                        
                            return app.exec();
                        }
                        

                        main.qml

                        import QtQuick 2.12
                        import QtQuick.Window 2.12
                        
                        import backend 1.0
                        
                        Window {
                            visible: true
                            width: 640
                            height: 480
                        
                            BackEnd {id: backend}
                        
                            Text {text: qsTr("Value 1: " + backend.getValue1().value + " " + backend.getValue1().units)}
                            Text {y: 20;text: qsTr("Value 2: " + backend.getValue2().value + " " + backend.getValue2().units)}
                        }
                        
                        GrecKoG Offline
                        GrecKoG Offline
                        GrecKo
                        Qt Champions 2018
                        wrote on last edited by
                        #11

                        Q_INVOKABLE leads to worse QML code here.

                        Semantically, Value1 and Value2 are properties of your Backend.
                        Invokable function are for functions, stuff that mutates your state or compute something, that's not the case here.

                        If the Value1 and Value2 pointers never change, expose them as Q_PROPERTY in Backend.h:

                        Q_PROPERTY(Value* value1 READ getValue1 CONSTANT)
                        If for some reason you don't want to register the Value type, you don't have to use QVariant, you can expose it as a Q_PROPERTY(QObject*, ...

                        Keep your getters as is and just delete the Q_INVOKABLE part.

                        QML code would then be:

                        Text {text: qsTr("Value 1: " + backend.value1.value + " " + backend.value1.units)}
                        Text {y: 20;text: qsTr("Value 2: " + backend.value2.value + " " + backend.value2.units)}
                        

                        Which can be rewritten with a Column and a repeater:

                        Column {
                            Repeater {
                                model: [backend.value1, backend.value2]
                                delegate: Text {
                                    text: qsTr("Value %1: %2 %3 ").arg(index).arg(modelData.value).arg(modelData.units)
                                    padding: 8
                            }
                        }
                        

                        And then depending on the actual usecase you might consider exposing your values in a model instead of named properties for each Value1, Value2

                        _ 1 Reply Last reply
                        0
                        • GrecKoG GrecKo

                          Q_INVOKABLE leads to worse QML code here.

                          Semantically, Value1 and Value2 are properties of your Backend.
                          Invokable function are for functions, stuff that mutates your state or compute something, that's not the case here.

                          If the Value1 and Value2 pointers never change, expose them as Q_PROPERTY in Backend.h:

                          Q_PROPERTY(Value* value1 READ getValue1 CONSTANT)
                          If for some reason you don't want to register the Value type, you don't have to use QVariant, you can expose it as a Q_PROPERTY(QObject*, ...

                          Keep your getters as is and just delete the Q_INVOKABLE part.

                          QML code would then be:

                          Text {text: qsTr("Value 1: " + backend.value1.value + " " + backend.value1.units)}
                          Text {y: 20;text: qsTr("Value 2: " + backend.value2.value + " " + backend.value2.units)}
                          

                          Which can be rewritten with a Column and a repeater:

                          Column {
                              Repeater {
                                  model: [backend.value1, backend.value2]
                                  delegate: Text {
                                      text: qsTr("Value %1: %2 %3 ").arg(index).arg(modelData.value).arg(modelData.units)
                                      padding: 8
                              }
                          }
                          

                          And then depending on the actual usecase you might consider exposing your values in a model instead of named properties for each Value1, Value2

                          _ Offline
                          _ Offline
                          _-Peter-_
                          wrote on last edited by
                          #12

                          @GrecKo Thanks for that it does make sense.

                          You are correct that value1 & 2 pointers never change. In the actual use case there will be other unexposed backend methods that update Value's rawValue which is then scaled to real units for the QML layer to read. All of Value's exposed methods and properties will be only be read by the QML layer. There will be exposed backend methods that are written to by the QML layer and other values that will be exposed in a model, but this is straight forward as there's plenty of information out there on doing that.

                          Can you please confirm your recommended changes to the code I previously posted. My understanding of the changes is below but that throws a "cannot convert 'QVariant' to 'Value*' in assignment." during the build.

                          class BackEnd : public QObject
                          {
                              Q_OBJECT
                              Q_PROPERTY(Value* value1 READ getValue1 CONSTANT)
                              Q_PROPERTY(Value* value2 READ getValue2 CONSTANT)
                          public:
                              explicit BackEnd(QObject *parent = nullptr);
                          
                             QVariant getValue1(){return QVariant::fromValue(value1);}
                             QVariant getValue2(){return QVariant::fromValue(value2);}
                          

                          When I change the Q_PROPERTY lines to below everything works

                           Q_PROPERTY(QVariant value1 READ getValue1 CONSTANT)
                          

                          Thanks again for your assistance!

                          1 Reply Last reply
                          0

                          • Login

                          • Login or register to search.
                          • First post
                            Last post
                          0
                          • Categories
                          • Recent
                          • Tags
                          • Popular
                          • Users
                          • Groups
                          • Search
                          • Get Qt
                          • Unsolved