Planned maintenance: From Sunday 8th December 10:00 CET there will be changes to try and solve the caching issues that have been experienced. If anyone has a problem connecting after this period then please PM @AndyS or any of the moderators.

QProgressbar unresponsive with qthread



  • Hi,

    My requirement is that , i need to run the script , which will generate the n number of files, on creation of each file i need to update the progressbar .

    Running the script is part of separate thread. After script starts running , i am using QFileSystemWatcher to moniter the files has been created, if created i will increment the progress bar accordingly.

    Qprogressbar is not updating when script is executing, Please help me how can i implement this.



  • @meganathan
    Something in your code is wrong then. How can anyone help if we have no idea what your code looks like? Have you tried getting a minimal example, presumably without needing file watchers etc., working in a separate thread, so that you have something simple to start from to get working?



  • Hi @meganathan ,

    can u post the code which u tried and the progressbar value will increase based on value provided to progressbar, check do u have provided the value for progressbar?.

    Thanks,



  • @JonB said in QProgressbar unresponsive with qthread:

    How can anyone help if we have no idea what your code looks like? Have you tried getting a minima

    FelixThread *ansysThread = new FelixThread(tempDirPath,ansysPath,felixMutex);
    ansysThread->start();
    qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
    ansysThread->wait();

    this ansys thread will run my script ,
    Inside thread run()

    QProcess *process = new QProcess();
    process->setWorkingDirectory(QString(getenv("TEMP"))+"\Felix");
    process->start(""" + ansysPath1 + "" -b -i get_node_results.mac -o output.out");
    process->waitForFinished(-1);

    In constructor
    QFileSystemWatcher *watcher = new QFileSystemWatcher(this);
    watcher->addPath(QString(getenv("TEMP"))+"/Felix");

    QObject::connect(watcher,SIGNAL(directoryChanged(const QString &)),this,SLOT(directoryChanged(const QString &)));

    My question is , when ansysThread is started, does ansysthread->wait() blocks the progress bar update or process->waitforfinished(-1) is blocking the main GUI thread to update



  • @meganathan
    I don't even see any QProgressBar anywhere. I don't know if you have one, and even if you do where it is and which thread updates it. Maybe you & I have different expectations about what information you need to supply to ask a question/get an answer. Perhaps someone else can answer without knowing this.



  • Sorry ,forget to update that part.
    Creation:
    ProgressBarWidget = new QWidget();
    ProgressBarWidget->setWindowTitle("FELIXStudio");
    // ProgressBarWidget->setStyleSheet("");

    labell1 = new QLabel("Execution progress");
    ExecutionProgress = new QProgressBar();
    
    QLabel *warningLabel= new QLabel("Do not modify Ansys files");
    QPalette palette = warningLabel->palette();
    palette.setColor(warningLabel->backgroundRole(), Qt::white);
    palette.setColor(warningLabel->foregroundRole(), Qt::red);
    warningLabel->setPalette(palette);
    QVBoxLayout *vLayoutt3 = new QVBoxLayout();
    vLayoutt3->addWidget(labell1);
    vLayoutt3->addSpacing(3);
    vLayoutt3->addWidget(ExecutionProgress);
    vLayoutt3->addSpacing(5);
    vLayoutt3->addWidget(warningLabel);
    vLayoutt3->addStretch();
    

    Inside directorychangePart():

    for(int i=0;i<list1.size();i++)
    {
    strFileName = list1.at(i).fileName();
    if(strFileName.startsWith("R") && alreadyExecuted==false && QString::compare(strFileName,alreadyExecutedFilename)!=0)
    {
    alreadyExecuted = true;
    alreadyExecutedFilename = strFileName;
    //QMessageBox::information(0,"Info",strFileName);
    currentVal = ExecutionProgress->value()+progressVal;
    ExecutionProgress->setValue(currentVal);
    }
    else if(strFileName.contains("loadstep") && QString::compare(strFileName,alreadyExecutedloadset)!=0 && bExtractedFiles== true)
    {
    loadstepFound = true;
    alreadyExecutedloadset = strFileName;
    //QMessageBox::information(0,"Info",strFileName);
    ExecutionProgress->setValue(5);
    setNumberofRFiles(); //this will read the fileCount1
    progressVal = 15/fileCount1;
    }
    }


  • Moderators

    @meganathan said in QProgressbar unresponsive with qthread:

    FelixThread *ansysThread = new FelixThread(tempDirPath,ansysPath,felixMutex);
    ansysThread->start();
    qApp->processEvents(QEventLoop::ExcludeUserInputEvents);
    ansysThread->wait();

    My question is , when ansysThread is started, does ansysthread->wait() blocks the progress bar update or process->waitforfinished(-1) is blocking the main GUI thread to update

    yes it does
    https://doc.qt.io/qt-5/qthread.html#wait



  • @J.Hilk hi,

    Is there any alternative function to Qthread::wait() which doesn't blocks main() GUI thread.


  • Moderators



  • @J.Hilk

    I tried like this
    QEventLoop loop;
    ansysThread->start();
    loop.exec();
    connect(ansysThread, SIGNAL(finished()),this,SLOT(onQProcessFinish()));

    finished() signal emits before Qthread::run() completes the execution. Hot to approach this, if i use ansysthread->wait() it blocks the main GUI thread.. So please suggest any other suggestion.


  • Qt Champions 2018

    @meganathan said in QProgressbar unresponsive with qthread:

    QEventLoop loop;
    ansysThread->start();
    loop.exec();
    connect(ansysThread, SIGNAL(finished()),this,SLOT(onQProcessFinish()));

    Why do you block your thread with

    loop.exec();
    

    ?!
    It should be

    connect(ansysThread, SIGNAL(finished()),this,SLOT(onQProcessFinish()));
    ansysThread->start();
    


  • @jsulm

    I need to wait for thread to completed the process..how can i approach without using ansysthread->wait()


  • Qt Champions 2018

    @meganathan Why do you need to wait? If you wait you block the waiting thread - and then you complain that the thread is blocking and progress bar not updating?! And if you want to wait then what is the point to use threads?
    You get the finished() signal when it is finished and can do whatever needs to be done when the thread finishes.
    Qt is asynchronous and you should avoid waiting for something. Learn how to program in an asynchronous way else there is no point to use Qt or threads.



  • @jsulm
    Based of the files generated by script inside ansysthread, i need to proceed after the script completes execution. i am struct there without using ansysthread->wait()


  • Qt Champions 2018

    @meganathan Again: you know when the thread finishes - you get the finished() signal. So, why don't you simply connect a slot to that signal and process in that slot?



  • @jsulm
    By the time thread emits finished() signal, all my remaining things that to done(after script execution) are already executed. This makes no sense. By using QEventloop can we block the until thread emits finished() signal.?


  • Moderators

    @meganathan as a rule of thumb,

    if you're using QEventLoop or QProcessEvents, you're doing something wrong(95% chance).


  • Qt Champions 2018

    @meganathan said in QProgressbar unresponsive with qthread:

    all my remaining things that to done(after script execution) are already executed

    Then do all these things in the slot connected to finished() signal as I already suggested.
    "By using QEventloop can we block the until thread emits finished() signal.?" - you can, but then your progress bar will not update which was your first question in this thread, right? And if you anyway want to block, then why do you want to use threads? I don't see the point...


  • Moderators

    here:

    #ifndef SUBTHREAD_H
    #define SUBTHREAD_H
    
    #include <QObject>
    #include <QThread>
    
    class SubThread : public QThread
    {
        Q_OBJECT
    public:
        explicit SubThread(QObject *parent = nullptr);
    
    protected:
        virtual void run()override;
    
    signals:
        void status(int stat);
    
    public slots:
    };
    
    #endif // SUBTHREAD_H
    
    
    #include "subthread.h"
    #include <QTime>
    
    SubThread::SubThread(QObject *parent) : QThread(parent)
    {
    
    }
    
    void SubThread::run()
    {
        QTime t;
        t.start();
    
        while(t.elapsed() < 10000){
            if(t.elapsed() % 100 == 0)
                emit status(t.elapsed()/100);
        }
    }
    
    #include <QApplication>
    #include <QProgressBar>
    #include "subthread.h"
    
    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
    
        QProgressBar bar;
        bar.show();
    
        SubThread myThread;
    
        QObject::connect(&myThread, &SubThread::status, &bar, &QProgressBar::setValue);
        QObject::connect(&myThread, &SubThread::finished, &a, &QApplication::quit);
        myThread.start();
    
    
        return  a.exec();
    }
    


  • @J.Hilk

      while(t.elapsed() < 10000){
    

    Now, you doubtless know more than I about threads, because I don't use them. But I don't get this approach. It looks like you're spinning an awfully busy loop. It's true than your main thread will run uninterrupted, but half the CPU will be executing this all the time/your mobile battery is going to drain, no? Could you explain?

    This is why the OP is asking about QEventLoop etc. Does a QThread run its own event loop? Does it exit when it gets to end of run() or does it have to be terminated explicitly?


  • Qt Champions 2018

    @JonB I think this is just a simple example not optimised for real world usage :-)


  • Moderators

    @JonB I usually don't subclass QThread, but that's what the OP did so I went with the example.

    It looks like you're spinning an awfully busy loop. It's true than your main thread will run uninterrupted, but half the CPU will be executing this all the time/your mobile battery is going to drain, no?

    absolute correct. But this is really only a simulation of any busy calculation, that also shows, you don't need to to pause or spin the event loop to emit a signal that is handled in another thread.

    Does a QThread run its own event loop? Does it exit when it gets to end of run() or does it have to be terminated explicitly?

    the default QThread does indeed spin its own event loop. By overwriting run my subclass does this not by default.
    everything inside run is executed in the new thread
    If I want an event loop in SubThread, I would have to call exec()at the end of the run function. If not, the thread finishes as soon as the run function finishes.



  • @jsulm , @J-Hilk
    Thank you for replies. I think I would really need to play with QThreads if it is to sink in! I thought this was code the OP was to type in & use, that's what happens here!

    So just to be clear: if one really wanted to do what you have here --- emit a signal every so often --- one would set up a QTimer in the thread and then execute QThread::exec(), right?


  • Moderators

    @JonB If you want a regular Signal from the thread, triggered by a Timer then yes.

    But the QTimer instance should be created inside run, or a function called from inside run. Otherwise the QTimer lives in the parent thread.



  • @jsulm

    QThread::finished signal() emits even before the thread completed it's process. The main reason for me to go for thread approach is because on using QProcess::waitforfinished(-1) makes my QProgress bar "Not responding" state.

    Even i tried to emit the signal inside the Qthread::run() to update the GUI but on using thread->wait() makes GUI unresponsive yet again.



  • @meganathan

    QThread::finished signal() emits even before the thread completed it's process.

    While you wait for @jsulm to reply, I imagine he'll want to ask you what you mean by the above? If you're not calling exec() it should emit when run() completes.


  • Moderators

    @meganathan it would seriously help if you show us the content of your FelixThread class



  • @J.Hilk
    class FelixThread : public QThread
    {
    Q_OBJECT

    public:
    FelixThread(QDir tempDir,QString ansysPath,QMutex & mutexObj);
    public slots:
    void onExecutionFinished(int exitStatus);

    private:

    void run();    
    QProcess *process;
    

    signals:
    void progressChanged(int val);
    };


Log in to reply