О том как отправлять данные из 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. Можно сослаться на погрешность, но при многократном повторении сего, если можно так сказать, эксперимента, результат оказывался примерно равен приведенному в этой статье.
Зачем и для кого все это делалось? Мне в голову почему-то пришла именно эта мысль, ибо такой вот «ерундой» я никогда еще не занимался. Ну а после решил поделиться результатами с вами.
Автор: Olegaaator