Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. C++ PROPERTY changed() to QML
QtWS25 Last Chance

C++ PROPERTY changed() to QML

Scheduled Pinned Locked Moved Solved General and Desktop
propertyc++qmlc++ to qmlchange
5 Posts 3 Posters 2.4k 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.
  • T Offline
    T Offline
    TMJJ001
    wrote on last edited by TMJJ001
    #1

    Hi all,

    I lost my way in C++ PROPERTY to connect to QML.
    What I did already.

    1. Created main.cpp. main.cpp calls backend_qml.
    2. Backend_qml calls HWButton.
    3. In the backend_qml there is a Q_PROPERTY which shares a page number to QML.
    4. If a Hardware button is pushed, the button changes the page number and the page needs to change in QML.
    5. (need to add this: send some more variables to the QML)
    #include <backend_qml.h>
    #include <system_control.h>
    
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QtQml>
    #include <QQmlContext>
    #include <QQmlEngine>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        backend_qml bqml;
        system_control cc_system;
    
        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("backend_qml", &bqml);
    
        //qmlRegisterType<backend_qml>("PropertyBinding", 1, 0, "PropertyBinding");
    
    
        engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    
    
        if (engine.rootObjects().isEmpty())
            return -1;
    
        return app.exec();
    }
    

    When I run:

        QQmlApplicationEngine engine;
        engine.rootContext()->setContextProperty("backend_qml", &bqml);
    

    I can change the page number, but I'm not able to get the signal in QML when the PROPERTY has CHANGED.

    When I run:

      qmlRegisterType<backend_qml>("PropertyBinding", 1, 0, "PropertyBinding");
    

    The application runs, but no data is transfered to QML. I think this is normal as I didn't make a instance of backend_qml.

    Below the backend_qml.h and backend_qml.cpp

    #ifndef BACKEND_QML_H
    #define BACKEND_QML_H
    
    #include <QObject>
    #include <QScopedPointer>
    #include <QDebug>
    #include "hwbutton.h"
    
    class backend_qml : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
    
    public:
        explicit backend_qml(QObject *parent = nullptr);
        int page() const {qDebug() << QString::number(m_page); return m_page;}
    
    signals:
        void pageChanged();
    
    
    public slots:
        void setPage(int page);
    
    private:
            int m_page;
            HWButton hwbutton;
    };
    
    #endif // BACKEND_QML_H
    
    
    #include "backend_qml.h"
    
    backend_qml::backend_qml(QObject *parent) : QObject(parent)
    {
        qDebug()<< "app is running";
    
        connect(&hwbutton,SIGNAL(buttonPushed(int)),this,SLOT(setPage(int)));
    
    }
    
    void backend_qml::setPage(int page)
    {
        qDebug() << "page changer called" ;
        m_page = page;
        emit pageChanged(); // trigger signal if page is changed
    }
    

    So the main goal is when setPage() is called, a function in qml is called together with the new pagenumber.

    I hope somebody is able to point me in the correct direct. I got really confussed.

    Thanks in advance,
    Kind regards,
    TMJJ

    ************** EDIT **************

    QML

    I have multiple qml files.

    In the main, I just have some global variables. here I also run my Main_Screen{}

    import QtQuick 2.6
    import QtQuick.Window 2.2
    
    
    Window {
        visible: true
        width: 800
        height: 480
        title: qsTr("Hello World")
        
        property string workspace_background_color   : "#FFFFFF"
        property string errorheader_background_color : "#FFFFFF"
        
        Main_screen{
        }
    }
    
    

    In the main_screenForm.ui.qml I have the following:

    import QtQuick 2.4
    import QtQuick.Layouts 1.3
    import QtQuick.Controls 1.4
    import "MaterialDesignIconGlyphs.js" as MaterialGlyphs
    
    Item {
        width: 800
        height: 480
    
        property alias workspace: workspace
    
        property alias pushbutton1: pushbutton1
        property alias pushbutton2: pushbutton2
        property alias pushbutton3: pushbutton3
        property alias pushbutton4: pushbutton4
        property alias pushbutton5: pushbutton5
    
        property alias mouse: mouse
    
        property alias button2_pushed: button2_pushed
        property alias button3_pushed: button3_pushed
        property alias button4_pushed: button4_pushed
        property alias button5_pushed: button5_pushed
    
        property alias workspace_stacked_view: workspace_stacked_view
    
        property string leftbar_pushed_button_indicator_color: "#FF6110"
    
        GridLayout {
            id: maingrid
            columnSpacing: 0
            rowSpacing: 0
            anchors.fill: parent
            anchors.margins: 0
    
            columns: 2
            rows: 2
    
            Rectangle {
                id: companyheader
    
                Layout.preferredHeight: 80
                Layout.preferredWidth: 100
                Layout.margins: 0
    
                color: "#014088"
    
                Image {
                    id: companylogo
                    anchors.fill: parent
                    fillMode: Image.PreserveAspectFit
                    source: "qrc:/resource/img/Company/Logo.png"
                }
    
                MouseArea {
                    id: pushbutton1
                    anchors.fill: parent
                }
            }
    
            Rectangle {
                id: errorheader
    
                Layout.preferredHeight: 80
                Layout.fillWidth: true
    
                color: "#FF6110"
    
                Text {
                    id: tetlol
                    x: 23
                    y: 19
                    width: 112
                    height: 42
                    text: backend_qml.page
                    font.pixelSize: 12
                }
            }
    ...
    
      StackView {
                    id: workspace_stacked_view
                    initialItem: homepage
                    anchors.fill: parent
                }
    ...
    

    Like this I'm able to print the page number inside my header. So this works fine.
    Now I also have a stackview. Here I want to change the page when a hardware button is pushed.
    So As explained above, I tried to use:

    qmlRegisterType<backend_qml>("PropertyBinding", 1, 0, "PropertyBinding");
    

    Then in my Main_screen.qml I did like this:

    import QtQuick 2.4
    import QtQml 2.2
    import PropertyBinding 1.0
    
    
    import "qrc:/pages/"                // import qml file from different resource folder
    
    Main_screenForm {
    
        button2_pushed.visible:true
        button3_pushed.visible:false
        button4_pushed.visible:false
        button5_pushed.visible:false
    
        mouse {
            onClicked: console.info("pushed mouse")
        }
    
        function pagechanger(n)
        {
            switch(n){
                case 1: button2_pushed.visible=true
                        button3_pushed.visible=false
                        button4_pushed.visible=false
                        button5_pushed.visible=false
                        workspace_stacked_view.push(homepage);break;
                case 2: button2_pushed.visible=false
                        button3_pushed.visible=true
                        button4_pushed.visible=false
                        button5_pushed.visible=false
                        workspace_stacked_view.push(settingpage);break;
                case 3: button2_pushed.visible=false
                        button3_pushed.visible=false
                        button4_pushed.visible=true
                        button5_pushed.visible=false
                        workspace_stacked_view.push(diagnosepage);break;
                case 4: button2_pushed.visible=false
                        button3_pushed.visible=false
                        button4_pushed.visible=false
                        button5_pushed.visible=true;break;
            }
        }
    
        pushbutton2{
            onClicked: {
                console.info("touch pushbutton2 clicked");
                pagechanger(1);
            }
        }
        pushbutton3{
            onClicked: {
                console.info("touch pushbutton3 clicked");
                pagechanger(2);
            }
        }
        pushbutton4{
            onClicked: {
                console.info("touch pushbutton4 clicked");
                pagechanger(3);
            }
        }
        pushbutton5{
            onClicked: {
                console.info("touch pushbutton5 clicked");
                pagechanger(4);
            }
        }
    
    
    
        Component{
            id:homepage
            HomePage{
            //anchors.fill:parent
            }
    
        }
    
        Component{
            id:settingpage
            SettingPage{
            //anchors.fill:parent
            }
        }
    
    
         Component{
            id:diagnosepage
            DiagnosePage{
            //anchors.fill:parent
          }
    
        }
         
        
         // HERE IN NEED TO CALL FUNCTION pagechanger!
         
    }
    
    /*##^## Designer {
        D{i:0;autoSize:true;height:480;width:640}
    }
     ##^##*/
    
    

    I hope it is still clear what I try to reach.

    Kind regards

    KroMignonK 1 Reply Last reply
    0
    • fcarneyF Offline
      fcarneyF Offline
      fcarney
      wrote on last edited by
      #2

      Show us what you are doing in QML.

      C++ is a perfectly valid school of magic.

      T 1 Reply Last reply
      0
      • fcarneyF fcarney

        Show us what you are doing in QML.

        T Offline
        T Offline
        TMJJ001
        wrote on last edited by
        #3

        @fcarney

        Thanks for the quick response.
        Please see the edited version.

        Thanks,
        TMJJ

        1 Reply Last reply
        0
        • T TMJJ001

          Hi all,

          I lost my way in C++ PROPERTY to connect to QML.
          What I did already.

          1. Created main.cpp. main.cpp calls backend_qml.
          2. Backend_qml calls HWButton.
          3. In the backend_qml there is a Q_PROPERTY which shares a page number to QML.
          4. If a Hardware button is pushed, the button changes the page number and the page needs to change in QML.
          5. (need to add this: send some more variables to the QML)
          #include <backend_qml.h>
          #include <system_control.h>
          
          #include <QGuiApplication>
          #include <QQmlApplicationEngine>
          #include <QtQml>
          #include <QQmlContext>
          #include <QQmlEngine>
          
          int main(int argc, char *argv[])
          {
              QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
              QGuiApplication app(argc, argv);
          
              backend_qml bqml;
              system_control cc_system;
          
              QQmlApplicationEngine engine;
              engine.rootContext()->setContextProperty("backend_qml", &bqml);
          
              //qmlRegisterType<backend_qml>("PropertyBinding", 1, 0, "PropertyBinding");
          
          
              engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
          
          
              if (engine.rootObjects().isEmpty())
                  return -1;
          
              return app.exec();
          }
          

          When I run:

              QQmlApplicationEngine engine;
              engine.rootContext()->setContextProperty("backend_qml", &bqml);
          

          I can change the page number, but I'm not able to get the signal in QML when the PROPERTY has CHANGED.

          When I run:

            qmlRegisterType<backend_qml>("PropertyBinding", 1, 0, "PropertyBinding");
          

          The application runs, but no data is transfered to QML. I think this is normal as I didn't make a instance of backend_qml.

          Below the backend_qml.h and backend_qml.cpp

          #ifndef BACKEND_QML_H
          #define BACKEND_QML_H
          
          #include <QObject>
          #include <QScopedPointer>
          #include <QDebug>
          #include "hwbutton.h"
          
          class backend_qml : public QObject
          {
              Q_OBJECT
              Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
          
          public:
              explicit backend_qml(QObject *parent = nullptr);
              int page() const {qDebug() << QString::number(m_page); return m_page;}
          
          signals:
              void pageChanged();
          
          
          public slots:
              void setPage(int page);
          
          private:
                  int m_page;
                  HWButton hwbutton;
          };
          
          #endif // BACKEND_QML_H
          
          
          #include "backend_qml.h"
          
          backend_qml::backend_qml(QObject *parent) : QObject(parent)
          {
              qDebug()<< "app is running";
          
              connect(&hwbutton,SIGNAL(buttonPushed(int)),this,SLOT(setPage(int)));
          
          }
          
          void backend_qml::setPage(int page)
          {
              qDebug() << "page changer called" ;
              m_page = page;
              emit pageChanged(); // trigger signal if page is changed
          }
          

          So the main goal is when setPage() is called, a function in qml is called together with the new pagenumber.

          I hope somebody is able to point me in the correct direct. I got really confussed.

          Thanks in advance,
          Kind regards,
          TMJJ

          ************** EDIT **************

          QML

          I have multiple qml files.

          In the main, I just have some global variables. here I also run my Main_Screen{}

          import QtQuick 2.6
          import QtQuick.Window 2.2
          
          
          Window {
              visible: true
              width: 800
              height: 480
              title: qsTr("Hello World")
              
              property string workspace_background_color   : "#FFFFFF"
              property string errorheader_background_color : "#FFFFFF"
              
              Main_screen{
              }
          }
          
          

          In the main_screenForm.ui.qml I have the following:

          import QtQuick 2.4
          import QtQuick.Layouts 1.3
          import QtQuick.Controls 1.4
          import "MaterialDesignIconGlyphs.js" as MaterialGlyphs
          
          Item {
              width: 800
              height: 480
          
              property alias workspace: workspace
          
              property alias pushbutton1: pushbutton1
              property alias pushbutton2: pushbutton2
              property alias pushbutton3: pushbutton3
              property alias pushbutton4: pushbutton4
              property alias pushbutton5: pushbutton5
          
              property alias mouse: mouse
          
              property alias button2_pushed: button2_pushed
              property alias button3_pushed: button3_pushed
              property alias button4_pushed: button4_pushed
              property alias button5_pushed: button5_pushed
          
              property alias workspace_stacked_view: workspace_stacked_view
          
              property string leftbar_pushed_button_indicator_color: "#FF6110"
          
              GridLayout {
                  id: maingrid
                  columnSpacing: 0
                  rowSpacing: 0
                  anchors.fill: parent
                  anchors.margins: 0
          
                  columns: 2
                  rows: 2
          
                  Rectangle {
                      id: companyheader
          
                      Layout.preferredHeight: 80
                      Layout.preferredWidth: 100
                      Layout.margins: 0
          
                      color: "#014088"
          
                      Image {
                          id: companylogo
                          anchors.fill: parent
                          fillMode: Image.PreserveAspectFit
                          source: "qrc:/resource/img/Company/Logo.png"
                      }
          
                      MouseArea {
                          id: pushbutton1
                          anchors.fill: parent
                      }
                  }
          
                  Rectangle {
                      id: errorheader
          
                      Layout.preferredHeight: 80
                      Layout.fillWidth: true
          
                      color: "#FF6110"
          
                      Text {
                          id: tetlol
                          x: 23
                          y: 19
                          width: 112
                          height: 42
                          text: backend_qml.page
                          font.pixelSize: 12
                      }
                  }
          ...
          
            StackView {
                          id: workspace_stacked_view
                          initialItem: homepage
                          anchors.fill: parent
                      }
          ...
          

          Like this I'm able to print the page number inside my header. So this works fine.
          Now I also have a stackview. Here I want to change the page when a hardware button is pushed.
          So As explained above, I tried to use:

          qmlRegisterType<backend_qml>("PropertyBinding", 1, 0, "PropertyBinding");
          

          Then in my Main_screen.qml I did like this:

          import QtQuick 2.4
          import QtQml 2.2
          import PropertyBinding 1.0
          
          
          import "qrc:/pages/"                // import qml file from different resource folder
          
          Main_screenForm {
          
              button2_pushed.visible:true
              button3_pushed.visible:false
              button4_pushed.visible:false
              button5_pushed.visible:false
          
              mouse {
                  onClicked: console.info("pushed mouse")
              }
          
              function pagechanger(n)
              {
                  switch(n){
                      case 1: button2_pushed.visible=true
                              button3_pushed.visible=false
                              button4_pushed.visible=false
                              button5_pushed.visible=false
                              workspace_stacked_view.push(homepage);break;
                      case 2: button2_pushed.visible=false
                              button3_pushed.visible=true
                              button4_pushed.visible=false
                              button5_pushed.visible=false
                              workspace_stacked_view.push(settingpage);break;
                      case 3: button2_pushed.visible=false
                              button3_pushed.visible=false
                              button4_pushed.visible=true
                              button5_pushed.visible=false
                              workspace_stacked_view.push(diagnosepage);break;
                      case 4: button2_pushed.visible=false
                              button3_pushed.visible=false
                              button4_pushed.visible=false
                              button5_pushed.visible=true;break;
                  }
              }
          
              pushbutton2{
                  onClicked: {
                      console.info("touch pushbutton2 clicked");
                      pagechanger(1);
                  }
              }
              pushbutton3{
                  onClicked: {
                      console.info("touch pushbutton3 clicked");
                      pagechanger(2);
                  }
              }
              pushbutton4{
                  onClicked: {
                      console.info("touch pushbutton4 clicked");
                      pagechanger(3);
                  }
              }
              pushbutton5{
                  onClicked: {
                      console.info("touch pushbutton5 clicked");
                      pagechanger(4);
                  }
              }
          
          
          
              Component{
                  id:homepage
                  HomePage{
                  //anchors.fill:parent
                  }
          
              }
          
              Component{
                  id:settingpage
                  SettingPage{
                  //anchors.fill:parent
                  }
              }
          
          
               Component{
                  id:diagnosepage
                  DiagnosePage{
                  //anchors.fill:parent
                }
          
              }
               
              
               // HERE IN NEED TO CALL FUNCTION pagechanger!
               
          }
          
          /*##^## Designer {
              D{i:0;autoSize:true;height:480;width:640}
          }
           ##^##*/
          
          

          I hope it is still clear what I try to reach.

          Kind regards

          KroMignonK Offline
          KroMignonK Offline
          KroMignon
          wrote on last edited by
          #4

          @TMJJ001 I think you are doing too complicate and not in the cleanest way. Here some hints:

          • C++ class names should be UpperCamelCase, to respect common Qt/QML coding rules
          • Instance names should be lowerCamelCase, again to respect common Qt/QML coding rules
          • try to think simple, if you fight against the framework, then you are doing something in the wrong way
          • I would also strongly recommend you to read the Qt documentation: Integrating QML and C++

          So, now how I would do it.
          The backend class:

          #ifndef BACKENDQML_H
          #define BACKENDQML_H
          
          #include <QObject>
          
          class BackendQml : public QObject
          {
              Q_OBJECT
              Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
          
          public:
              explicit BackendQml(QObject *parent = nullptr): QObject(parent), m_page(0) {}
              int page() const { return m_page; }
          
          signals:
              void pageChanged(int page);
          
          
          public slots:
              void setPage(int page)
              {
                  if(m_page != page)
                  {
                       m_page = page;
                       emit pageChanged(page);
                  }
              }
          
          private:
                  int m_page;
          };
          
          #endif // BACKENDQML_H
          

          Expose the global variable to QML Engine:

              QQmlApplicationEngine engine;
              engine.rootContext()->setContextProperty("backendQml", &bqml);
          

          Then in QML (Main_Screen):

          import QtQuick 2.6
          import QtQuick.Window 2.2
          
          
          Window {
              visible: true
              width: 800
              height: 480
              title: qsTr("Hello World")
              
              property string workspace_background_color   : "#FFFFFF"
              property string errorheader_background_color : "#FFFFFF"
              readonly property int currentPage: backendQml.page 
          
              onCurrentPageChanged {
                  console.log("Current page is " + currentPage)
             }
             .. 
          }
          

          And when changing page, simply change you pagechanger() function to add backendQml.page=n, like this:

              function pagechanger(n)
              {
                  backendQml.page=n
                  switch(n){
                  ...
                  }
              }
          

          It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

          T 1 Reply Last reply
          3
          • KroMignonK KroMignon

            @TMJJ001 I think you are doing too complicate and not in the cleanest way. Here some hints:

            • C++ class names should be UpperCamelCase, to respect common Qt/QML coding rules
            • Instance names should be lowerCamelCase, again to respect common Qt/QML coding rules
            • try to think simple, if you fight against the framework, then you are doing something in the wrong way
            • I would also strongly recommend you to read the Qt documentation: Integrating QML and C++

            So, now how I would do it.
            The backend class:

            #ifndef BACKENDQML_H
            #define BACKENDQML_H
            
            #include <QObject>
            
            class BackendQml : public QObject
            {
                Q_OBJECT
                Q_PROPERTY(int page READ page WRITE setPage NOTIFY pageChanged)
            
            public:
                explicit BackendQml(QObject *parent = nullptr): QObject(parent), m_page(0) {}
                int page() const { return m_page; }
            
            signals:
                void pageChanged(int page);
            
            
            public slots:
                void setPage(int page)
                {
                    if(m_page != page)
                    {
                         m_page = page;
                         emit pageChanged(page);
                    }
                }
            
            private:
                    int m_page;
            };
            
            #endif // BACKENDQML_H
            

            Expose the global variable to QML Engine:

                QQmlApplicationEngine engine;
                engine.rootContext()->setContextProperty("backendQml", &bqml);
            

            Then in QML (Main_Screen):

            import QtQuick 2.6
            import QtQuick.Window 2.2
            
            
            Window {
                visible: true
                width: 800
                height: 480
                title: qsTr("Hello World")
                
                property string workspace_background_color   : "#FFFFFF"
                property string errorheader_background_color : "#FFFFFF"
                readonly property int currentPage: backendQml.page 
            
                onCurrentPageChanged {
                    console.log("Current page is " + currentPage)
               }
               .. 
            }
            

            And when changing page, simply change you pagechanger() function to add backendQml.page=n, like this:

                function pagechanger(n)
                {
                    backendQml.page=n
                    switch(n){
                    ...
                    }
                }
            
            T Offline
            T Offline
            TMJJ001
            wrote on last edited by
            #5

            @KroMignon

            Thanks for the extensive explanation!
            Now I understand what I was doing wrong.

            Kind regards

            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