QApplication a exec()程序启动,一直到exit()被调用才终止,所以说事件循环是伴随着Qt程序的整个运行周期!
QApplication a;
a exec();
简述事件循环流程:
主动创建派发事件sendEvent(阻塞 )/postEvent(不阻塞 处理之前就返回)/外部事件->(事件队列)notify处理所有通过Qt事件系统传递的事件并且调用notify_helper (notify方法中被调用,用于处理事件的分发和过滤) ->notify_helper会调用目标对象的 event方法(receiver->event(event))来分发事件;
notify和notify_helper部分源码:
可以这么说,每一个事件执行前,都要经过QApplication::notify,所以,我们可以重写notify来对事件做特殊处理。
bool QApplication::notify(QObject *receiver, QEvent *event)
{
...
switch (e->type()) {
...
case QEvent::Wheel: // User input and window activation makes tooltips sleep
case QEvent::ActivationChange:
case QEvent::KeyPress:
case QEvent::KeyRelease:
case QEvent::FocusOut:
case QEvent::FocusIn:
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
...
res = d->notify_helper(receiver, e);
...
}
处理事件过滤器
到这里调用链到了QCoreApplicationPrivate::notify_helper,这个方法比较重要,我们来看主体代码:
bool QCoreApplicationPrivate::notify_helper(QObject *receiver, QEvent * event)
{
...
// send to all application event filters (only does anything in the main thread)
if (QCoreApplication::self
&& receiver->d_func()->threadData->thread.loadAcquire() == mainThread()
&& QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)) {
filtered = true;
return filtered;
}
// send to all receiver event filters
if (sendThroughObjectEventFilters(receiver, event)) {
filtered = true;
return filtered;
}
// deliver the event
consumed = receiver->event(event);
return consumed;
}
可以看到,流程中涉及两个事件过滤器的调用:sendThroughApplicationEventFilterssendThroughObjectEventFilters,事件过滤器调用完后,才是调用接收者的event函数。
对象的event方法
从QCoreApplicationPrivate::notify_helper代码可以看到,处理完事件接收者的事件过滤器后,就会调用接收者的event方法来处理事件。
每一个从QObject继承出来的子类都有event方法,都可以处理自己的事件。
我们简单看下QWidget的event方法:
bool QWidget::event(QEvent *event)
{
...
switch (event->type()) {
...
case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonPress:
mousePressEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonRelease:
mouseReleaseEvent((QMouseEvent*)event);
break;
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent((QMouseEvent*)event);
break;
...
}
notify 方法
notify
方法是 QCoreApplication
(或其子类)的一个虚函数,用于接收并处理来自Qt事件系统的事件。当Qt事件系统检测到有事件发生时,它会调用 QCoreApplication
的 notify
方法,并将事件的目标对象(receiver
)和事件本身(event
)作为参数传递。
notify_helper 方法
notify_helper
方法是 QCoreApplicationPrivate
(QCoreApplication
的私有实现部分)的一个成员函数,它接收相同的参数(receiver
和 event
)并执行事件的过滤和分发逻辑。这个方法是 notify
方法内部调用的一部分,用于实现更复杂的事件处理逻辑。
notify_helper 的工作流程
- 事件过滤器检查:
- 首先,
notify_helper
检查当前是否在主线程中,并且事件是否应该通过应用程序级别的事件过滤器。这是通过调用QCoreApplication::self->d_func()->sendThroughApplicationEventFilters(receiver, event)
实现的。如果事件被过滤器中的任何一个消费(即过滤器返回了true
),则notify_helper
会将filtered
设置为true
并返回,表示事件已被处理,不再需要传递给目标对象。
- 首先,
- 对象级别的事件过滤器检查:
- 如果事件没有被应用程序级别的事件过滤器消费,
notify_helper
接着会检查是否有任何对象级别的事件过滤器(即安装在目标对象或其父对象上的事件过滤器)应该处理该事件。这是通过调用sendThroughObjectEventFilters(receiver, event)
实现的。同样,如果事件被消费,notify_helper
会返回true
。
- 如果事件没有被应用程序级别的事件过滤器消费,
- 事件分发:
- 如果事件既没有被应用程序级别的事件过滤器也没有被对象级别的事件过滤器消费,
notify_helper
会调用目标对象的event
方法(receiver->event(event)
)来分发事件。event
方法是QObject
类的一个虚函数,子类可以通过重写这个方法来提供对特定事件类型的处理。notify_helper
会返回event
方法的返回值,该值通常表示事件是否被消费(true
表示消费,false
表示未消费)。
- 如果事件既没有被应用程序级别的事件过滤器也没有被对象级别的事件过滤器消费,
总结
notify
和 notify_helper
一起工作,构成了Qt事件处理机制的核心。notify
方法是Qt事件系统与应用程序之间的接口,而 notify_helper
则负责实现事件的具体过滤和分发逻辑。通过这种方式,Qt能够灵活地处理各种类型的事件,同时允许开发者通过安装事件过滤器来拦截和修改事件的传递过程。
通过上面的分析,可以获得5种处理或过滤事件的方法;1.重写事件; 2.event中处理;3.事件过滤器;4.notify;5QApplication安装事件过滤器