QML и C++. Гоняем данные, оцениваем скорость взаимодействия

в 10:21, , рубрики: c++, QML, qt, Qt Software, QtQuick, Программирование, метки: , , ,

О том как отправлять данные из QML в C++ и после манипуляций с ними возвращать их (данные) обратно, было уже неоднократно рассказано. В большинстве статей приводятся одни и те же примеры или, в лучшем случае, слегка измененные авторами статей.

Давайте рассмотрим пару самых явных способов передавать данные из QML в C++ и обратно. Также оценим их эффективность.

Ну, пожалуй, начнем

Берем самое простое, что может прийти в голову: есть окно с текстом, при нажатии на текст, нам нужно сделать какие-нибудь манипуляции с этим текстом средствами c++ и после показать конечный вариант в этом же окне.

Первый вариант реализации столь сложной задачи: из QML вызываем слот, описанный в C++ классе и передаем ему наш текст. После изменения текста вызываем сигнал и вместе с этим сигналом передаем измененный текст в QML.

Файл main.cpp | Создаем экземпляр класса, в котором описаны наш сигнал и слот, декларируем контекстное свойство (как бы передаем ссылку на наш класс в qml)

#include <QApplication>
#include "qmlapplicationviewer.h"
#include <QDeclarativeContext>
#include "asd.h"

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer<QApplication> 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();
}

Файл asd.h (заголовок нашего класса с сигналом и слотом)

#ifndef ASD_H
#define ASD_H

#include <QObject>

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

Файл asd.cpp (описываем наш слот) | Как видно из кода, слот принимает текст, добавляет к нему слово и после вызывает сигнал

#include "asd.h"

asd::asd(QObject *parent) :
    QObject(parent)
{
}

void asd::getOldText(QString text){
    emit transmitNewText(text + " Hello!");
}

Ну и main.qml (наше окно с текстом) | По нажатию кнопки мыши (onClicked) вызываем слот и ждем сигнал (onTransmitNewText) при получении которого меняем текст сообщения в нашем окне

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)
    }
}

На этом скучная часть заканчивается. Давайте это включим и посмотрим, сколько времени требуется на вызов слота и отправку нашего измененного текста с сигналом.

QML и C++. Гоняем данные, оцениваем скорость взаимодействия

Для чистоты эксперимента кликнем на тексте 20 раз:
QML и C++. Гоняем данные, оцениваем скорость взаимодействия

Видим две строки, называющиеся «Сигналы». Открываем временную шкалу, убеждаемся, что для оценки скорости всего процесса нам нужна только верхняя строка с нашей картинки т.к. именно она длится с самого начала вызова слота до момента завершения отправки сигнала:
QML и C++. Гоняем данные, оцениваем скорость взаимодействия

Второй вариант реализации: при нажатии на текст генерируем сигнал, соединяем этот сигнал со слотам уже знакомого нам класса, после чего все тем же путем после изменения текста вызываем все тот же сигнал и отвечаем на него слотом, описанным в QML.

На первый взгляд может показаться, что для этого потребуется больше времени, чем в первом варианте.

Изменяем наш main.cpp (тут все просто и понятно, соединяем слоты и сигналы)

#include <QApplication>
#include "qmlapplicationviewer.h"
#include <QGraphicsObject>
#include "asd.h"

Q_DECL_EXPORT int main(int argc, char *argv[])
{
    QScopedPointer<QApplication> 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 (немного изменяем заголовок нашего класса) | т.к. в qml определяя функцию нельзя явно указать тип данных, придется заменить QString на QVariant

#ifndef ASD_H
#define ASD_H

#include <QObject>
#include <QVariant>

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 (добавлен все тот же QVariant)

#include "asd.h"

asd::asd(QObject *parent) :
    QObject(parent)
{
}

void asd::getOldText(QString text){
    emit transmitNewText(QVariant(text + " Hello!"));
}

Ну и наше новое окно main.qml

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)
    }
}

Проверим, сколько времени нам понадобится на этот раз:
QML и C++. Гоняем данные, оцениваем скорость взаимодействия

Подводим итог: разница во времени составила примерно 0.9 мс Да, штука, конечно, не шибко заметная, но никто ведь не ожидал отличий миллисекунд эдак в 20. Можно сослаться на погрешность, но при многократном повторении сего, если можно так сказать, эксперимента, результат оказывался примерно равен приведенному в этой статье.

Зачем и для кого все это делалось? Мне в голову почему-то пришла именно эта мысль, ибо такой вот «ерундой» я никогда еще не занимался. Ну а после решил поделиться результатами с вами.

Автор: Olegaaator

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js