Recently want to know about QT threads, but in the case of the relevant data master is starting from the thread and event loop. For the event loop is a relatively abstract concept, study for a long time also difficult to build a specific model in the brain. Here today to summarize the contents of these days, for future reference.
first, the incident
A lot of information on the Internet will be very clear. The point here is to define a sequence of calls to the event after an event is issued. Here we install a filter in Qapplication, install a filter code in one qwidget as follows:
Class Label:public Qwidget{public:label () {installeventfilter (this);} BOOL EventFilter (Qobject *watched, qevent *event) {if (watched = = this) {if (event->type () = = qevent::mousebuttonpress) {qdebug () << "EventFilter";}} return false;} Protected:void mousepressevent (qmouseevent *) {qdebug () << "Mousepressevent";} BOOL Event (Qevent *e) {if (e->type () = = qevent::mousebuttonpress) {qdebug () << "event";} Return Qwidget::event (e);}};
Class Eventfilter:public Qobject{public:eventfilter (Qobject *watched, Qobject *parent = 0): Qobject (parent), m_watched ( Watched) {}bool eventfilter (qobject *watched, qevent *event) {if (watched = = m_watched) {if (event->type () = = QEvent::Mo usebuttonpress) {qdebug () << "Qapplication::eventfilter";}} return false;} Private:qobject *m_watched;};
int main (int argc, char *argv[]) {qapplication app (argc, argv); Label Label;app.installeventfilter (New EventFilter (&label, &label)); Label.show (); return app.exec ();}
Experimental results:
Qapplication::eventfiltereventfiltereventmousepressevent
See that the event is first called by the filter on the app and then called by the filter on the label before it is passed to the label's event distribution, and then its event handler is called. Where no corresponding event in the event distribution is passed up to his parent object, the parent does not continue to pass up until the topmost level ends.
Second, the event cycle
Studying the event loop has to mention the EXEC () function. The best thing we can think of is that the function call is qapplocation::exec (); The first QT book tells us that the main function calls the function to open a program's event loop. In fact, there are many classes in this class that have this function. For example:
Qdialog::exec () qthread::exec () qdrag::exec () qmenu::exec () ...
So is this function the same in different classes? In this paper, the understanding of the event loop is through the analysis of the function to understand.
Let's take a look at the implementation of the Qapplication::exec () function:
int qcoreapplication::exec () { ... Qeventloop EventLoop; int returncode = Eventloop.exec (); ... return ReturnCode;}
You can see that the function instantiates an event loop class and calls the Exec () function of the class. The visible event loop is mainly done by Qeventloop.
Let's see if the qdialog::exec () function implementation also has the Qeventloop class
int qdialog::exec () { q_d (qdialog); ... SetAttribute (Qt::wa_showmodal, true); ... Show (); ... Qeventloop EventLoop; (void) eventloop.exec (qeventloop::D ialogexec); ...}
There are two parts to this function: 1, setting dialog for modal Show Dialog 2, opening a local event loop
Off-topic: You can see the modal of the dialog box and the event loop is not necessarily connected, the Realization modal dialog box we can use Dig.setattribute (qt::wa_showmodal,true), Dig.show () These two sentences to achieve.
And so Qthread::exec (), qmenu::exec () must have implemented a Qeventloop class to turn on the event loop.
Let's take a look at how the Qeventloop class implements the event loop:
int qeventloop::exec (Processeventsflags flags) { q_d (qeventloop); ... while (!d->exit) processevents (Flags | waitformoreevents | EVENTLOOPEXEC); ... return d->returncode;}
This is a wireless loop function (unless exit is triggered), the loop body is a processevents function. Check the QT documentation for a description of the function:
Processes pending events that match flags until there is no more events to process. Returns true if pending events were handled; otherwise returns false. This function was especially useful if you had a long running operation and want to show it progress without allowing use R input; i.e. by using the EXCLUDEUSERINPUTEVENTS flag.
You can see that the function dispatches an unhandled event, and if so, the pending event is processed to return true and enter the event wait state. Otherwise, false is returned.
Continue down Analysis:
BOOL Qeventloop::p rocessevents (Processeventsflags flags) { q_d (qeventloop); if (!d->threaddata->eventdispatcher) return false; if (Flags & deferreddeletion) qcoreapplication::sendpostedevents (0, Qevent::D eferreddelete); return d->threaddata->eventdispatcher->processevents (flags);//Invoke event dispatcher under different platforms to handle events. }
The condition that the Processevents return value is also visible by the function will finally call the QT and platform-related functions:
BOOL QGuiEventDispatcherWin32::p rocessevents (qeventloop::P rocesseventsflags flags) { if (! QEventDispatcherWin32::p rocessevents (Flags)) return false; if (configrequests) //any pending configs? Qwinprocessconfigrequests (); return true;}
It is an indication that the program will enter an infinite loop wait or distribute event status when executing to the EXEC function without continuing down execution. A more in-depth analysis of this platform-related function is available in reference 1. There is no further analysis of the deeper areas.
And how did the distribution of the events be handed over to the last deal? I see this description in the Qevent class of the QT Documentation:
Qt ' s Main Event loop (Qcoreapplication::exec ()) Fetches native window system events from the event queue,translates them in To Qevents, and sends the translated events to Qobjects.
See that the main loop is responsible for removing the local window event from the event queue (pending event) and translating it into a qevent event, distributed to a specific Qobject (Qobject->event ());
From the previous analysis we can assume that this series of tasks is definitely a qeventloop::exec () in the peocessevents complete. The function obtains the event from the queue and distributes it outward.
when the event is in the Qobject->event () function, The function is distributed to the specific event handler, and if the event () function does not have the events, it is routed to the parent object's event function until the event is processed or passed to the end of the top-level object.
Now if an event (for example: qevent::mousebuttonpress) The event handler performs a lengthy task (for example, bulk read files). The event will remain in the pending state until the processing is complete. At this point the while loop does not continue to loop as we call it a blocking event loop. The loop is blocked by the processevent not distributing the event.
There are three ways to solve this problem (ref. 2): Here we talk about two ways of solving the event loop;
1, if a long time task is a callback function or loop body can be used inside the function qapp->processevents; Force distribution of events. This method problem: may result in recursion.
Solution: Qapp->processevents (qeventloop::excludeuserinputevents);
2, you instantiate a Qeventloop class to open a local event loop. Same problem: It can also lead to recursion
Reference documents:
Anatomy of the mechanism of QT events
Event Loops
Event Loop Nesting
Qt: Events and Event loops