我是靠谱客的博主 羞涩香烟,最近开发中收集的这篇文章主要介绍Qt之事件机制,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

事件机制

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之事件机制所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(32)

评论列表共有 0 条评论

立即
投稿
返回
顶部