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

от автора

О том как отправлять данные из 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)     } } 

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

Для чистоты эксперимента кликнем на тексте 20 раз:

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

Второй вариант реализации: при нажатии на текст генерируем сигнал, соединяем этот сигнал со слотам уже знакомого нам класса, после чего все тем же путем после изменения текста вызываем все тот же сигнал и отвечаем на него слотом, описанным в 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)     } } 

Проверим, сколько времени нам понадобится на этот раз:

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

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

ссылка на оригинал статьи http://habrahabr.ru/post/171341/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *