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. Connecting C++ with QML

Connecting C++ with QML

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
25 Posts 9 Posters 457 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.
  • C Offline
    C Offline
    CassD
    wrote last edited by
    #16

    Qt is not all about QML for sure and C++ still has a huge importance in it, apps are not just about user interface, there's lots of core stuff behind that the author was probably not focusing about. Yeah just like toys like Jesper said. You still need a lots of C++ for communication, data handling and so on.

    The author of your book probably just wanted to focus on the QML language itself, I don't know the reasons about that, but I guess he just wanted to focus on UI creation only and forgetting all the core stuff and how to integrate core with QML ? Does he explain the reasons of the choice when he makes the statement ?
    I just guess this might a book just about UI creation, not that much intened for developpers.

    1 Reply Last reply
    0
    • G Offline
      G Offline
      Groundbounce
      wrote last edited by
      #17

      The book is just about QML: Qt6 QML for beginners by Daniel Gakwaya. Very good for QML yes, I recommend it. But someone has to explain how to do this, he came so close with QML functionality but said he would not touch on the C++ side of it.

      1 Reply Last reply
      0
      • Z Offline
        Z Offline
        zvoopz
        wrote last edited by
        #18

        The most simple way to use QML is treat it as user interface only. All calculations, validations and logic makes cpp. My QML is dumb: it sends input and receives output to show. I am migrating from Qt Widget to QML now and can share my experience.
        The most difficult part for me was to find an approach to provide communications between these two parts of app and register their binding. I have made a controller cpp class which manages requests and sends data from backend cpp classes and UI through Qt signal-slot mechanism. No Q_PROPERTY in my app just signals. Any communication between any calculator class and UI goes through controller. Controller owns calculators and makes all decisions.

        Controller.h
        class Controller : public QObject
        {
            Q_OBJECT
            QML_SINGLETON
            QML_ELEMENT
        public:
            explicit Controller(QObject *parent = nullptr);
        //next is a set of functions which are triggered by QML, Q_INVOKABLE is a keyword that connects
            Q_INVOKABLE void goToMainWindow();
            Q_INVOKABLE void loadWindow(const QString &qmlFileName, const QString &key);
            Q_INVOKABLE void window1TextFieldsParser();
            Q_INVOKABLE void window2TextFieldsParser();
            Q_INVOKABLE void window3TextFieldsParser();
            Q_INVOKABLE void profileEditTextFieldsParser();
            Q_INVOKABLE void on_loadProfileButton_clicked(const QString &nameOfProfile);
        //I extract and send only strings, cpp decides how to treat them
        
        signals: //To QML
            void window1Changed(QString summary);
            void showInfo(const QString &message, const QString &title, QObject* window);
            void showConfirmationDialog(const QString &message, const QString &title, QObject* window, const QString &requestId);
            void window2Changed(const QString summary);
            void clearListViewItems();
            void addItemsToListView (const QString &profileName);
            void updateLabel(const QString &summary);   
        

        How QML sends signal?

        Button{
                id: button      
                }
                //LOGIC
                onClicked: {
        	//QML emits signal to Controller  that switches window
                Controller.loadWindow("Window2.qml", "Window2")
                }
            }
        
        Button{
            id: loadProfileButton
            text: qsTr("Load")
             onClicked:{
         	//LOGIC
                if(profileListView.currentIndex!==-1){
        		//assign variable 
                       let selectedProfileName = model.get(profileListView.currentIndex).name
                       //and emit signal with value
                       Controller.on_loadProfilePushButton_clicked(selectedProfileName)
               }else{
        		//show error message
                        messenger.showInfo(qsTr("Select a profile"), qsTr("Error"))
               }
         }
        

        How QML receives signal?

        Connections {
              target: Controller
             function onClearListViewItems() {
             model.clear()
             }
        
                 function onAddItemsToListView(profileName) {
                 model.append({ name: profileName })
                 }
           }
        

        Easy but very verbose language

        1 Reply Last reply
        0
        • GrecKoG Offline
          GrecKoG Offline
          GrecKo
          Qt Champions 2018
          wrote last edited by
          #19

          Why even do it in c++ if all your data is stored in QML and you are not using properties or models in c++?

          Given the name of the invokables and slots it seems that the c++ is too coupled to the QML and it goes against what is usually recommended.

          1 Reply Last reply
          0
          • Z Offline
            Z Offline
            zvoopz
            wrote last edited by
            #20

            Because this is my first experience in QML and I never used JavaScript as well to write additional code in QML but I feel confident in c++.
            I have two dozens of TextField objects to accept user input in different ways with input validation. It might be string, integer or double that`s why I use the most simple approach for my current level of knowledge.

            I have a window with 7 TextFields and single Input button. How do I parse them?

            //QML
            Button{
                   id: inputWindow1Button
                   objectName: "inputWindow1Button"
                   text: qsTr("Input")
            	//LOGIC
                    onClicked: { //emits signal to run Controller::window1TextFieldsParser() which is declared as Q_INVOKABLE
                       Controller.window1TextFieldsParser()
                  }
            }
            

            .cpp

            void Controller::window1TextFieldsParser(){
              QQuickWindow* multiWindow = m_currentWindow; //currently active window where cpp looks for 
              objectName to parse
              QObject* speed = multiWindow->findChild<QObject*>("speed1of3"); //look for QML objectName
              QString speedText = speed->property("text").toString().trimmed(); //extract text from "speed1of3" TextField 
              QML object
              double speedCheck;
            
            if (speedText.isEmpty()){//check if QString is empty
              //Error signal to QML
              emit showInfo(tr("Speed field is empty"),
                          tr("Invalid input"), m_currentWindow);
              return;
            }else{
              //convert  QString to double, normalize input (treat both coma and dot as decimal separator)
              speedCheck = convertStringToDouble(speedText); 
            }
              //validate input range
            if(speedCheck<=0 || std::isnan(speedCheck)){
               //handle invalid input through emit showInfo()
              return;
            }else{
              m_speed=speedCheck; //assign member variable with valid value
            }
            }
            
            Ronel_qtmasterR 1 Reply Last reply
            0
            • Z zvoopz

              Because this is my first experience in QML and I never used JavaScript as well to write additional code in QML but I feel confident in c++.
              I have two dozens of TextField objects to accept user input in different ways with input validation. It might be string, integer or double that`s why I use the most simple approach for my current level of knowledge.

              I have a window with 7 TextFields and single Input button. How do I parse them?

              //QML
              Button{
                     id: inputWindow1Button
                     objectName: "inputWindow1Button"
                     text: qsTr("Input")
              	//LOGIC
                      onClicked: { //emits signal to run Controller::window1TextFieldsParser() which is declared as Q_INVOKABLE
                         Controller.window1TextFieldsParser()
                    }
              }
              

              .cpp

              void Controller::window1TextFieldsParser(){
                QQuickWindow* multiWindow = m_currentWindow; //currently active window where cpp looks for 
                objectName to parse
                QObject* speed = multiWindow->findChild<QObject*>("speed1of3"); //look for QML objectName
                QString speedText = speed->property("text").toString().trimmed(); //extract text from "speed1of3" TextField 
                QML object
                double speedCheck;
              
              if (speedText.isEmpty()){//check if QString is empty
                //Error signal to QML
                emit showInfo(tr("Speed field is empty"),
                            tr("Invalid input"), m_currentWindow);
                return;
              }else{
                //convert  QString to double, normalize input (treat both coma and dot as decimal separator)
                speedCheck = convertStringToDouble(speedText); 
              }
                //validate input range
              if(speedCheck<=0 || std::isnan(speedCheck)){
                 //handle invalid input through emit showInfo()
                return;
              }else{
                m_speed=speedCheck; //assign member variable with valid value
              }
              }
              
              Ronel_qtmasterR Offline
              Ronel_qtmasterR Offline
              Ronel_qtmaster
              wrote last edited by
              #21

              @zvoopz check these
              https://doc.qt.io/qt-5/qtqml-cppintegration-topic.html
              https://doc.qt.io/qt-6/qtqml-cppintegration-overview.html

              1 Reply Last reply
              0
              • Z Offline
                Z Offline
                zvoopz
                wrote last edited by
                #22

                Thanks to your recommendations I rejected the ugly practice to dig out input values from QML with findChild<QObject*>("objectName"); and implemented a Q_PROPERTY binding.

                I see a disappointing limitation, maybe you can give me an advise how to overcome it

                Consider the simple example with several TextFields, Input button and Start button

                QML
                Button{
                id: inputButton
                onClicked:{
                //extract values from TextFieldName.text
                AppController.setTextFieldValue([value1, value2,...])
                }
                
                Button{
                id: startButton
                onClicked:{
                AppController.startCalculations()
                }
                

                I have connected my QML and cpp as follows

                cpp
                Q_PROPERTY (QVariantList someValues READ someValues
                            WRITE setSomeValues NOTIFY someValuesChanged FINAL)
                
                As soon as user pushes Input button cpp receives and processes data because QML sends them through
                Q_INVOKABLE void setSomeValues() like this:
                
                void ControllerClass::setSomeValues(const QVariantList &someValues){
                	m_temperature = someValues[0];
                	//and so on ...
                	m_windSpeed = someValues[5];
                }
                

                Let`s image the situation that user has provided input but forgotten to push Input button
                Cpp has not received data yet but those values exist in QML TextFields

                void ControllerClass::startCalculation(){
                
                if(!temperature.hasValue()){ //std:optional<int>
                
                //Instead of request QML for current values
                requestQML(); //user has forgotten to push button to set temp
                
                //I need to emit error message
                emit showInfo("Error", "Invalid input");
                return;
                }
                

                So the limitation I see in this case that QML can send data to cpp, but cpp cannot request current values.
                How cpp can ask QML for missing data? How to handle such cases properly?

                1 Reply Last reply
                0
                • B Online
                  B Online
                  Bob64
                  wrote last edited by
                  #23

                  You could have a C++ object exposed as a QML object that exposes properties corresponding to each data field. You can then bind the QML fields directly to the C++ properties and the C++ is always up to date with what is in the QML.

                  1 Reply Last reply
                  0
                  • Z Offline
                    Z Offline
                    zvoopz
                    wrote last edited by
                    #24

                    Do you mean no Input button and expose every TextField as separate Q_PROPERTY through onEditingFinished:?

                    1 Reply Last reply
                    0
                    • GrecKoG Offline
                      GrecKoG Offline
                      GrecKo
                      Qt Champions 2018
                      wrote last edited by
                      #25

                      That depends on what you specify for your UX. If you don't want to have to use a submit button then mapping each textfield to a c++ property is the more direct way yes. Doing that on editingFinished is a good solution.

                      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