Qt__ Event handling mechanism

https://www.cnblogs.com/narjaja/p/9143917.html

 

1, Qt event##

Qt will convert system messages (such as mouse buttons, keyboard keys, etc.) into Qt events. Qt events are encapsulated as objects, and the classes that define the objects inherit from the abstract class QEvent.

2, Generation of Qt event##

1. Generated by operating system###

  • Spontaneous events
    Messages obtained from the system, such as mouse buttons, keyboard keys, etc., are put into the system message queue.

2.QT application generation###

  • Posted events

      from Qt Or application generated, put Qt Message queuing.
    
    static void postEvent(QObject *receiver, QEvent *event, int priority = Qt::NormalEventPriority);
  • Sent events

      from Qt Or generated by the application, which is not put into the queue and is directly distributed and processed.
    
    static bool sendEvent(QObject *receiver, QEvent *event);

Note: both functions accept a QObject * and a QEvent * as parameters.
Predecessors said that the event of sendEvent can be allocated on stack or heap; The event of the postEvent must be allocated on the heap.
But how can I try both
The code is as follows:

    QPointF pos(10,10);
    QMouseEvent* mEvnPress = new QMouseEvent(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    QApplication::postEvent(&label,mEvnPress);

Examples###

For example, consider redrawing the event handling function paintEvent(), which can be called by three events:
When the window is covered by other windows and redisplayed again, the system will generate a spontaneous event to request redrawing.
When we call update(), the Posted event is generated.
When we call repaint(), a Sent event is generated.

3, Qt event call##

When QApplication::exec() is called, it enters the event queue loop, constantly detecting events and calling events.

  • First process the events in the Qt event queue until it is empty.
  • Then process the messages in the system message queue until they are empty.
  • When processing system messages, new Qt events will be generated, which need to be processed again.

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

4, Dispatch and handling of events##

In fact, calls to Qt events will eventually be traced back to the QCoreApplication::notify() function. The declaration of this function is:

virtual bool QCoreApplication::notify ( QObject * receiver, QEvent * event );

This function will send the event to the receiver, that is, call receiver - > Event (event). This function realizes the distribution of events. According to the type of event, different event handlers mousePressEvent(), keyPressEvent(), paintEvent() and so on will be called.

Note that QCoreApplication::notify() is called by any event of any object of any thread. Therefore, there is no thread problem of event filter. However, we do not recommend this, because there is only one notify () function, and the event filter is much more flexible.

5, Filtering of events##

Event in the internal function notify called by notify()_ The source code of helper () is as follows:

bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
    // send to all application event filters
    if (sendThroughApplicationEventFilters(receiver, event))
        return true;
    // send to all receiver event filters
    if (sendThroughObjectEventFilters(receiver, event))
        return true;
    // deliver the event
    return receiver->event(event);
}

Before the event is passed to the object (before calling the receiver - > event() function), the filter installed by the application and receiver must be passed. How to install the filter:

QObject(A)->installEventFilter(QObject(B));

First, QObject(A) has a member variable of type QObjectList, named eventFilters
After a QObject(A) has installed the event filter, it will save the pointer of QObject(B) in eventFilters. Before the event reaches the QObject::event() function, it will first check the eventFilters list of the object. If it is not empty, it will first call the eventFilter() function of the object in the list

Filters are defined as follows:

bool QObject::eventFilter ( QObject * watched, QEvent * event )

The return value of the event filter function eventFilter() is of bool type
If true is returned, it means that the event has been processed, and Qt will directly return to process the next event
If false is returned, the event will then be sent to the remaining event filters or target objects for processing

If you use the installEventFilter() function to install an event filter for an object, the event filter is only valid for the object. Only the events of this object need to be passed to the eventFilter() function of the event filter for filtering, and other objects are not affected.
The filter installed for QCoreApplication (because it is also a derived class of QObject, the filter installation method is the same as the above) belongs to the global event filter, which is effective for every object in the program, and the event of any object is first passed to the eventFilter() function.
The advantage of event filter is that the event filter processes the event before the target object receives the event. If we filter out the event, the target object will not see the event at all.

6, Forwarding of events##

For some types of events, if they have not been processed after the whole event distribution process, the event will be forwarded to its parent widget up to the topmost window

How to judge whether an event has been handled? (there are two levels)

  • QApplication::notify(), QObject::eventFilter(), QObject::event() returns a bool value to indicate whether it has been processed "True" indicates that it has been processed, and "false" indicates that the event needs to continue to be delivered.
  • The other is to call QEvent::ignore() or QEvent::accept() to identify the event. Accept means that the event is processed.

For clarity, post some Qt source code (from QApplication::notify()):

    case QEvent::ToolTip:
    case QEvent::WhatsThis:
    case QEvent::QueryWhatsThis:
        {
            QWidget* w = static_cast<QWidget *>(receiver);
            QHelpEvent *help = static_cast<QHelpEvent*>(e);
            QPoint relpos = help->pos();
            bool eventAccepted = help->isAccepted();
            while (w) {
                QHelpEvent he(help->type(), relpos, help->globalPos());
                he.spont = e->spontaneous();
                res = d->notify_helper(w, w == receiver ? help : &he);
                e->spont = false;
                eventAccepted = (w == receiver ? help : &he)->isAccepted();
                if ((res && eventAccepted) || w->isWindow())
                    break;

                relpos += w->pos();
                w = w->parentWidget();
            }
            help->setAccepted(eventAccepted);
        }
        break;

The processing of WhatsThis event is shown here: send it to w first, and stop if the event is accepted or is already a top-level window; Otherwise, get the parent object of W and continue to distribute.

7, Summary##

Now we can summarize the event handling of Qt, which actually has five levels:

  • 1. Rewrite event handling functions such as paintEvent(), mousePressEvent(). This is the most common and simplest form, and the function is also the simplest.
  • 2. Rewrite the event() function. Event () function is the event entry of all objects. It is implemented in QObject and QWidget. By default, it passes events to specific event handling functions.
  • 3. Install event filters on specific objects. This filter filters only the events received by this object.
  • 4. Install the event filter on QCoreApplication::instance(). This filter will filter all events of all objects, so it is as powerful as the notify() function, but it is more flexible because multiple filters can be installed. The global event filter can see the mouse events emitted from the disabled component. The global filter has a problem: it can only be used in the main thread.
  • 5. Rewrite QCoreApplication::notify() function. This is the most powerful, provides complete control like the global event filter, and is not limited by threads. However, only one can be used globally (because QCoreApplication is singleton).

In order to further understand the calling sequence of these levels of event handling methods, we can write a test code:

#include <qapplication.h>
#include <QMainWindow>
#include <QPushButton>
#include <custombutton.h>
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::MouseButtonPress) {
                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));
    QPointF pos(10,10);
    QMouseEvent* mEvnPress = new QMouseEvent(QEvent::MouseButtonPress, pos, Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    QApplication::postEvent(&label,mEvnPress);
    label.show();
    return app.exec();
}

Operation results:

Therefore, we can know that the global event filter is called first, followed by the event filter on the object, followed by the event() function, and finally the specific event handling function.

Reference##

abluemooon's blog
Bean space

Posted by intergroove on Wed, 11 May 2022 09:37:49 +0300