Skip to content
  • 0 Votes
    1 Posts
    236 Views
    No one has replied
  • 0 Votes
    3 Posts
    778 Views
    jeremy_kJ

    @Tom-asso said in Newbie question: How to spin a BusyIndicator while loading file data?:

    Just starting out with Qt threading api and have some questions. My C++/QML app reads data from a large file and displays it; the QML-defined GUI lets the user modify the display (e.g. with color maps, view angles, etc), and also provides a menu item to load data from another file. While loading data, I would like a QML BusyIndicator to spin, until the data is ready to display. While the BusyIndicator is spinning, the user should be prevented from trying to modify the display through the GUI. I realize the GUI thread must be running in order to spin the BusyIndicator, so presumably my GUI thread code should at least set the BusyIndicator.running property, and launch a worker thread which actually opens the new file and loads its data.

    What’s the best way to run a worker thread with Qt’s api?

    Do you plan to allow cancellation of loading?

    How do I prevent user interaction with other GUI controls while the worker thread is doing its job?

    Item has an enabled property that controls mouse and keyboard input for the item and its children. Eg:

    import QtQuick 2.12 import QtQuick.Window 2.12 Window { contentItem.enabled: false TextInput { anchors.centerIn: parent text: "This input is disabled by its parent" } }

    @AxelVienna said in Newbie question: How to spin a BusyIndicator while loading file data?

    QApplication::setOverrideCursor(Qt::WaitCursor);

    QGuiApplication, not QApplication. There's no need to involve widgets for a QML/Quick application.

  • 0 Votes
    5 Posts
    2k Views
    Gojir4G

    @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
  • 0 Votes
    5 Posts
    2k Views
    E

    This is how I style one off BusyIndicator:

    BusyIndicator { running: true Component.onCompleted: { contentItem.pen = "white" contentItem.fill = "white" } }

    If I recall correctly I was looking at source code of BusyIndicator to understand how to style it.

  • 0 Votes
    2 Posts
    624 Views
    M

    @mjaga Just in case somebody wants to test this, here is a minimal example demonstrating the problem:

    #include <QApplication> #include <QProgressBar> int main(int argc, char *argv[]) { QApplication a(argc, argv); a.setStyle("plastique"); /* working... */ // a.setStyle("cleanlooks"); /* working... */ // a.setStyle("Windows"); /* working... */ // a.setStyle("Fusion"); /* working... */ // a.setStyle("gtk2"); /* NOT working! */ QProgressBar pb; pb.setMaximum(0); pb.setMinimum(0); pb.setValue(0); pb.show(); return a.exec(); }