QML and C ++. We drive data, evaluate the speed of interaction

About how to send data from QML to C ++ and after manipulating them to return them (data) back, has already been repeatedly told . Most articles provide the same examples or, at best, slightly modified by the authors of the articles.

Let's look at a couple of the most explicit ways to pass data from QML to C ++ and vice versa. We also evaluate their effectiveness.

Well, let's start


We take the simplest thing that may come to mind: there is a window with text, when you click on the text, we need to do some manipulations with this text using c ++ and then show the final version in the same window.

The first version of the implementation of such a difficult task: from QML, we call the slot described in the C ++ class and pass it our text. After changing the text, we call the signal and together with this signal we transmit the changed text to QML.

File main.cpp | We create an instance of the class in which our signal and slot are described, declare a context property (as if we pass a link to our class in qml)
#include 
#include "qmlapplicationviewer.h"
#include 
#include "asd.h"
Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer app(createApplication(argc, argv));
    QmlApplicationViewer viewer;
    asd ASD;
    viewer.rootContext()->setContextProperty("ASD", &ASD);
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
    viewer.setMainQmlFile(QLatin1String("qml/habr1/main.qml"));
    viewer.showExpanded();
    return app->exec();
}


The asd.h file (the heading of our class with a signal and slot)
#ifndef ASD_H
#define ASD_H
#include 
class asd : public QObject
{
    Q_OBJECT
public:
    explicit asd(QObject *parent = 0);
signals:
    void transmitNewText(QString text);
public slots:
    void getOldText(QString text);
};
#endif // ASD_H


File asd.cpp (describe our slot) | As you can see from the code, the slot receives text, adds a word to it, and then calls a signal
#include "asd.h"
asd::asd(QObject *parent) :
    QObject(parent)
{
}
void asd::getOldText(QString text){
    emit transmitNewText(text + " Hello!");
}


Well, main.qml (our window with text) | By pressing the mouse button (onClicked) we call the slot and wait for the signal (onTransmitNewText) upon receipt of which we change the message text in our window
import QtQuick 1.1
Rectangle {
    width: 360
    height: 360
    Connections {
        target: ASD
        onTransmitNewText: text1.text = text
    }
    Text {
        id: text1
        text: qsTr("Hello World.")
        anchors.centerIn: parent
    }
    MouseArea {
        anchors.fill: parent
        onClicked: ASD.getOldText(text1.text)
    }
}


This ends the boring part. Let's turn it on and see how long it takes to call the slot and send our modified text with a signal.



For the purity of the experiment, click on the text 20 times:


We see two lines called “Signals”. We open the timeline, make sure that to estimate the speed of the whole process, we need only the top line from our picture, because it lasts from the very beginning of the call of the slot until the signal is completed:


Second implementation: when you click on the text, we generate a signal, connect this signal to the slots of a class we already know, and then, in the same way, after changing the text, we call the same signal and We respond to it with the slot described in QML.

At first glance, it may seem that this will require more time than in the first embodiment.

We change our main.cpp (everything is simple and clear here, we connect slots and signals)
#include 
#include "qmlapplicationviewer.h"
#include 
#include "asd.h"
Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer app(createApplication(argc, argv));
    QmlApplicationViewer viewer;
    viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
    viewer.setMainQmlFile(QLatin1String("qml/habr2/main.qml"));
    asd ASD;
    QObject *qml = viewer.rootObject();
    QObject::connect(qml, SIGNAL(transmitOldText(QString)),
                     &ASD, SLOT(getOldText(QString)));
    QObject::connect(&ASD, SIGNAL(transmitNewText(QVariant)),
                     qml, SLOT(getNewText(QVariant)));
    viewer.showExpanded();
    return app->exec();
}


asd.h (slightly change the title of our class) | because in qml defining a function, you cannot explicitly specify the data type, you have to replace QString with QVariant
#ifndef ASD_H
#define ASD_H
#include 
#include 
class asd : public QObject
{
    Q_OBJECT
public:
    explicit asd(QObject *parent = 0);
signals:
    void transmitNewText(QVariant text);
public slots:
    void getOldText(QString text);
};
#endif // ASD_H


asd.cpp (added the same QVariant )
#include "asd.h"
asd::asd(QObject *parent) :
    QObject(parent)
{
}
void asd::getOldText(QString text){
    emit transmitNewText(QVariant(text + " Hello!"));
}


Well, our new main.qml window
import QtQuick 1.1
Rectangle {
    id: rth
    width: 360
    height: 360
    function getNewText(text){
        text1.text = text
    }
    signal transmitOldText(string text)
    Text {
        id: text1
        text: qsTr("Hello World.")
        anchors.centerIn: parent
    }
    MouseArea {
        anchors.fill: parent
        onClicked: transmitOldText(text1.text)
    }
}


Let's check how much time we need this time:


At the request of readers, we add to our testing a function that returns a value


So, main.cpp remains exactly as it was in the first version. We all also declare a context property (reference to an instance of our class)
asd ASD;
viewer.rootContext()->setContextProperty("ASD", &ASD);


Slightly modify our C ++ slot (now it returns a value)
QString asd::getOldTextTransmitNewText(QString text){
    return text + " Hello!";
}


After which we slightly change main.qml
MouseArea {
        anchors.fill: parent
        onClicked: text1.text = ASD.getOldTextTransmitNewText(text1.text)
    }


Turn on, look at the elapsed time:


The same option, only with Q_INVOKABLE
Q_INVOKABLE
    QString getOldTextTransmitNewText(QString text);


It turns out quite a bit slower than the slot:


To summarize (recall that the milliseconds given are the sum for 20 calls)


The first method turned out to be the longest (calling a slot from qml with subsequent signal catching): 14.885 ms .
The second option is faster (where we connected the slots and signals): 13.993 ms .
The fastest option is to call a function that returns a value: 13.456 ms . for the slot and 13.508 ms . for Q_INVOKABLE (within the margin of error).

Yes, the thing, of course, is not very noticeable, but no one expected the differences of 20 milliseconds to be different. You can refer to the error, but with the repeated repetition of this, so to speak, experiment, the result turned out to be approximately equal to that given in this article.

Why and for whomwas all this done? For some reason, it was precisely this thought that occurred to me, for I had never dealt with such “nonsense”. Well, after I decided to share the results with you.

Also popular now: