📜 ⬆️ ⬇️

C ++ objects and QML, all by shelves

On Habré and on the Web, there are a lot of articles on QML, but all of them leave some points behind the scenes. Today, I will try to raise the curtain over some obvious points for those who dealt with a bunch of QML and C ++, and not so obvious for those who are just beginning to delve into the nuances of this remarkable technology.
So. Suppose we have an application interface in QML and C ++ class with operation logic. How do we put all this together? Let's start with our C ++ class, the very first thing we need to do in order for it to be accessible from QML is to inherit it from QObject or from any other heir to this very QObject.

class TestClass : public QObject { Q_OBJECT public: explicit TestClass(QObject *parent = 0); signals: public slots: }; 

Now we will make some property accessible from QML, for this there is a macro Q_PROPERTY.
 class TestClass : public QObject { Q_OBJECT Q_PROPERTY(int someProperty READ getSomeProperty WRITE setSomeProperty NOTIFY somePropertyChanged) public: explicit TestClass(QObject *parent = 0); int getSomeProperty()const; void setSomeProperty(const int &); private: int someProperty; signals: void somePropertyChanged(); public slots: }; int TestClass::getSomeProperty()const { qDebug() << "I'm getter"; return someProperty; } void TestClass::setSomeProperty(const int &i) { qDebug() << "I'm setter"; someProperty = i; } 


Here, someProperty is actually our property itself, getSomeProperty is a method for reading, setSomeProperty is a method for writing. If we are going to change our property from C ++, we need to notify the interface in QML with the help of somePropertyChanged signal. Now we need to register our class in QML, for this we need to call the QmlApplicationViewer constructor, which is created by QtCreator automatically when creating a new QtQuick project, add a call to the template function qmlRegisterTypes.
')
 qmlRegisterType<TestClass>("ModuleName", 1, 0, "TypeName"); 


Here TestClass is our class, ModuleName is the name of the imported QML module, TypeName is the name of the object type in QML. Now in the QML file we import our class, and create an instance.
 import QtQuick 1.0 import ModuleName 1.0 Rectangle { width: 360 height: 360 TypeName{ id: myObj someProperty: 10 } Text { text: "My property is: " + myObj.someProperty anchors.centerIn: parent } MouseArea { anchors.fill: parent onClicked: { Qt.quit(); } } } 


In detail we are interested in the following points:
one)
 import ModuleName 1.0 
- so we say QML engine in which module we will look for our type.
2)
 TypeName{ id: myObj someProperty: 10 } 

Actually creating an object of our type and writing properties.
3)
 text: "My property is: " + myObj.someProperty 
- Reading our property.

Compile, run.
image

In order to be able to call methods from QML C ++, they must be defined as slots or using the Q_INVOKABLE macro.

 class TestClass : public QObject { Q_OBJECT Q_PROPERTY(int someProperty READ getSomeProperty WRITE setSomeProperty NOTIFY somePropertyChanged) public: explicit TestClass(QObject *parent = 0); int getSomeProperty()const; void setSomeProperty(const int &); Q_INVOKABLE void myMethod(); private: int someProperty; signals: void somePropertyChanged(); public slots: void mySlot(); }; void TestClass::myMethod() { qDebug() << "I am Method"; someProperty++; } void TestClass::mySlot() { qDebug() << "I am SLOT"; someProperty--; } 


Modify QML file.
 import QtQuick 1.0 import ModuleName 1.0 Rectangle { width: 360 height: 360 TypeName{ id: myObj someProperty: 10 } Text { text: "My property is: " + myObj.someProperty anchors.centerIn: parent } Rectangle{ width: 20 height: 20 color: "red" MouseArea { anchors.fill: parent onClicked: { myObj.mySlot(); } } } Rectangle{ anchors.right: parent.right width: 20 height: 20 color: "blue" MouseArea { anchors.fill: parent onClicked: { myObj.myMethod(); } } } } 


We compile, run, click on the squares and see from the debug output that everything works, only changes in our property do not affect the interface. But we had foreseen this and when declaring the property, we specified NOTIFY somePropertyChanged, we modify our method and slot so that if the property changes, somePropertyChanged signal is emitted.
 void TestClass::myMethod() { qDebug() << "I am Method"; someProperty++; emit somePropertyChanged(); } void TestClass::mySlot() { qDebug() << "I am SLOT"; someProperty--; emit somePropertyChanged(); } 


Compile, run and enjoy again - it responds.
And how can we be if we ourselves want to process the signal emitted by a C ++ object from QML code? It's simple. Add a signal to our class and generate it at the right moment.
 void TestClass::mySlot() { qDebug() << "I am SLOT"; someProperty--; emit somePropertyChanged(); if(someProperty < 0) emit someSignal(); } 


In order to catch this signal in QML, our object requires an onSomeSignal event handler, event names in QML are obtained by converting the first letter of the signal to uppercase and adding the prefix on.
 TypeName{ id: myObj someProperty: 10 onSomeSignal: { Qt.quit(); } } 


Here is the creation of an object with an event handler in a QML file.
That's all that I wanted to tell. Thanks for attention.

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


All Articles