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模拟异步操作。

  • 3
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
9.1事件机制与原理分析 9.1.1 什么是Qt事件驱动?         我们在写Qt工程类项目的时候都会发现,主程序里面都有这么一段代码: int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); } 有点抽象,Qt进行了封装        实际上a.exec()便是Qt程序进入事件消息循环, 9.1.2 图形界面应用程序的消息处理模型 回调、os的魔抓windows、linux,从用户层到 内核层,如何管理进程、线程、 Os如何处理、底层机制 特点: 基于操作系统才能运行 GUI应用程序提供的功能必须由用户触发 用户操作界面时操作系统是第一个感知的  系统内核的消息通过事件处理转变成QT的信号 9.1.3 Qt中的事件处理 (1)在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent.              事件处理的核心包括事件①产生、②分发、③接受和处理 ①事件的产生 谁来产生事件? 最容易想到的是我们的输入设备,比如键盘、鼠标产生的 keyPressEvent,keyReleaseEvent, mousePressEvent,mouseReleaseEvent事件 (被封装成QMouseEvent和QKeyEvent)。 ②Qt事件的分发 谁来负责分发事件? 对于non-GUI的Qt程序,是由QCoreApplication负责将QEvent分发给QObject的子类-Receiver.  对于Qt GUI程序,由QApplication来负责   ③事件的接受和处理 谁来接受和处理事件? 答案是QObject。 类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责( 内存管理、内省intropection、事件处理制)之一。 任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的处理权转给父类。 9.1.4 QObject的内省机制

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kevin_org

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值