Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Calling function from object of object in QML results in TypeError
QtWS25 Last Chance

Calling function from object of object in QML results in TypeError

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
8 Posts 2 Posters 2.6k Views
  • 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.
  • P Offline
    P Offline
    prex
    wrote on last edited by
    #1

    I'm trying to connect a function of a C++ object of another C++ object to my QML UI. The first C++ object lives in a separate QThread. The structure is as follows:

    • main.qml
    • main.cpp
      • Base class, QThread
        • Hardware class

    Which means that the Hardware class is just an object created in the QThread Base.

    I would like to connect my QML UI to the functions of the Hardware class. So I set the context property:

    Base* base = new Base(argc, argv);
    engine.rootContext()->setContextProperty("base", base);
    

    I was not able to connect to the functions of the Hardware class, e.g.

    onClicked: base.hardware.resetSystem()
    

    fails with

    qrc:/SideBarForm.ui.qml:95: TypeError: Cannot call method 'resetSystem' of undefined
    

    But I can successfully call functions of the base class, e.g.

    onClicked: base.test()
    

    And calling the function from main.cpp works also fine:

    base->hardware->resetSystem();
    

    Furthermore, hardware is public in Base and resetSystem() is a public slot in Hardware:

    public:
      std::shared_ptr<Hardware> hardware;
    

    --

    public slots: 
      void resetSystem();
    

    What is the proper way of connecting signals and slots from "sub-objects" in QThreads to a QML interface?

    ODБOïO 1 Reply Last reply
    0
    • P prex

      I'm trying to connect a function of a C++ object of another C++ object to my QML UI. The first C++ object lives in a separate QThread. The structure is as follows:

      • main.qml
      • main.cpp
        • Base class, QThread
          • Hardware class

      Which means that the Hardware class is just an object created in the QThread Base.

      I would like to connect my QML UI to the functions of the Hardware class. So I set the context property:

      Base* base = new Base(argc, argv);
      engine.rootContext()->setContextProperty("base", base);
      

      I was not able to connect to the functions of the Hardware class, e.g.

      onClicked: base.hardware.resetSystem()
      

      fails with

      qrc:/SideBarForm.ui.qml:95: TypeError: Cannot call method 'resetSystem' of undefined
      

      But I can successfully call functions of the base class, e.g.

      onClicked: base.test()
      

      And calling the function from main.cpp works also fine:

      base->hardware->resetSystem();
      

      Furthermore, hardware is public in Base and resetSystem() is a public slot in Hardware:

      public:
        std::shared_ptr<Hardware> hardware;
      

      --

      public slots: 
        void resetSystem();
      

      What is the proper way of connecting signals and slots from "sub-objects" in QThreads to a QML interface?

      ODБOïO Offline
      ODБOïO Offline
      ODБOï
      wrote on last edited by ODБOï
      #2

      @prex one simple way is to add a Q_INVOKABLE method (or public slot) to Base

      Q_INVOKABLE void resetHardwareSys(){
       hardware->resetSystem();
      }
      

      or you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )

      P 1 Reply Last reply
      1
      • ODБOïO ODБOï

        @prex one simple way is to add a Q_INVOKABLE method (or public slot) to Base

        Q_INVOKABLE void resetHardwareSys(){
         hardware->resetSystem();
        }
        

        or you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )

        P Offline
        P Offline
        prex
        wrote on last edited by
        #3

        @LeLev Thanks, this works now. So the first solution means going over two public slots. I'm wondering about how to handle signals from C++ to QML then. First using QObject::connect() and then the Connections QML type? I have lots of data from the Hardware class which I need to visualize in the UI.

        I was reading many posts about signals & slots not working between QML and QThreads. I'm a little bit confused since it seems to work here...

        1 Reply Last reply
        0
        • P Offline
          P Offline
          prex
          wrote on last edited by
          #4

          I like the Q_PROPERTY approach in general but I don't understand what you mean by

          @LeLev said in Calling function from object of object in QML results in TypeError:

          you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )

          At the moment I have different Q_PROPERTIES defined in my Hardware class, but how can I make them accessible by QML? Or do you mean adding a Q_PROPERTY for the whole Hardware class?

          ODБOïO 1 Reply Last reply
          0
          • P prex

            I like the Q_PROPERTY approach in general but I don't understand what you mean by

            @LeLev said in Calling function from object of object in QML results in TypeError:

            you can expose your Hardware to QML adding a Q_PROPERTY for it and returning it as a QVariant (it is not enough to set it public to access it in QML )

            At the moment I have different Q_PROPERTIES defined in my Hardware class, but how can I make them accessible by QML? Or do you mean adding a Q_PROPERTY for the whole Hardware class?

            ODБOïO Offline
            ODБOïO Offline
            ODБOï
            wrote on last edited by ODБOï
            #5

            @prex said in Calling function from object of object in QML results in TypeError:

            you mean adding a Q_PROPERTY for the whole Hardware class?

            yes,
            for the getter method, don't return the hardware object directly, use QVariant::fromValue to return it as a QVariant

            P 1 Reply Last reply
            0
            • ODБOïO ODБOï

              @prex said in Calling function from object of object in QML results in TypeError:

              you mean adding a Q_PROPERTY for the whole Hardware class?

              yes,
              for the getter method, don't return the hardware object directly, use QVariant::fromValue to return it as a QVariant

              P Offline
              P Offline
              prex
              wrote on last edited by
              #6

              @LeLev I‘m not sure if I understand correctly. Should I do something like

              Q_PROPERTIES(Hardware hardware ...)
              

              in Base? But how to access this then? Can you please elaborate a little bit more on it?

              ODБOïO 1 Reply Last reply
              0
              • P prex

                @LeLev I‘m not sure if I understand correctly. Should I do something like

                Q_PROPERTIES(Hardware hardware ...)
                

                in Base? But how to access this then? Can you please elaborate a little bit more on it?

                ODБOïO Offline
                ODБOïO Offline
                ODБOï
                wrote on last edited by ODБOï
                #7

                @prex hi

                class Hardware : public QObject
                {
                    Q_OBJECT
                public:
                    explicit Hardware (QObject *parent = nullptr);
                public slots:
                
                    void write(const QString &str){
                        qDebug()<< str;
                    }
                };
                
                class Example : public QObject
                {
                    Q_OBJECT
                    Q_PROPERTY( Hardware * hardware READ hardware NOTIFY hardwareChanged)
                
                public:
                    explicit Example(QObject *parent = nullptr);
                
                    Hardware * hardware (){
                        return  m_hardware;
                    }
                signals:
                    void hardwareChanged();
                
                private:
                    Hardware *m_hardware;
                };
                
                 Example e;
                    engine.rootContext()->setContextProperty("obj",&e);
                
                import QtQuick 2.12
                import QtQuick.Window 2.12
                
                Window {
                    visible: true
                    width: 640
                    height: 480
                    title: qsTr("Hello World")
                
                    Component.onCompleted: obj.hardware.write("hello")
                
                }
                
                
                P 1 Reply Last reply
                1
                • ODБOïO ODБOï

                  @prex hi

                  class Hardware : public QObject
                  {
                      Q_OBJECT
                  public:
                      explicit Hardware (QObject *parent = nullptr);
                  public slots:
                  
                      void write(const QString &str){
                          qDebug()<< str;
                      }
                  };
                  
                  class Example : public QObject
                  {
                      Q_OBJECT
                      Q_PROPERTY( Hardware * hardware READ hardware NOTIFY hardwareChanged)
                  
                  public:
                      explicit Example(QObject *parent = nullptr);
                  
                      Hardware * hardware (){
                          return  m_hardware;
                      }
                  signals:
                      void hardwareChanged();
                  
                  private:
                      Hardware *m_hardware;
                  };
                  
                   Example e;
                      engine.rootContext()->setContextProperty("obj",&e);
                  
                  import QtQuick 2.12
                  import QtQuick.Window 2.12
                  
                  Window {
                      visible: true
                      width: 640
                      height: 480
                      title: qsTr("Hello World")
                  
                      Component.onCompleted: obj.hardware.write("hello")
                  
                  }
                  
                  
                  P Offline
                  P Offline
                  prex
                  wrote on last edited by
                  #8

                  @LeLev Thank you very much for the code sample!

                  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 Extensions
                  • Unsolved