Busy indicator in QML
-
I am trying to implement busy indicator in my application. But the current implementation is not working correctly.
---Main.qml----
import QtQuick 2.4 import QtQuick.Controls 1.3 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 ApplicationWindow { title: qsTr("Hello World") width: 640 height: 480 visible: true BusyIndicator { id: indicator running: false } MainForm { anchors.fill: parent button1.onClicked: { indicator.running = true console.info(indicator.running) obj.runWorkerFunction() indicator.running=false console.info(indicator.running) } } } ---Testclass.cpp---- #include "testclass.h" #include <QDebug> #include <QThread> TestClass::TestClass(QObject *parent) : QObject(parent) { } TestClass::~TestClass(){ } void TestClass::workerFunction() { for(int i = 0; i < 1000; i++){ qDebug() << i; } qDebug() << "Done"; } void TestClass:: runWorkerFunction(){ // QThread* thread = QThread::create([this]() { // workerFunction(); // emit workerFinished(); // }); // thread->start(); workerFunction(); } ---Main.cpp #include <QApplication> #include <QQmlApplicationEngine> #include <QQmlContext> #include "testclass.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); TestClass obj; QQmlApplicationEngine engine; QQmlContext *context = engine.rootContext(); context->setContextProperty("obj", &obj); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
I have tried using Thread which is currently commented out, but busy indicator does not work. The goal is to show the indicator only during the worker thread performs heavy calculation. Additionally with Connections binding I could not make it work. Can anyone help me out with this problem.
Thank you
-
Which part does not work?
openFile
is never called- thread is never started
- busy indicator never stops running
- something else?
-
Hi @sierdzio ,
- Open file is called
- Thread is started
- Busy indicator never starts after finishing the openFile function i think for very small duration it sets to true and then quickly back to false in the callback. But this is not seen visually. I have tried adding log messages and it seems only after the function open file is finished all the messages are logged
-
I have updated my post, to make it more clear and code testable
-
@VinayBalajiRajputh said in Busy indicator in QML:
I have tried adding log messages and it seems only after the function open file is finished all the messages are logged
IMHO that's the expected behavior as you are not using thread and make everything in a function the events are blocked until execution is finished.
What you can do if to provide a property from
TestClass
whic indicates if thread is running, and then bind this property with the BusyIndicator.But just a warning about the thread part, as I'm not an expert I reused your code with some modification for creating and starting the thread. But I don't think this is the correct way to use threads. I recommend that you read carefully QThread documentation, there is a nice example of how to use worker objects by moving them to the thread using QObject::moveToThread(). There are also other ways like QThreadPool and QRunnable or QtConcurrent.
There are also plenty of post on this forum and many others about how to use QThreadimport QtQuick 2.10 import QtQuick.Window 2.10 //Post: https://forum.qt.io/topic/104906/busy-indicator-in-qml/3 import QtQuick 2.4 import QtQuick.Controls 1.3 import QtQuick.Window 2.2 import QtQuick.Dialogs 1.2 ApplicationWindow { title: qsTr("Hello World") width: 640 height: 480 visible: true Connections{ target: obj onIsRunningChanged: console.log("Running: " + obj.isRunning) } BusyIndicator { id: indicator running: obj.isRunning anchors.centerIn: parent } Button { text: "start" anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter onClicked: obj.runWorkerFuntion() } }
c++
//testclass.h #ifndef TESTCLASS_H #define TESTCLASS_H #include <QObject> class TestClass : public QObject { Q_OBJECT Q_PROPERTY(bool isRunning READ isRunning NOTIFY isRunningChanged) bool m_isRunning = false; void workerFunction(); public: explicit TestClass(QObject *parent = nullptr); bool isRunning() const; public slots: void runWorkerFuntion(); signals: void isRunningChanged(bool isRunning); protected slots: void setIsRunning(bool isRunning); void threadStarted(); void threadFinished(); }; #endif // TESTCLASS_H
testclass.cpp #include "testclass.h" #include <QThread> #include <QDebug> TestClass::TestClass(QObject *parent) : QObject(parent) {} bool TestClass::isRunning() const { return m_isRunning; } void TestClass::runWorkerFuntion() { qDebug() << "runWorkerFuntion() from main thread: " << QThread::currentThreadId(); // /!\ THIS IS NOT A GOOD WAY TO USE THREAD QThread* thread = QThread::create([this](){ workerFunction(); }); connect(thread, &QThread::started, this, &TestClass::threadStarted); connect(thread, &QThread::finished, this, &TestClass::threadFinished); connect(thread, &QThread::finished, thread, &QObject::deleteLater); thread->start(); } void TestClass::workerFunction() { qDebug() << "workerFunction() from thread: " << QThread::currentThreadId(); QThread::sleep(1); } void TestClass::setIsRunning(bool isRunning) { if (m_isRunning == isRunning) return; m_isRunning = isRunning; emit isRunningChanged(m_isRunning); } void TestClass::threadStarted() { setIsRunning(true); } void TestClass::threadFinished() { setIsRunning(false); }
console output:
runWorkerFuntion() from main thread: 0x4228 workerFunction() from thread: 0x15a4 qml: Running: true qml: Running: false