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


  • Moderators

    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 QThread

    import 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
    

 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.