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 10
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.
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.