Qt event handling mechanism

Thinking Guide

1. Introduction to the event

The QT program is event-driven, and every action of the program is triggered by an internal event. The occurrence and processing of QT events become the main line of program operation and exist in the entire life cycle of the program.

Common QT event types are as follows:

Keyboard events: key presses and releases

Mouse events: mouse movement, mouse button press and release

Drag and drop event: drag and drop with the mouse

wheel event: mouse wheel scrolling

Paint event: redraw some part of the screen

Timing event: timer expires

Focus event: keyboard focus moves

Enter and leave events: the mouse moves into or out of the widget

Move event: the position of the widget changes

Size change event: the size of the widget changes

Show and hide events: widget show and hide

Window event: Whether the window is the current window

QT converts messages generated by the system into QT events, and QT events are encapsulated as objects. All QT events inherit the abstract class QEvent, which is used to describe actions that occur inside or outside the program. Any QObject object has the ability to process QT events. .

At the end of the article, Qt information is prepared for everyone

2. QT event generation

(1) Operating system events

The operating system puts the acquired events, such as mouse button, keyboard button and other keyPressEvent, keyReleaseEvent, mousePressEvent, mouseReleaseEvent events, into the message queue of the system, and reads the messages in the message queue during the Qt event loop, converts them into QEvents and distributes them To the corresponding QWidget object, the event (QEvent *) in the corresponding QWidget will process the event, and the event (QEvent *) will call different event processing functions according to the event type, and send QT predefined in the event processing function The signal of the signal finally calls the slot function associated with the signal.

Event handling for GUI applications:

A. After the QT event is generated, it will be sent to the corresponding QWidget object immediately

B. The event (QEvent *) in the corresponding QWidget performs event processing

C. event(QEvent *) calls different event processing functions according to the event type

D. Send QT predefined signals in the event processing function

E. Call the slot function associated with the signal

(2) Qt application generated by itself

There are two ways for the program to generate events. One is to call QApplication::postEvent(), such as the QWidget::update() function. When the screen needs to be redrawn, the program calls the update() function, a new paintEvent is generated, and QApplication is called: :postEvent(), put it into Qt’s message queue, and wait for it to be processed in turn;

Another way is to call the sendEvent() function. The event will not be put into the queue, but will be dispatched and processed directly. The QWidget::repaint() function uses the blocking type.

The lifespan of the event object in sendEvent() is managed by the Qt program, supports event objects allocated on the stack and heap; the lifespan of the event object in postEvent() is managed by the Qt platform, and only supports distribution The event object that is allocated on the heap and will be destroyed by the Qt platform after the event is processed.

3. Qt event handling

(1) Event scheduling

There are two scheduling methods for events, synchronous and asynchronous.

Qt’s event loop is asynchronous. When QApplication::exec() is called, it enters the event loop. It first processes the events in the Qt event queue until it is empty, and then processes the messages in the system message queue until it is empty. When processing system messages, new Qt events will be generated, which need to be processed again.

When calling QApplication::sendEvent, the message will be processed immediately, which is synchronous. In fact, QApplication::sendEvent() directly enters the event distribution and processing link by calling QApplication::notify().

(2) Event notification and distribution

Event filter is a unique event processing mechanism in Qt, which is powerful and flexible to use. Through event filters, one object can listen to intercept events of another object. Event filters are implemented as follows: In the base class QObject of all Qt objects, there is a member variable of type QObjectList named eventFilters. When a QObject (A) installs an event filter for another QObject (B), B Will save the pointer of A in eventFilters. Before B processes the event, it will first check the eventFilters list, and if it is not empty, call the eventFilter() function of the object in the list first. An object can install filters for multiple objects, and an object can have multiple filters installed at the same time. After the event arrives, the event filters are called in the reverse order of the installation order. The return value of the event filter function ( eventFilter() ) is bool type. If it returns true, it means that the event has been processed, and Qt will return directly to process the next event. If false is returned, the event will then be sent to the remaining event filter or target object for processing.

In QT, the dispatch of events starts from QApplication::notify(), because QApplication is also inherited from QObject, so check the QApliation object first, if there is an event filter installed on the qApp, call the event filter first, and then QApplication: :notify() will filter or merge some events (for example, mouse events of invalid widgets will be filtered out, and repeated drawing events in the same area will be merged), and the events will be sent to reciver::event() for processing.

In receiver::event(), first check whether there is an event filter installed on the receiver. If so, call it. Then according to the type of QEvent, call the corresponding specific event processing function. Common events have specific event handlers, such as: mousePressEvent(), focusOutEvent(), resizeEvent(), paintEvent(), resizeEvent(), etc. In practical applications, it is often necessary to overload specific event handlers to handle events. For uncommon events, there is no corresponding specific event handler. If you want to handle these events, you need to use other methods, such as overloading the event() function, or installing event filters.

(3) Forwarding of events

For some types of events, if the event has not been processed after the entire event dispatching process is over, then this event will be forwarded upwards to its parent widget until the topmost window. Event-related functions in Qt communicate with each other in two ways, one is QApplication::notify(), QObject::eventFilter(), QObject::event() returns a bool value to indicate whether it has been processed; the other It is to call QEvent::ignore() or QEvent::accept() to identify the event, which is only used for communication between the event() function and a specific event handler, and it is only meaningful for certain types of events , these events are the events mentioned above that will be forwarded, including: mouse, scroll wheel, key press and other events.

(4) Event processing and filtering

Qt provides five different levels of event handling and filtering:

A. Rewrite a specific event handler.

The most common event handling method is to override mousePressEvent(), keyPressEvent(), paintEvent() and other specific event handling functions.

B. Rewrite the event() function.

When rewriting the event() function, you need to call the event() function of the parent class to handle events that do not need to be processed or are not clear how to handle.

return QWidget::event(event);

C. Install event filters on Qt objects

There are two steps to install an event filter: (Assume that A is used to monitor and filter events of B)

First call B’s installEventFilter( const QOject *obj ), with A’s pointer as a parameter, all events sent to B will be processed by A’s eventFilter() first. Then, A needs to rewrite the QObject::eventFilter() function, and process the event in eventFilter().

D. Install an event filter for the QApplication object

If a filter is installed on the QApplication object, all events must first pass through the current eventFilter() before being sent to any other filter. In QApplication::notify(), the filter of qApp is called first, and then the event is analyzed to decide whether to merge or discard.

E. Inherit the QApplication class and overload the notify() function

Qt uses the QApplication::notify() function to distribute events. To get these events before any event filters view any events, rewriting the notify() function is the only way. Generally speaking, event filters are better to use, because there is no need to inherit the QApplication class, and any number of event filters can be installed on the QApplication object.

4. Example of custom event and eventFilter

class DefineEvent : public QEvent
{
public:
    const static QEvent::Type DefineType = static_cast<QEvent::Type>(QEvent::User + 0xFF);

    explicit DefineEvent(QString data) : QEvent(DefineType)
    {
        m_data = data;
    }

    QString data() {return m_data;}

private:
    QString m_data;
};
#ifndef WIDGET_H
#define WIDGET_H
 
#include <QWidget>
#include <QLineEdit>
#include "StringEvent.h"
#include <QMouseEvent>
#include <QDebug>
#include <QApplication>
 
class Widget : public QWidget
{
    Q_OBJECT
    QLineEdit m_edit;
public:
    Widget(QWidget *parent = 0): QWidget(parent), m_edit(this)
    {
        m_edit.installEventFilter(this);
    }
    bool event(QEvent* evt)
    {
        if( evt->type() == QMouseEvent::MouseButtonDblClick )
        {
            qDebug() << "event: Before sentEvent";
            StringEvent e("D.T.Software");
            QApplication::sendEvent( &m_edit, &e);
            qDebug() << "event: After sentEvent";
        }
        return QWidget::event(evt);
    }
 
    bool eventFilter(QObject* obj, QEvent* evt)
    {
        if( (obj == & amp;m_edit) & amp; & amp; (evt->type() == StringEvent::TYPE) )
        {
            StringEvent* se = dynamic_cast<StringEvent*>(evt);
            qDebug() << "Receive: " << se->data();
            m_edit.insert(se->data());
            return true;
        }
 
        return QWidget::eventFilter(obj, evt);
    }
 
    ~Widget()
    {
 
    }
};
 
#endif // WIDGET_H


 Custom event types can use registerEventType
 QEvent::Type ImageLoadedEvent::evType(){
    if(s_evType == QEvent::None)
    {
        s_evType = (QEvent::Type)registerEventType();
    }
    return s_evType;
}