概述
事件机制
1、事件的来源
- 系统产生
比如用户按下键盘或鼠标,就会产生一个键盘事件或鼠标事件,这是由程序外部产生的事件。操作系统会将这些事件放到系统消息队列中去,进行下一个事件循环时,对该消息进行处理。 - Qt应用程序自身产生
程序产生事件的方式有两种。一种是调用QApplication::postEvent(),例如QWidget::update()函数,当重新绘制屏幕时,程序调用update函数,new出来一个paintEvent,调用QApplication::postEvent(),将其放入Qt的消息队列中,等待下一次事件循环再对其依次处理。另一种是调用QApplication::sendEvent函数,该方法不需要将事件放入事件队列中,而是直接被处理,QWidget::repaint函数就是这种方式。简单理解,前者是异步方式,后者是同步方式。
2、事件与事件循环
事件是由操作系统或程序框架在不同的时刻发生的。通俗来说,事件可以简单理解为信号,例如,用户按下鼠标、敲下键盘或者窗口进行重绘时所发出的信号,都可以理解为一个个事件。
所谓的事件循环,也可以称为消息循环。Qt作为一个跨平台的UI框架,其事件循环是对不同的平台的事件做了封装,对外提供统一的接口。
QEventLoop类是Qt中事件循环主要类,该类对外提供了几个接口:
// 启动并阻塞事件
int exec(QEventLoop::ProcessEventsFlags flags=AllEvents);
// 事件退出
void exit(int returnCode = 0);
// 判断时间是否运行
bool isRunning() const;
// 处理事件
bool processEvents(QEventLoop::ProcessEventsFlags flags=AllEvents);
// 唤醒事件
void wakeUp();
3、事件过滤器
事件过滤器是Qt中一个独特的事件处理机制,功能强大而且使用起来灵活方便。通过它,可以让一个对象侦听拦截另外一个对象的事件。
事件过滤器的实现方式:
- 继承自QObject基类
- 对目标对象调用installFilter()函数给对象安装过滤器
- 重写监视对象的eventFilter()函数
下面通过一个简单的实例进行说明
// 给QLineEdit安装过滤器
m_pLineEdit.installEventFilter(this);
// 重写eventFilter方法
bool eventFilter(QObject* obj, QEvent* ev)
{
bool ret = true;
if( (obj == &LineEdit) && (ev->type() == QEvent::MouseMove) )
{
QKeyEvent* evt = dynamic_cast<QKeyEvent*>(e);
ret = false;
}
return QWidget::eventFilter(obj, ev);
}
上述代码中,eventFilter函数返回值为true时表示该事件已经被处理,不需要传递到m_pLineEdit对象,返回false表示该事件没有被处理或者过滤。
4、事件派发或处理过程
Qt中事件的派发是从 QApplication::notify() 开始的,因为QAppliction也是继承自QObject,所以先检查QAppliation对象,如果有事件过滤器安装在qApp上,先调用这些事件过滤器。接下来QApplication::notify() 会过滤或合并一些事件(比如失效widget的鼠标事件会被过滤掉,而同一区域重复的绘图事件会被合并)。之后,事件被送到接收者的event() 处理。
同样,在接收者的event()中,先检查有无事件过滤器安装在接收者上。若有,则调用之。接下来,根据QEvent的类型,调用相应的特定事件处理函数。一些常见的事件都有特定事件处理函数,比如:mousePressEvent(),focusOutEvent(),resizeEvent(),paintEvent(),resizeEvent()等等。在实际应用中,经常需要重载这些特定事件处理函数在处理事件。但对于那些不常见的事件,是没有相对应的特定事件处理函数的。如果要处理这些事件,就需要使用别的办法,比如重载event() 函数,或是安装事件过滤器。
事件处理流程图:
如何判断一个事件是否被处理了呢?
- 一种方式是: QApplication::notify(), QObject::eventFilter(), QObject::event() 通过
返回bool值来表示是否已处理. “真”表示已经处理, “假”表示事件需要继续传递.; - 另一种方式是:调用QEvent::ignore() 或 QEvent::accept() 对事件进行标识. 这种方式只用于event() 函数和特定事件处理函数之间的沟通,ignore() 是事件继续向上传;
5、事件循环的应用场景
-
场景一:处理复杂计算,界面卡死
有时候我们在计算某个复杂操作时,界面会出现卡死现象,为了防止这种情况出现
可以通过不断触发paintEvents事件,不断刷新界面; -
场景二:处理复杂操作,鼠标点击界面,界面假死
这种情况往往发生在后台处理复杂数据的计算时,用户鼠标无意点击了界面,造成的界面出现假死,这个时候可以通过setCursor()函数屏蔽用户鼠标操作。 -
场景三:模拟同步调用
有时候我们需要模拟执行第一步,等其完成后再执行第二步,比如登陆界面,输入登录信息后,后台进行验证完毕后,进入主界面这样一个过程,可以通过使用本地QEventloop模拟异步操作。
最后
以上就是羞涩香烟为你收集整理的Qt之事件机制的全部内容,希望文章能够帮你解决Qt之事件机制所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复