从C ++更新QML文本

问题描述 投票:1回答:3

我在Qt中更改QML窗口的文本时遇到了一些问题。我有一个调用线程的C ++文件,从那里我试图改变文本标签的值。线程正在运行,但QML中的文本值没有变化。以下是我的代码的一部分:

main.cpp中:

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

Thread.cpp:

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:

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

谁能告诉我为什么不工作?我的错误在哪里?

谢谢!

c++ qt qml
3个回答
2
投票

你有2个错误:

  • 您不应该从另一个线程更新GUI,run方法在另一个线程中执行,因此Qt不保证它正常工作。
  • 不要将元素从QML导出到C ++,因为它带来了几个问题,因为很多时候不可能通过objectname获取对象,另一个不方便的是Item的生命周期是由QML确定的,所以在给定的时刻它可能是消除了标签可以指向一个无保留的内存使其使用等。相反,它将C ++对象导出到QML。

考虑到上述解决方案是:

thread.h

#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

thread.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.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.qml

// ...

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
}

// ...

欲了解更多信息:


1
投票

您不应该从另一个线程修改UI。请改用信号/插槽。您不应该从QThread创建子类(也创建一个worker并在另一个线程中移动它)。

Item {
    id: rooItem
    visible: true
    anchors.fill: parent

    signal change(string s);
    onChange: foobar.text = s
    Text {
        id: foobar
        text: "Empty"
    }
}

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

0
投票

您使用错误的机制更新qml属性,以正确的方式查看QQmlProperty。您还可以将QObject实例导出到qml引擎中,并将labels文本属性绑定到该对象的某个属性。请记住,qml / qt quick基本上都是黑客攻击。有一种方法可以在不使用信号的情况下从非gui线程安全地更新gui。相反,你可以使用events来完成工作。

© www.soinside.com 2019 - 2024. All rights reserved.