J'ai quelques problèmes pour changer le texte d'une fenêtre QML dans Qt. J'ai un fichier C ++ qui appelle un thread et à partir de là, j'essaye de changer la valeur de l'étiquette de texte. Le thread fonctionne correctement mais la valeur de texte du QML ne change pas. Voici une partie de mon code:
main.cpp :
Window {
id: window
visible: true
width: 360
height: 360
Component {
id: fruitDelegate
Row {
spacing: 10
Text { text: name }
Text { text: '$' + cost }
}
}
Text {
width: 99
height: 19
text: qsTr("Speed: ")
anchors.verticalCenterOffset: 1
anchors.horizontalCenterOffset: 0
anchors.centerIn: parent
objectName: "lab"
}
Text {
width: 38
height: 19
text: qsTr(" 0 ")
anchors.verticalCenterOffset: 1
anchors.horizontalCenterOffset: 46
anchors.centerIn: parent
objectName: "myLabel"
}
}
Thread.cpp : p >
thread2::thread2(QQuickItem *label) {
this->label = label;
}
void thread2::run() {
int test = 0;
char buffer[10];
int speed = 100;
while(1) {
speed++;
sprintf(buffer,"%d km/h",speed);
this->label->setProperty("text", QString(buffer));
QThread::msleep(1000);
qDebug()<<"tic: "<<buffer<<endl;
}
template.qml :
int main(int argc, char *argv[]) {
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:///template.qml")));
QQuickItem *label = engine.rootObjects().at(0)->findChild<QQuickItem*>("myLabel");
thread2 thread(label);
thread.start();
}
Quelqu'un peut-il me dire pourquoi cela ne fonctionne pas? Où est mon erreur?
Merci!
3 Réponses :
Vous ne devez pas modifier l'interface utilisateur d'un autre thread. Utilisez plutôt le signal / slot.
Vous ne devez pas créer une classe enfant à partir de QThread , également (créez un worker et déplacez-le dans un autre thread).
class Worker: public QObject
{
Q_OBJECT
public slots:
void run()
{
while(1) {
QThread::msleep(1000);
emit changed(QDateTime::currentDateTime().toString());
}
}
signals:
void changed(QString);
};
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QThread* th = new QThread();
Worker* worker = new Worker();
worker->moveToThread(th);
QObject::connect(th, &QThread::started, worker, &Worker::run);
th->start();
QQuickView view(QStringLiteral("qrc:/Main.qml"));
QObject* o = view.rootObject();
QObject::connect(worker, SIGNAL(changed(QString)), o, SIGNAL(change(QString)));
view.showMaximized();
return app.exec();
}
Item {
id: rooItem
visible: true
anchors.fill: parent
signal change(string s);
onChange: foobar.text = s
Text {
id: foobar
text: "Empty"
}
}
Vous avez 2 erreurs:
Compte tenu de ce qui précède, la solution est:
thread.h
// ...
Text {
id: txt
width: 38
height: 19
text: qsTr(" 0 ")
anchors.verticalCenterOffset: 1
anchors.horizontalCenterOffset: 46
anchors.centerIn: parent
objectName: "myLabel"
}
Connections{
target: thread
onTextChanged: txt.text = text
}
// ...
thread .cpp
#include "thread.h"
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
Thread thread;
QObject::connect(&app, &QGuiApplication::aboutToQuit, &thread, &Thread::stop);
thread.start();
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("thread", &thread);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.cpp
#include "thread.h"
#include <QDebug>
Thread::Thread(QObject *parent):
QThread(parent)
{
}
Thread::~Thread()
{
}
void Thread::stop()
{
requestInterruption();
wait();
}
void Thread::run()
{
int speed = 100;
QString text;
while(!isInterruptionRequested()) {
speed++;
text = QString("%1 km/h").arg(speed);
Q_EMIT textChanged(text);
QThread::msleep(1000);
qDebug()<<"tic: "<< text;
}
}
main .qml
#ifndef THREAD_H
#define THREAD_H
#include <QThread>
class Thread : public QThread
{
Q_OBJECT
public:
Thread(QObject *parent=nullptr);
~Thread() override;
Q_SLOT void stop();
Q_SIGNAL void textChanged(const QString & text);
protected:
void run() override;
};
#endif // THREAD_H
Pour plus d'informations, lisez:
Vous utilisez le mauvais mécanisme pour mettre à jour une propriété qml, jetez un œil à < code> QQmlProperty pour la bonne manière. Vous pouvez également exporter une instance de QObject dans le moteur qml et lier la propriété text labels à une propriété de cet objet. Gardez toujours à l'esprit que qml / qt quick sont essentiellement des hacks. Il existe un moyen de mettre à jour l'interface graphique en toute sécurité à partir d'un thread non graphique sans utiliser de signaux. à la place, vous pouvez utiliser des événements pour effectuer le travail. p>
@TrebledJ Pour démarrer la thead, vous devez appeler la méthode start et elle invoquera la méthode run sur le thread approprié
En exécutant thread.start (), la méthode run () est appelée. Oui cela fonctionne. Je le sais parce que le message de débogage de la boucle while () est imprimé. La méthode run est donc appelée. Aussi, je téléchargerai le fichier .h que vous m'avez demandé.