📜 ⬆️ ⬇️

QML and C ++. A simple example of a bunch

image
QML technology is beautiful and pleasing to the eye. She was very interested in me, and I decided to master it. But it was not there, for I was stupid and helpless. Nowhere on the net did I find an example “for dummies” (I was probably looking bad) to build from scratch the simplest QML and C ++ applications in conjunction. Everywhere something was missing: either Qt Creator was not taken into account, or the code produced errors, or there were no points that users themselves had to know. Official documentation and examples here in Habré were also with these shortcomings. So I decided after long attempts and mistakes to write such an article for beginners with a detailed description.

Task . You need to write a QML program in conjunction with C ++, where
1. On the form there is a button, an input line, and an output field.
2. It is required to read a number from the input line, add 1, and the answer is displayed in the output field.
3. The interface is written in QML.
4. Functional in C ++, that is, we need to ensure the relationship between QML and C ++: the QML button calls the C ++ function, and the function changes the properties of QML objects.


Creating a basic QML application


We use Qt Creator. I used version 2.3 with Qt 4.7.4
image
Creating a QML Application

1. Create a GUI Application: File -> New File or Project .... There, on the left, select the Qt Widget Project , with the right Qt GUI application . Then click below the button " Select ... ".

')
2. In the next window, select the name of our project (without spaces and Russian letters). For example, in our case it is " Example ".


3. In the next window, you should have a tick near " Desktop ". If you do not have it, then you have installed Qt Creator incorrectly (or you do not intend to create desktop applications). That Qt Creator official build, which I installed (2.3), for some reason did not install the desktop parts by default.


4. In the next window, uncheck " Create form ".


5. In the next window, you can not change anything. And click the " Finish " button.


Editing the project file


6. Edit the project file (we have Example.pro here ):


And add to the line " QT + = core gui " the word " declarative ". As a result, we get the line:

QT += core gui declarative 


Creating a QML project

7. On the folder with the project in Qt Creator, right-click and go to the item " Add a new ... "


8. Select " QML " on the left and " QML file " on the right.


9. Call it " main ".


10. The next window is unchanged.


11. As a result, we get the file "main.qml" with the text:

 import QtQuick 1.0 Rectangle { width: 100 height: 62 } 


Create a resource file

12. On the folder with the project in Qt Creator, right-click and go to the item " Add a new ... "



13. Select " Qt " on the left and " Qt Resource File " on the right.


14. Call it res .


15. The next window is unchanged.


As a result, we get the file " res.qrc "

16. Add the prefix. To do this, click on the " Add " button, and then click " Add prefix ".


17. Change the prefix text to " / ".


18. Add our QML file. To do this, click on the " Add " button, and then click " Add files ".


19. And choose our file " main.qml ". And the file will be added to the resources of our application:


If we now run our application, we will not see qml yet:


Source Editing

Now let's do the qml connection to make it work.

20. We proceed to editing the file " mainwindow.h " (located in the header). It looks like:
 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QtGui/QMainWindow> class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); ~MainWindow(); }; #endif // MAINWINDOW_H 


Change it to this view:

 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtDeclarative/QDeclarativeView> #include <QGraphicsObject> #include <QtGui> #include <QDeclarativeContext> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: QDeclarativeView *ui; }; #endif // MAINWINDOW_H 


We added #include <QtDeclarative / QDeclarativeView> , #include <QGraphicsObject> and others, added a namespace , added the keyword explicit , and most importantly added QDeclarativeView * ui .

21. Now let's edit the mainwindow.cpp file. It looks like:

 #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { } MainWindow::~MainWindow() { } 


Change to this:

 #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { //  QML ui = new QDeclarativeView; ui->setSource(QUrl("qrc:/main.qml")); setCentralWidget(ui); ui->setResizeMode(QDeclarativeView::SizeRootObjectToView); } MainWindow::~MainWindow() { // QML delete ui; } 


22. Run our application and get a white window. Our QML is working.


Writing application


Now we can proceed to writing the application itself, which will solve our problem.

Build interface.

23. At the moment, main.qml looks like this:

 import QtQuick 1.0 Rectangle { width: 100 height: 62 } 




Edit it by changing the main window rectangle:

 import QtQuick 1.0 //  Rectangle { width: 300 height: 300 anchors.fill: parent } 


24. Add a simple button to our form.

  // Rectangle { id: button //  //   x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //  width: 100 height: 30 //  color: "gray" //  Text { id: buttonLabel text: "" anchors.centerIn: parent; } //  MouseArea { anchors.fill: parent id: mouseArea } } 


As a result, main.qml will look like this:

 import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent // Rectangle { id: button //  //   x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //  width: 100 height: 30 //  color: "gray" //  Text { id: buttonLabel text: "" anchors.centerIn: parent; } //  MouseArea { anchors.fill: parent id: mouseArea } } } 


If we run the application,

then we get the following:


25. Add an input line where the user will enter information with the name textinput .

 //  Rectangle { id: textinputRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //   width: 100 height: 18 //   color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } 


As a result, main.qml will look like this:

 import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent // Rectangle { id: button //  //   x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //  width: 100 height: 30 //  color: "gray" //  Text { id: buttonLabel text: "" anchors.centerIn: parent; } //  MouseArea { anchors.fill: parent id: mouseArea } } //  Rectangle { id: textinputRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //   width: 100 height: 18 //   color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } } 

Note the following:

At startup, we get the following:


26. Add an output field where the program will display the answer with the name memo .

  //  Rectangle { id: memoRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+70; //   width: 100 height: 35 //   color: "gray" TextEdit{ id: memo objectName: "memo" wrapMode: TextEdit.Wrap width:parent.width; readOnly:true } } 


As a result, main.qml will look like this:

 import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent // Rectangle { id: button //  //   x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //  width: 100 height: 30 //  color: "gray" //  Text { id: buttonLabel text: "" anchors.centerIn: parent; } //  MouseArea { anchors.fill: parent id: mouseArea } } //  Rectangle { id: textinputRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //   width: 100 height: 18 //   color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } //  Rectangle { id: memoRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+70; //   width: 100 height: 35 //   color: "gray" TextEdit{ id: memo objectName: "memo" wrapMode: TextEdit.Wrap width:parent.width; readOnly:true } } } 


At startup, we get the following:


So, we have described the interface of our program.

C ++ part

27. When you press a button, nothing happens. Fix it. First, let's establish the relationship between the QML model and C ++ code. To do this, edit the mainwindow.cpp file, namely the MainWindow function, adding the lines:

  //   Root = ui->rootObject(); // C++  QML,    ++   window ui->rootContext()->setContextProperty("window", this); 


We get the following:

 #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { //  QML ui = new QDeclarativeView; ui->setSource(QUrl("qrc:/main.qml")); setCentralWidget(ui); ui->setResizeMode(QDeclarativeView::SizeRootObjectToView); //   Root = ui->rootObject(); // C++  QML,    ++   window ui->rootContext()->setContextProperty("window", this); } MainWindow::~MainWindow() { // QML delete ui; } 


28. In the added code, we have an undeclared variable Root . Through it, we will then search for all other children. Let's declare it in mainwindow.h in the class in the private section:

 QObject *Root;//  QML  


As a result, we get:

 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtDeclarative/QDeclarativeView> #include <QGraphicsObject> #include <QtGui> #include <QDeclarativeContext> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: QDeclarativeView *ui; QObject *Root;//  QML  }; #endif // MAINWINDOW_H 


29. Let our QML button call the C ++ function under an arbitrary name FunctionC . Let's declare it in mainwindow.h in the class in the public section:

 Q_INVOKABLE void FunctionC();// C++   QML 


As a result, we get:

 #ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QtDeclarative/QDeclarativeView> #include <QGraphicsObject> #include <QtGui> #include <QDeclarativeContext> namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); Q_INVOKABLE void FunctionC();// C++   QML private: QDeclarativeView *ui; QObject *Root;//  QML  }; #endif // MAINWINDOW_H 


Notice the Q_INVOKABLE keyword. This is what makes the function for QML visible.

30. Now we describe our function in mainwindow.cpp :

 void MainWindow::FunctionC() { //   QObject* textinput = Root->findChild<QObject*>("textinput"); //   QObject* memo = Root->findChild<QObject*>("memo"); QString str;//    //       text str=(textinput->property("text")).toString(); int a; a=str.toInt();//    a++;//   1 QString str2;//     str2=QString::number(a);//    //         memo->setProperty("text", str+"+1="+str2); } 


31. Finally, add our function in the handler of our QML button in the main.qml file. The mouse action handler now looks like this:

 //  MouseArea { anchors.fill: parent id: mouseArea } 


Now it will become like this:

  //  MouseArea { anchors.fill: parent id: mouseArea //    window.FunctionC() onClicked: window.FunctionC() } 


As a result, we get:

 import QtQuick 1.0 Rectangle { width: 300 height: 300 anchors.fill: parent // Rectangle { id: button //  //   x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2; //  width: 100 height: 30 //  color: "gray" //  Text { id: buttonLabel text: "" anchors.centerIn: parent; } //  MouseArea { anchors.fill: parent id: mouseArea //    window.FunctionC() onClicked: window.FunctionC() } } //  Rectangle { id: textinputRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+40; //   width: 100 height: 18 //   color: "gray" TextInput { id: textinput objectName: "textinput" color: "#151515"; selectionColor: "blue" font.pixelSize: 12; width: parent.width-4 anchors.centerIn: parent focus: true text:"1" } } //  Rectangle { id: memoRect //   //  x: parent.width / 2 - button.width / 2; y: parent.height / 2 - button.height / 2+70; //   width: 100 height: 35 //   color: "gray" TextEdit{ id: memo objectName: "memo" wrapMode: TextEdit.Wrap width:parent.width; readOnly:true } } } 


Notice that we call the function through the window .

That's all! Now run the program and click on the button. If you did everything correctly and I made no mistakes, then you will see:

null

Link to source: Download .
Link to executable file: Download .

Source: https://habr.com/ru/post/138837/


All Articles