Update qml value dynamically in C++ using thread
-
wrote on 9 Sept 2021, 03:38 last edited by
Hi, may I know how to use thread to update value dynamically in C++? I am using processEvents() to update the infinity loop value, but I found that it is super lag. That's why I am wondering can we prevent this problem by using thread or not? If yes, I would like to seek for your guidelines. Thank you
-
Hi, may I know how to use thread to update value dynamically in C++? I am using processEvents() to update the infinity loop value, but I found that it is super lag. That's why I am wondering can we prevent this problem by using thread or not? If yes, I would like to seek for your guidelines. Thank you
-
wrote on 9 Sept 2021, 06:02 last edited by
Code below is the example that I refer to https://doc.qt.io/archives/3.3/qthread.html . However, step2b is not executed successfully, so how can I upload qml value via QThread?
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QThread>
#include <QDebug>int value;
class MyThread : public QThread {
public:
virtual void run();
};void MyThread::run()
{
int count = 0;
for( ;; ) {
sleep( 2 );
value = count;
count++;
}
}int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endifQGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); // Step 1: get access to the root object QObject *rootObject = engine.rootObjects().first(); QObject *qmlObject = rootObject->findChild<QObject*>("progressbar"); MyThread a; MyThread b; a.start(); b.start(); // Step 2b: set or get the desired property value for any qml object // qmlObject->setProperty("value", value); // qDebug() << qmlObject->property("visible"); app.exec(); a.wait(); b.wait(); return 0;
}
-
Code below is the example that I refer to https://doc.qt.io/archives/3.3/qthread.html . However, step2b is not executed successfully, so how can I upload qml value via QThread?
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QThread>
#include <QDebug>int value;
class MyThread : public QThread {
public:
virtual void run();
};void MyThread::run()
{
int count = 0;
for( ;; ) {
sleep( 2 );
value = count;
count++;
}
}int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endifQGuiApplication app(argc, argv); QQmlApplicationEngine engine; const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); // Step 1: get access to the root object QObject *rootObject = engine.rootObjects().first(); QObject *qmlObject = rootObject->findChild<QObject*>("progressbar"); MyThread a; MyThread b; a.start(); b.start(); // Step 2b: set or get the desired property value for any qml object // qmlObject->setProperty("value", value); // qDebug() << qmlObject->property("visible"); app.exec(); a.wait(); b.wait(); return 0;
}
wrote on 9 Sept 2021, 06:32 last edited by@JJLim Demo:
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include <QtConcurrent> class Helper: public QObject{ Q_OBJECT public: using QObject::QObject; Q_INVOKABLE void start(){ doWork(); } signals: void progressChanged(int); private: void doWork(){ QtConcurrent::run([=]{ for(int i=0; i < 100; i++){ emit progressChanged(i); QThread::sleep(1); } }); } }; int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); Helper helper; QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("helper", &helper); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); } #include "main.moc"
import QtQuick 2.15 import QtQuick.Window 2.15 import QtQuick.Controls 2.15 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") ProgressBar { id: progressbar from: 0 to: 100 anchors.centerIn: parent width: 300 } Connections{ target: helper function onProgressChanged(i){ progressbar.value = i } } Component.onCompleted: helper.start() }
-
wrote on 9 Sept 2021, 06:47 last edited by
@eyllanesc Thank you very much, it works perfectly!!!
Btw may I know how the QThread works, if I have 4 threads, so the tasks will be separated evenly among these 4 threads? Can I assume that it works like the POSIX threads?
-
@eyllanesc Thank you very much, it works perfectly!!!
Btw may I know how the QThread works, if I have 4 threads, so the tasks will be separated evenly among these 4 threads? Can I assume that it works like the POSIX threads?
@JJLim out of curiosity,
what makes you think you need threads in the first place? (all)most Qt classes are asynchronous in nature. And needing to use sleep is usually a sign for immature design/implementation, or admittedly very low level operations (polling level changes on input pins for example) -
wrote on 9 Sept 2021, 07:20 last edited by
I see, thks for your explanation.
@J-Hilk I was thinking to use thread for preventing some laggy issues. For exp, the qml components (progress bar) are updated based on the infinity loop in the C++, this process makes the display almost freeze. That's why I am thinking is it possible to use thread to overcome this issue or not.
I am still learning about it, so I would like to explore something news haha.
Btw, thank you very much for your guidance @eyllanesc , it helps me a lot.
-
wrote on 9 Sept 2021, 07:31 last edited by
@J-Hilk So based on your explanation, is it possible that thread can be used to solve the GUI laggy issue when updating the value during the runtime (infinity loops). Or is there any alternative method to prevent this kind of issue?
The code has been attached, when I add more infinity loops, my qt GUI will almost freeze, not sure is it due to the coding problem or it is actually the PC issues haha.
-
@J-Hilk So based on your explanation, is it possible that thread can be used to solve the GUI laggy issue when updating the value during the runtime (infinity loops). Or is there any alternative method to prevent this kind of issue?
The code has been attached, when I add more infinity loops, my qt GUI will almost freeze, not sure is it due to the coding problem or it is actually the PC issues haha.
@JJLim said in Update qml value dynamically in C++ using thread:
based on the infinity loop in the C++
rights thats my point, what are you doing in those infinite loops?
-
wrote on 9 Sept 2021, 08:57 last edited by
Fyi, the purpose of infinity loop is for keep updating the value.
-
@JJLim said in Update qml value dynamically in C++ using thread:
Fyi, the purpose of infinity loop is for keep updating the value.
yes of course but why are you using an infinite loop instead of a QTimer, you can't update the UI faster than every 20(ish) ms anyway
-
wrote on 9 Sept 2021, 10:09 last edited by JJLim 9 Sept 2021, 10:10
oic, so what u mean is I can just use QTimer to update qml component dynamically? Can I have a relevant example for the further clarification?
Bcuz what am I doing now is set an infinity loop, within the loop, I use std::this_thread::sleep_for() to let the GUI accept new value for n interval haha
Sorry for asking so many questions, I am newbie to Qt and learning now
-
oic, so what u mean is I can just use QTimer to update qml component dynamically? Can I have a relevant example for the further clarification?
Bcuz what am I doing now is set an infinity loop, within the loop, I use std::this_thread::sleep_for() to let the GUI accept new value for n interval haha
Sorry for asking so many questions, I am newbie to Qt and learning now
@JJLim here, the modified
Helper
class from @eyllanesc exampleclass Helper: public QObject{ Q_OBJECT public: explicit Helper(QObject *parent = nullptr): QObject(parent) { m_tUpdateProgress.setInterval(1000); // 1000ms -> every second connect(&m_tUpdateProgress, &QTimer::timeout, this, &Helper::doWork); } public slots: void start(){ m_progress = 0; m_tUpdateProgress.start(); } void stop(){ m_tUpdateProgress.stop(); } signals: void progressChanged(int); private: void doWork(){ m_progress++; emit progressChanged(m_progress); } private: int32_t m_progress{0}; QTimer m_tUpdateProgress; };
-
wrote on 9 Sept 2021, 11:23 last edited by
Wow it works perfectly!!!
Thank you very much for your guidance ^.^
I got it now haha -
wrote on 31 Jan 2022, 11:42 last edited by
It was a great help for running threads. Running in QtConcurrent::run([=], really solved all the issues of my UI non responsive ness.. Thanks a lot for your help