unexplained delay after QProgressBar finish loading

橙三吉。 提交于 2019-12-02 07:02:53

问题


I have emit signal from a loop (which make some calculations) that triggers progress bar update which located on the main GUI, after the loop ends the progress bar updated to 100% (the progress bar become hidden when the process ends), but than there is a delay, the progress bar stays on 100% and sometimes the mouse changes to busy, and only after few seconds the progress bar become hidden (indicates me that the delay ends), there is nothing after that loop, so nothing I can thinks of can make this delay.

  • I should note that if the loop calculations are light (meaning not a lots of calculations need to be done) there is no such delay.

The emit signal is inside a class in the logic layer, I have try something by including <QtGui/QApplication> into that class (which sounds to me not the right thing to do, as this is the logic layer so why it should need QtGui libraries, but I'm only testing something), I put the following code qApp->processEvents(); inside the loop and now things seems to run smother, no busy mouse, but still there is a delay (the only thing different I can react with the GUI while this delay occurs, but there is no updated results until this delay ends).

Because of the test with the processEvents() I was thinking it's something related to threads, but if so how can I correct the delay behavior, of-course if anyone thinks it could be something else, please do tell.

Some sample code:

Logic layer class:

#include <QtGui/QApplication>
...

processMethod(...)
{
    Loop(...)
    {
        qApp->processEvents();
        emit processBarSignle(value);
        ...some calculations...
    }
    emit processBarSignle(100);
}

View layer (MainWindow):

on_btn_nextProcess_clicked()
{
    m_ui->pBar_process->setVisible(true);
    LogicClass->processMethod(...);
    m_ui->pBar_process->setVisible(false);
}

Thanks


回答1:


Try the following:

#include <QtCore/QCoreApplication>
...

processMethod(...)
{
    Loop(...)
    {
        emit processBarSignle(value);
        QCoreApplication::processEvents();
        ...some calculations...
    }
    emit processBarSignle(100);
    QCoreApplication::processEvents();
}

processEvents() is a static method of QCoreApplication, like that it is sufficient to include only QCoreApplication which is part of the QtCore library.

In addition, you should add processEvents() after the progress bar has been updated, not before that.

Note that processEvents() does not return until every event in Qt's Event Queue has been processed. If there is e.g. a Cancel button, you will have to check if the user actually cancelled the operation each time you called processEvents().
You can exclude user-specific events like mouse clicks / key presses by using

QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents )

but that will not allow clicking anything (e.g. a Cancel Button) while the loop is active.

As a further note: It should be called "processBarSi ng le" ;-)


Clarification on threads etc:

Your whole loop, and any mouse clicks etc are executed in only one thread. If you call emit(), the slot which is connected to that signal is executed instantly (unless the slot was actually in a different thread). In the meantime, the loop does not continue!

When the slot has finished, your loop will continue. In my example this means processEvents() will get called. Now if your slot updated the progress bar or did anything else which caused a repaint, there will be a repaint event in the Event Queue and this repaint will now happen.
If you execute processEvents() before calling your slot, there would be no repaint event which could be processed at this point.

Once again, the loop does not continue until processEvents() is completely done. When all pending events were processed, the loop continues with your calculations.




回答2:


In your code sample, there is actually only one thread. When on_btn_nextProcess_clicked() is called, it shows the progress bar, then runs processMethod() in the same thread. Ideally you want to separate your UI and Data Processing logic.

In intialization, create a separate QThread, start it, and move your LogicClass object to that thread by calling logicClassObject->moveToThread([your new thread]). Then, turn processMethod() into a slot, create a startProcessing() signal in MainWindow and connect the two. Finally, create a processingDone() slot in MainWindow and a finishedProcessing() slot in LogicClass and connect them. When this is all set up you can change your code to the following:

void LogicClass::processMethod(...)
{
    Loop(...)
    {
        emit processBarSignal(value);
        ...some calculations...
    }
    emit processingDone();
}

void MainWindow::on_btn_nextProcess_clicked()
{
    m_ui->pBar_process->setVisible(true);
    emit startProcessing(...);
}

void MainWindow::finishedProcessing()
{
    m_ui->pBar_process->setVisible(false);
}

Whenever you connect signals and slots from two separate threads, multithreading is taken care of automatically. Emitting the signal in one thread causes an event to be qeued in the other which only calls the slot once the second thread regains control.

In this case, the UI thread will schedule an event in the processing thread to start processing. The processing thread will then continually schedule progressBar value updates and finally schedule an event to turn off the progress bar when its done. The two threads will run according to the OS thread scheduler and processing won't block UI.



来源:https://stackoverflow.com/questions/14398050/unexplained-delay-after-qprogressbar-finish-loading

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!