zoukankan      html  css  js  c++  java
  • Qt的事件模型(5种使用办法,通常重新实现event handler即可。只有定义控件才需要管理信号的发射)

    Qt的事件模型

    1.事件的概念

            应用程序对象将系统消息接收为 Qt 事件。应用程序可以按照不同的粒度对事件加以监控、过滤并做出响应。

        在 Qt 中,事件是指从 QEvent继承 的对象。Qt将事件发送给每个QObject对象,这样对象便可对事件做出响应。也就是说,Qt 的事件处理机制主要是基于 QEvent 类来实现的,QEvent 类是其他事件类的基类。当一个事件产生时,Qt 就会构造一个 QEvent 子类的实例来表述该事件,然后将该事件发送到相应的对象上进行处理。

        编程人员可以对应用程序级别和对象级别中的事件进行监控和过滤。

    2.事件的创建

            大多数事件是由窗口系统生成的,它们负责向应用程序通知相关的用户操作,例如:按键、  鼠标单击或者重新调整窗口大小。也可以从编程角度来模拟这类事件。在Qt中大约有 50 多种事件类型,最常见的事件类型是报告鼠标活动、按键、重绘请求以及窗口处理操作。编程人员也可以添加自己的活动行为,类似于内建事件的事件类型。

            通常,接收方如果只知道按键了或者松开鼠标按钮了,这是不够的。例如,它还必须知道按的是哪个键,松开的是哪个鼠标按钮以及鼠标所在位置。每一 QEvent 子类均提供事件类型的相关附加信息,因此每个事件处理器均可利用此信息采取相应处理。

    3.事件的交付

            Qt 通过调用虚函数 QObject::event() 来交付事件。出于方便起见,QObject::event()会将大多数常见的事件类型转发给专门的处理函数,例如:QWidget::mouseReleaseEvent()和 QWidget::keyPressEvent()。开发人员在编写自己的控件时,或者对现有控件进行定制时,可以轻松地重新实现这些处理函数。

            有些事件会立即发送,而另一些事件则需要排队等候,当控制权返回至 Qt 事件循环时才会开始分发。Qt 使用排队来优化特定类型的事件。例如,Qt 会将多个 paint 事件压缩成一个事件,以便达到最大速度。

            通常,一个对象需要查看另一对象的事件,以便可以对事件做出响应或阻塞事件。这可以通过调用被监控对象的 QObject::installEventFilter() 函数来实现。实施监控对象的QObject::eventFilter() 虚函数会在受监控的对象在接收事件之前被调用。

            另外,如果在应用程序的 QApplication 唯一实例中安装一个过滤器,则也可以过滤应用程序的全部事件。系统先调用这类过滤器,然后再调用任何窗体特定的过滤器。开发人员甚至还可以重新实现事件调度程序 QApplication::notify(),对整个事件交付过程进行全面控制。

    4.事件循环模型

        Qt 的主事件循环能够从事件队列中获取本地窗口系统事件,然后判断事件类型,并将事件分发给特定的接收对象。 主 事 件 循 环 通 过 调 用 QCoreApplication::exec() 启 动 , 随 着QCoreApplication::exit()结束,本地的事件循环可用利用 QEventLoop 构建。作为事件分发器的 QAbstractEventDispatcher 管理着 Qt 的事件队列,事件分发器从窗口系统或其他事件源接收事件,然后将他们发送给 QCoreApplication 或 QApplication 的实例进行处理或继续分发。QAbstractEventDispatcher 为事件分发提供了良好的保护措施。

         一般来说,事件是由触发当前的窗口系统产生的,但也可以通过使用QCoreApplication::sendEvent()和 QCoreApplication::postEvent()来手工产生事件。需要说明的是 QCoreApplication::sendEvent()会立即发送事件,QCoreApplication::postEvent()则会将事件放在事件队列中分发。如果需要在一个对象初始化完成之际就开始处理某种事件,可以将事件通过 QCoreApplication::postEvent()发送。

       通过接收对象的 event()函数可以返回由接收对象的事件句柄返回的事件,对于某些特定类型的事件如鼠标(触笔)和键盘事件,如果接收对象不能处理,事件将会被传播到接收对象的父对象。需要说明的是接收对象的 event()函数并不直接处理事件,而是根据被分发过来的事件的类型调用相应的事件句柄进行处理。

    5. 自定义事件

        一般有下列5种方式可以用来处理和过滤事件,每种方式都有其使用条件和使用范围。

    ⑴ 重载 paintEvent()、 mousePressEvent()等事件处理器(event handler)

        重新实现像mousePressEvent(), keyPressEvent()和paintEvent()这样的event handler是目前处理event所采用的最常见的方法,这种方法比较容易掌握

    ⑵ 重载 QcoreApplication::notify()函数

        这种方式能够对事件处理进行完全控制。也就是说,当你需要在事件处理器(event handler)之前得到所有事件的话,就可以采用这个方法,但是这样一来,因为只有一个notify()函数,所以每次只能有一个子类被激活。这与事件过滤器不同,因为后者可以有任意数目并且同时存在。

    ⑶ 在 QCoreApplication::instance()也即在 qApp 上安装事件过滤器

        这样就可处理所有部件(widget)上的所有事件,这和重载 QCoreApplication::notify()函数的效果是类似的。 一旦一个event filter被注册到qApp(唯一的QApplication对象), 程序里发到其它对象的事件在发到其它的event filter之前,都要首先发到这个eventFilter上,不难看出,这个方法在调试(debugging)应用程序时也是非常有用的。

    ⑷ 重载 QObject::event()函数

       通过重新实现的event()函数,我们可以在事件到达特定部件的事件过滤器(event handler)前处理 Tab 事件。需要注意的是,当重新实现某个子类的event()的时候,我们需要调用基类的event()来处理不准备显式处理的情况。

    ⑸ 在选定对象(Object)上安装事件过滤器(event filter)

        该对象需要继承自QObject ,这样就可以处理除了Tab 和 Shift-Tab 以外的所有事件。当该对象用installEventFilter()注册之后,所有发到该对象的事件都会先经过监测它的event filter。如果该object同时安装了多个event filter,那么这些 filter会按照“后进先出”的规则依次被激活, 即顺序是从最后安装的开始,到第一个被安装的为止。

    6.事件与信号的区别

        需要注意,我们不应该混淆“事件”和“信号”这两个概念。

    ⑴ 使用场合和时机不同

        一般情况下,在“使用”窗口部件时,我们经常需要使用信号,并且会遵循信号与槽的机制;而在“实现”窗口部件时,我们就不得不考虑如何处理事件了。举个例子,当使用QPushButton时,我们对于它的clicked()信号往往更为关注,而很少关心促成发射该信号的底层的鼠标或者键盘事件。但是,如果要实现一个类似于QPushButton的类,我们就需要编写一定的处理鼠标和键盘事件的代码,而且在必要的时候,仍然需要发射和接收clicked()信号。

    ⑵ 使用的机制和原理不同

        事件类似于Windows里的消息,它的发出者一般是窗口系统。相对信号和槽机制,它比较“底层”,它同时支持异步和同步的通信机制,一个事件产生时将被放到事件队列里,然后我们就可以继续执行该事件“后面”的代码。事件的机制是非阻塞的。

        信号和槽机制相对而言比较“高层”,它的发出者一般是对象。从本质上看,它类似于传统的回调机制,是不支持异步调用的。

        举个例子,在QApplication中有两个投送事件的方法:postEvent ()和sendEvent(),它们分别对应Windows中的PostMessage()和SendMessage(),就是是异步调用和同步调用,一个等待处理完后返回,一个只发送而不管处理完与否就返回。

        在应用中,涉及到底层通信时,往往使用事件的时候比较多,但有时也会用到信号和槽。

    ⑶ 信号与槽在多线程时支持异步调用

        在单线程应用时,你可以把信号与槽看成是一种对象间的同步通信机制,这是因为在这种情况下,信号的释放过程是阻塞的,一定要等到槽函数返回后这个过程才结束,也就是不支持异步调用。

        从Qt4开始,信号和槽机制被扩展为可以支持跨线程的连接,通过这种改变,信号与槽也可以支持异步调用了,这方面的内容涉及到多线程的很多知识,读者感兴趣的话,可以参阅《C++ GUI Qt4编程》中的相关内容。

    参考:http://blog.csdn.net/qter_wd007/article/details/6838524

  • 相关阅读:
    POJ 1401 Factorial
    POJ 2407 Relatives(欧拉函数)
    POJ 1730 Perfect Pth Powers(唯一分解定理)
    POJ 2262 Goldbach's Conjecture(Eratosthenes筛法)
    POJ 2551 Ones
    POJ 1163 The Triangle
    POJ 3356 AGTC
    POJ 2192 Zipper
    POJ 1080 Human Gene Functions
    POJ 1159 Palindrome(最长公共子序列)
  • 原文地址:https://www.cnblogs.com/findumars/p/4702818.html
Copyright © 2011-2022 走看看