catalogue
2, QCoreApplication main event loop
6, Nesting of event loop and Simulation of synchronous call by QEventLoop
1, Event loop for Qt
As a cross platform UI framework, Qt's event loop implementation principle is to encapsulate event loops of different platforms and provide a unified abstract interface. Qt has done similar work, as well as many open source libraries such as glfw and SDL.
2, QCoreApplication main event loop
In general Qt programs, there is a QCoreApplication/QGuiApplication/QApplication in the main function, and exec is called at the end.
int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); //Or QGuiApplication, or QApplication ... ... return app.exec(); }
In the application class, after removing startup parameters, versions and other related things, the key is to maintain a QEventLoop, and the exec of application is the exec of QEventLoop. However, this EventLoop in the application is called the "main event loop". All event distribution and event handling begin here. Application also provides sendEvent and poseEvent functions to send events respectively. The event sent by sendEvent will be processed immediately, that is, "synchronous" execution. The events sent by postEvent will be added to the event queue and processed in the next round of event loop, that is, "asynchronous" execution. There is also a special sendPostedEvents, which is to immediately synchronize the events that have been added to the queue for asynchronous execution.
3, Start of event cycle
Generally, our event loop is started by exec(), for example, the following example:
QCoreApplicaton::exec() QApplication::exec() QDialog::exec() QThread::exec() QDrag::exec() QMenu::exec()
These all start the event loop. The event loop is an infinite "loop" first. The program loops indefinitely in exec (), which can prevent the code following exec () from running until the program jumps out of exec (). When you jump out of exec(), the event loop is terminated. QEventLoop::quit() can terminate the event loop. The event loop is actually similar to an event queue, which processes the listed events in turn. When the time is finished but the time loop does not end, it is actually similar to a for(;;) that does not occupy CPU time Cycle. Its essence is actually to redistribute time slices in the form of queues.
4, processEvents
Our UI interface should be refreshed continuously (for QWidget, the paintEvent event event is triggered) to ensure smooth display and timely response to user input. Generally, it is necessary to have a good frame rate, such as refreshing 60 frames per second, that is, FPS 60, which is often called. After conversion, it is 1000 ms/ 60 ≈ 16 ms, that is, refreshing every 16 Ms. Sometimes we need to do some complex calculations, which take far more than 16 milliseconds. Before the calculation is completed, the function will not exit (equivalent to blocking). If the event loop is not processed in time, the UI will get stuck. In this scenario, we can use the interface provided by Qt to immediately process an event loop to ensure the fluency of the UI.
//time-consuming operation doWork1() //Insert a processEvents in the appropriate position to ensure that the event loop is processed QCoreApplication::processEvents(); //time-consuming operation doWork2()
5, QEventLoop class
QEventLoop is the event loop class in Qt. The main interfaces are as follows:
int exec(QEventLoop::ProcessEventsFlags flags = AllEvents) void exit(int returnCode = 0) bool isRunning() const bool processEvents(QEventLoop::ProcessEventsFlags flags = AllEvents) void processEvents(QEventLoop::ProcessEventsFlags flags, int maxTime) void wakeUp()
Exec is the initiating event loop. After calling exec, the function that calls exec will be blocked until the while loop ends in EventLoop.
6, Nesting of event loop and Simulation of synchronous call by QEventLoop
Event loops can be nested. When in a child event loop, the events in the parent event loop are actually in an interrupted state. The events in the parent loop can be executed only after the child loop jumps out of exec. Of course, this does not mean that the interface response similar to that in the parent loop will be interrupted when executing the child loop, because most of the events of the parent loop will also be in the child loop. When executing QMessageBox::exec(), QEventLoop::exec(), although these execs() interrupt QApplication::exec() in main(), the GUI interface response has been included in the child loop, So the GUI interface can still get a response. If a child event loop is still valid, but its parent loop is forced to jump out, the parent loop will not jump out immediately, but will not jump out until the child event loop jumps out.
1. Get data synchronously
There are often scenarios where an operation is triggered, and the next step can only be carried out after the operation is completed. For example: data acquisition, after initiating a login request to the server, you must wait until you receive the data returned by the server before deciding how to execute the next step. In this scenario, if it is designed as asynchronous call, you can directly use Qt signal / slot. If it is designed as synchronous call, you can use local QEventLoop.
void A::onFinish(bool r, const QString &info) { m_result = r; qDebug() << info; //Exit event loop in slot loop.quit(); } bool A::get(const QString &userName, const QString &passwdHash, const QString &dataName) { //Declare local EventLoop QEventLoop loop; m_result = false; //Connect the signal first connect(&network, SIGNAL(finished(bool,const QString &)),this,SLOT(onFinish(bool,const QString &))); //Initiate login request getData(userName, passwdHash, dataName); //Start the event loop. Block the current function call, but the event loop can still run. //This is not going to run down to the front slot, calling loop.. After quitting, we will continue to go down loop.exec(); //Return result. Before loop exits, M_ The value in result has been updated. return m_result; }
2. Main thread waiting
For example, if you want to wait for the main thread for 100ms, you can't use sleep, which will cause the GUI interface to stop responding, but you can avoid this by using event loop:
QEventLoop loop; QTimer::singleShot(100, &loop, SLOT(quit())); loop.exec();
3. The dialog box pops up
void A::Show() { QDialog dlg; dlg.show(); QEventLoop loop; connect(&dlg, SIGNAL(finished(int)), &loop, SLOT(quit())); loop.exec(QEventLoop::ExcludeUserInputEvents); }