Qt 事件与消息循环
事件
https://subingwen.cn/qt/event_handler/
Qt 框架提供了一些列的事件处理机制,当窗口事件产生之后,事件会经过:事件派发 -> 事件过滤->事件分发->事件处理几个阶段。Qt 窗口中对于产生的一系列事件都有默认的处理动作,如果有特殊需求就需要在合适的阶段重写事件的处理动作。
事件(event)是由系统或者 Qt 本身在不同的场景下发出的。当用户按下/移动鼠标、敲下键盘,或者是窗口关闭/大小发生变化/隐藏或显示都会发出一个相应的事件。一些事件在对用户操作做出响应时发出,如鼠标/键盘事件等;另一些事件则是由系统自动发出,如计时器事件。
每一个Qt应用程序都对应一个唯一的 QApplication 应用程序对象,然后调用这个对象的 exec() 函数,它启动了主线程的事件循环,这样 Qt 框架内部的事件检测就开始了(程序将进入事件循环来监听应用程序的事件)。
1 | int main(int argc, char *argv[]) |
事件在Qt中产生之后,的分发过程是这样的:
当事件产生之后,Qt使用用应用程序对象调用notify()函数将事件发送到指定的窗口:
1
[override virtual] bool QApplication::notify(QObject *receiver, QEvent *e);
事件在发送过程中可以通过事件过滤器进行过滤,默认不对任何产生的事件进行过滤。
1
2// 需要先给窗口安装过滤器, 该事件才会触发
[virtual] bool QObject::eventFilter(QObject *watched, QEvent *event)当事件发送到指定窗口之后,窗口的事件分发器会对收到的事件进行分类:
1
[override virtual protected] bool QWidget::event(QEvent *event);
事件分发器会将分类之后的事件(鼠标事件、键盘事件、绘图事件。。。)分发给对应的事件处理器函数进行处理,每个事件处理器函数都有默认的处理动作(我们也可以重写这些事件处理器函数),比如:鼠标事件:
1
2
3
4
5
6// 鼠标按下
[virtual protected] void QWidget::mousePressEvent(QMouseEvent *event);
// 鼠标释放
[virtual protected] void QWidget::mouseReleaseEvent(QMouseEvent *event);
// 鼠标移动
[virtual protected] void QWidget::mouseMoveEvent(QMouseEvent *event);
所以 Qt 的事件处理器函数处于食物链的最末端,每个事件处理器函数都对应一个唯一的事件,这为我们重新定义事件的处理动作提供了便利。另外,Qt 提供的这些事件处理器函数都是回调函数,也就是说作为使用者我们只需要指定函数的处理动作,关于函数的调用是不需要操心的,当某个事件被触发,Qt框架会调用对应的事件处理器函数。
事件处理函数的一般特征:
① 受保护的虚函数
② 函数名分为两部分: 事件描述 + Event
③ 函数带一个事件类型的参数
消息循环
消息循环由 QApplication::exec 启动。原理是主线程进入一个由 QEventLoop 管理的无限循环,持续监听来自窗口系统,比如鼠标点击、键盘输入、定时器、网络套接字以及其他线程的事件。
当一个事件发生时,它会被封装成一个 QEvent 对象并放入对应线程的事件队列中排队。事件循环会不断从队列中取出事件,分发给指定的 QObject 接收者,通过调用该对象的 event 虚函数来处理。这个 event 函数会根据事件类型调用更具体的事件处理器,比如 mousePressEvent。整个应用就在这个循环的驱动下不断响应和处理各种事件,直到调用 quit() 或 exit(),事件循环才会终止。

