Qt Event 乱弹
Qt 的应用程序都是事件驱动的。
在Qt中,所有的Event对象都是由从QEvent类派生出来的类来描述的。通过调用QObject::event()函数来发送到从QObject继承出来的Qt对象,这个对象会有相应的方法来处理这个事件。
事件的来源主要有两种:
1, 系统产生的
通常是window system把从系统得到的消息,比如鼠标按键,键盘按键等, 放入系统的消息队列中. Qt事件循环的时候读取这些事件,转化为QEvent,再依次处理.
2, Qt应用程序程序自身产生的
程序产生事件有两种方式, 一种是调用QApplication::postEvent(). 例如QWidget::update()函数,当需要重新绘制屏幕时,程序调用update()函数,new出来一个paintEvent,调用QApplication::postEvent(),将其放入Qt的消息队列中,等待依次被处理. 另一种方式是调用sendEvent()函数. 这时候事件不会放入队列, 而是直接被派发和处理, QWidget::repaint()函数用的就是这种方式.
但是对于Qt来说,它并不需要区分这些事件的来源,他们都会采用同样的方式来一致的处理。而且几乎每一种事件都会有一个特定的类相对应。如:QMouseEvent对应鼠标事件,QKeyEvent对应键盘就十分,QCloseEvent对应窗口关闭事件,等等。
QtEvent 的类型很多, 常见的 event类型如下:
** 键盘事件: 按键按下(press)和松开(release)
** 鼠标事件:鼠标按键的按下(press)和松开(release),鼠标移动(move),双击(double click)
** 拖放事件: 用鼠标进行拖放(drag and drop)
** 滚轮事件: 鼠标滚轮滚动(wheel event)
** 绘屏事件: 重绘屏幕的某些部分(paint)
** 定时事件: 定时器到时(timer)
** 焦点事件: 键盘焦点移动(focus)
** 进入和离开事件: 鼠标移入widget之内,或是移出(focus in & focus out)
** 大小改变事件: widget的大小改变(resize)
** 显示和隐藏事件: widget显示和隐藏(show & hide)
** 窗口事件: 窗口是否为当前窗口
** 还有一些不太常见的event,比如socket事件,剪贴板事件,字体改变,布局改变等
在大多数情况下,Qt类都是通过一个虚函数来实现对事件的响应的,这样对于继承出来的类来说,就有机会重新实现这个事件的响应方法。比如,我们会经常写QWidget::paintEvent(…)函数来对一个widget做paint处理,其实,这就是在响应一个QPaintEvent事件。
事件发送的方法主要有两种:
1, send event:
这可以通过调用QCoreApplication::sendEvent(QObject* receiver, QEvent* event)这个函数来实现。当通过这个函数调用来发送一个事件的时候,事件响应函数立刻就会被调用到,也就是说,这是一个同步调用。
2, post event:
这可以通过调用QCoreApplication::postEvent(QObject* receiver, QEvent* event)这个函数来实现。当通过这个函数调用来发送一个事件的事件,事件响应函数并没有立刻被调用,而是把事件先放到一个事件队列里面去,然后在Qt的Event Loop下次才会检索到这个event,然后调用相应的事件处理函数。
Qt的event loop还有这样一个特性,他会把相同的event进行合并,以避免这些事件被执行多次。如:你一次post了多个QPaintEvent事件,那么Qt会把这些事件合并成为一个QPaintEvent事件,这样做的好处是节约系统资源,只paint一次就可以了,而且还有效的避免的界面的闪烁。
Qt有以下几种不同的事件处理方法:
1, Qt的类已经实现的那些事件处理方法,如:paintEvent(..), mousePressEvent(..), keyPressEvent(..), 等等。这些事件处理函数都是虚函数,我们可以在自己定义的类里面重新实现这些函数来处理相应的事件。这是最经常实用,这是最通用,最容易的方法。
2, 重新实现QCoreApplication::notify(QObject* receiver, QEvent* event)函数。这也是一个非常强大,而且可以对事件进行完全控制的方法。但是在一个应用程序中,只能有一个QCoreApplication类(或者是它的子类)的实例存在。
3, 在QCoreApplication(或者其子类)的实例上面安装event filter来处理事件。这样的event filter可以处理到所有的widget event,所有它和重写QCoreApplication::notify函数功能一样强大。另外,在一个应用程序中可以有多个全局性的event filter。需要注意的是,application的event filter只有在那些在主线程中的对象调用。
4, 重新实现QObject::event函数。在这个函数中,你能获得更多的事件控制权限,它会在一个对象的特定事件处理函数之前被调用。比如说:paintEvent, keyPressEvent,等等。
5, 给一个对象安装一个event filter,这个filter将会获得这个对象的所有事件调用。
事件运行机制:
有两种event调度方式,一种是同步的, 一种是异步.
** 当应用程序的main函数调用QCoreApplication的exec()方法是,应用程序进入Qt的主事件循环,它从事件队列中取出本窗口及系统事件,然后把他们打包成相应的QEvent的子类对象,并且使用函数QCoreApplication::notify函数发送事件到相应的QObject对象。在这个主事件循环中,是异步处理的。
** QApplication::sendEvent()的时候, 消息会立即被处理,是同步的. 实际上QApplication::sendEvent()是通过调用QApplication::notify(), 直接进入了事件的派发和处理环节
Event Filter:
一个event filter是一个能够接收所有发送到这个对象上面的事件的对象,并且能够停止或者转发到这个对象上的事件。它通过eventFilter()函数来接收事件,如果这个事件应该被过滤掉(如停止这个事件,或者这个事件已经被处理了,下面不再需要了),那么eventFilter函数返回true,如果不应该被过滤掉,就返回false。
QObject还提供了event filter的安装和卸载方法,如下所示:
a) QObject::installEventFilter(const QObject* filterObject)
b) QObject::removeEventFilter(QObject* filterObject)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论