#c #qt #qml
#c #qt #qml #qt5
Вопрос:
Я хочу изменить текст объекта QML во время выполнения.
Я попробовал это следующим образом, но текст просто остается пустым.
Это внутренний класс:
class BackEnd : public QObject {
Q_OBJECT
Q_PROPERTY(QString userFieldText READ userFieldText WRITE setUserFieldText)
public:
explicit BackEnd(QObject *parent = nullptr);
QString userFieldText();
void setUserFieldText(QString amp;username);
private:
QString _userFieldText;
};
В файле qml я включаю window.backend, создаю новый экземпляр BackEnd и пытаюсь получить доступ к значениям, таким как
BackEnd {
id: backend
}
Text {
...
text: backend.userFieldText
}
Я регистрирую класс таким образом.
qmlRegisterType<BackEnd>("window.backend", 0, 1, "BackEnd");
В отдельном потоке, где я хотел бы изменить объекты, я создаю экземпляр серверного класса и вызываю функцию setter.
BackEnd backend;
QString user("set by backend");
backend.setUserFieldText(user);
Компиляция работает, она выполняется, но ничего не меняет.
Я уже пробовал поместить его в таймер в коде QML и обновлять его каждую секунду, но, похоже, ничего не работает.
Комментарии:
1. Вы могли бы показать, как вы создаете поток
2. Поток работает. Уже пробовал это. Это просто std::thread .
3. Вы забыли назначить свою
NOTIFY
функцию внутриQ_PROPERTY
.
Ответ №1:
У вас есть следующие ошибки:
- Как вы указываете, вы создали экземпляр
Backend
в одном потоке и другой экземпляр в QML, поэтому изменение состояния одного экземпляра не изменяет другой экземпляр. В тех случаях, когда вы хотите иметь объект на C и QML, лучше создать контекстное свойство сsetContextProperty()
помощью . - QML принимает только объекты, которые находятся в основном потоке, поэтому внутренний объект не может быть создан в другом потоке, одна из возможностей заключается в том, что вы создаете другой объект, который находится во вторичном потоке и передает данные в основной поток с помощью сигналов, другая возможность — использовать
QThread
, который принимает создание сигналов и подключается кэто кBackend
объекту. - Свойства, которые вы хотите выполнить привязку в QML, должны быть уведомлены с помощью сигнала.
Учитывая вышесказанное, примером может служить следующий:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QThread>
class BackEnd : public QObject {
Q_OBJECT
Q_PROPERTY(QString userFieldText READ userFieldText WRITE setUserFieldText NOTIFY userFieldTextChanged)
public:
explicit BackEnd(QObject *parent = nullptr):
QObject(parent){}
QString userFieldText() const {
return _userFieldText;
}
void setUserFieldText(const QString amp;username){
if(userFieldText() == username) return;
_userFieldText = username;
emit userFieldTextChanged();
}
signals:
void userFieldTextChanged();
private:
QString _userFieldText;
};
class WorkerThread: public QThread
{
Q_OBJECT
public:
using QThread::QThread;
~WorkerThread() override {
requestInterruption();
quit();
wait();
}
signals:
void textChanged(const QString amp;);
protected:
void run() override{
while (!isInterruptionRequested()) {
emit textChanged(QString("set by backend: %1 ").arg(counter));
QThread::msleep(100);
counter ;
}
}
private:
int counter = 0;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
BackEnd backend;
WorkerThread thread;
QObject::connect(amp;thread, amp;WorkerThread::textChanged, amp;backend, amp;BackEnd::setUserFieldText);
thread.start();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("backend", amp;backend);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
#include "main.moc"
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Text {
anchors.centerIn: parent
text: backend.userFieldText
}
}