Qt学习之路(23):自定义事件

Qt允许你创建自己的事件类型,这在多线程的程序中尤其有用,当然,也可以用在单线程的程序中,作为一种对象间通讯的机制。那么,为什么我需要使用事件,而不是使用信号槽呢?主要原因是,事件的分发既可以是同步的,又可以是异步的,而函数的调用或者说是槽的回调总是同步的。事件的另外一个好处是,它可以使用过滤器。

Qt中的自定义事件很简单,同其他类似的库的使用很相似,都是要继承一个类进行扩展。在Qt中,你需要继承的类是QEvent。注意,在Qt3中,你需要继承的类是QCustomEvent,不过这个类在Qt4中已经被废除(这里的废除是不建议使用,并不是从类库中删除)。

继承QEvent类,你需要提供一个QEvent::Type类型的参数,作为自定义事件的类型值。这里的QEvent::Type类型是QEvent里面定义的一个enum,因此,你是可以传递一个int的。重要的是,你的事件类型不能和已经存在的type值重复,否则会有不可预料的错误发生!因为系统会将你的事件当做系统事件进行派发和调用。在Qt中,系统将保留0 - 999的值,也就是说,你的事件type要大于999. 具体来说,你的自定义事件的type要在QEvent::User和QEvent::MaxUser的范围之间。其中,QEvent::User值是 1000,QEvent::MaxUser的值是65535。从这里知道,你最多可以定义64536个事件,相信这个数字已经足够大了!但是,即便如此,也只能保证用户自定义事件不能覆盖系统事件,并不能保证自定义事件之间不会被覆盖。为了解决这个问题,Qt提供了一个函数:registerEventType(),用于自定义事件的注册。该函数签名如下:

static int QEvent::registerEventType ( int hint = -1 );

函数是static的,因此可以使用QEvent类直接调用。函数接受一个int值,其默认值为-1,返回值是创建的这个Type类型的值。如果hint是合法的,不会发生任何覆盖,则会返回这个值;如果hint不合法,系统会自动分配一个合法值并返回。因此,使用这个函数即可完成type值的指定。这个函数是线程安全的,因此不必另外添加同步。

你可以在QEvent子类中添加自己的事件所需要的数据,然后进行事件的发送。Qt中提供了两种发送方式:

* static bool QCoreApplication::sendEvent(QObjecy * receiver, QEvent * event):事件被QCoreApplication的notify()函数直接发送给receiver对象,返回值是事件处理函数的返回值。使用这个函数必须要在栈上创建对象,例如:

QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);

QApplication::sendEvent(mainWindow, &event);

* static bool QCoreApplication::postEvent(QObject * receiver, QEvent * event):事件被QCoreApplication追加到事件列表的最后,并等待处理,该函数将事件追加后会立即返回,并且注意,该函数是线程安全的。另外一点是,使用这个函数必须要在堆上创建对象,例如:

QApplication::postEvent(object, new MyEvent(QEvent::registerEventType(2048)));

这个对象不需要手动delete,Qt会自动delete掉!因此,如果在post事件之后调用delete,程序可能会崩溃。另外,postEvent()函数还有一个重载的版本,增加一个优先级参数,具体请参见API。通过调用sendPostedEvent()函数可以让已提交的事件立即得到处理。

如果要处理自定义事件,可以重写QObject的customEvent()函数,该函数接收一个QEvent对象作为参数。注意,在Qt3中这个参数是QCustomEvent类型的。你可以像前面介绍的重写event()函数的方法去重写这个函数:

void CustomWidget::customEvent(QEvent *event) {
 CustomEvent *customEvent = static_cast<CustomEvent *>(event);
 // ....
}

另外,你也可以通过重写event()函数来处理自定义事件:

bool CustomWidget::event(QEvent *event) {
 if (event->type() == MyCustomEventType) {
  CustomEvent *myEvent = static_cast<CustomEvent *>(event);
   // processing...
  return true;
 }
  return QWidget::event(event);
}

这两种办法都是可行的。

好了,至此,我们已经概略的介绍了Qt的事件机制,包括事件的派发、自定义等一系列的问题。下面的章节将继续我们的学习之路!

出处:http://devbean.blog.51cto.com/448512/232314

时间: 2024-09-12 23:04:32

Qt学习之路(23):自定义事件的相关文章

Qt 学习之路 2 --- 读书笔记

一.文章来由 来自豆子老师非常好的一本Qt教程,但是只有网络版,所以用这个做笔记了,不动笔墨不读书嘛~~ 二.读书笔记 1.Qt 学习之路 2(2):Qt 简介 1.1 关于 Qt 的一站式解决 Qt 是一个著名的 C++ 应用程序框架.但并不只是一个 GUI 库,因为 Qt 十分庞大,并不仅仅是 GUI 组件.使用 Qt,在一定程度上你获得的是一个"一站式"的解决方案:不再需要研究 STL,不再需要 C++ 的,不再需要到处去找解析 XML.连接数据库.访问网络的各种第三方库,因为

Qt学习之路(21):event()

今天要说的是event()函数.记得之前曾经提到过这个函数,说在事件对象创建完毕后,Qt将这个事件对象传递给QObject的event()函数. event()函数并不直接处理事件,而是将这些事件对象按照它们不同的类型,分发给不同的事件处理器(event handler). event() 函数主要用于事件的分发,所以,如果你希望在事件分发之前做一些操作,那么,就需要注意这个event()函数了.为了达到这种目的,我们可以重写 event()函数.例如,如果你希望在窗口中的tab键按下时将焦点移

Qt学习之路(3):Hello,world!(续)

下面来逐行解释一下前面的那个Hello, world!程序,尽管很简单,但却可以对Qt程序的结构有一个清楚的认识.现在再把代码贴过来: #include <QApplication> #include <QLabel> int main(int argc, char *argv[]) { QApplication app(argc, argv); QLabel *label = new QLabel("Hello, world!"); label->sho

Qt学习之路(19):事件(event)

前面说了几个标准对话框,下面不打算继续说明一些组件的使用,因为这些使用很难讲完,很多东西都是与实际应用相关的.实际应用的复杂性决定了我们根本不可能把所有组件的所有使用方法都说明白.这次来说说Qt相对高级一点的特性:事件. 事件(event)是有系统或者Qt本身在不同的时刻发出的.当用户按下鼠标,敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件是在对用户操作做出响应的时候发出,如键盘事件等:另一些事件则是由系统自动发出,如计时器事件. 一般来说,使用Qt编程时,我们并不会把

Qt学习之路(20):事件接收与忽略

本章内容也是关于Qt事件.或许这一章不能有一个完整的例子,因为对于事件总是感觉很抽象,还是从底层上理解一下比较好的吧! 前面说到了事件的作用,下面来看看我们如何来接收事件.回忆一下前面的代码,我们在子类中重写了事件函数,以便让这些子类按照我们的需要完成某些功能,就像下面的代码: void MyLabel::mousePressEvent(QMouseEvent * event) { if(event->button() == Qt::LeftButton) { // do something }

Qt学习之路(24):QPainter

多些大家对我的支持啊!有朋友也提出,前面的几节有关event的教程缺少例子.因为event比较难做例子,也就没有去写,只是把大概写了一下.今天带来的是新的部分,有关Qt的2D绘图.这部分不像前面的内容,还是比较好理解的啦!所以,例子也会增加出来. 有人问豆子拿Qt做什么,其实,豆子就是在做一个Qt的画图程序,努力朝着Photoshop和GIMP的方向发展.但这终究要经过很长的时间.很困难的路程的,所以也放在网上开源,有兴趣的朋友可以来试试的呀- 好了,闲话少说,来继续我们的学习吧! Qt的绘图系

Qt学习之路(22):事件过滤器

Qt创建了QEvent事件对象之后,会调用QObject的event()函数做事件的分发.有时候,你可能需要在调用event()函数之前做一些另外的操作,比如,对话框上某些组件可能并不需要响应回车按下的事件,此时,你就需要重新定义组件的event()函数.如果组件很多,就需要重写很多次 event()函数,这显然没有效率.为此,你可以使用一个事件过滤器,来判断是否需要调用event()函数. QOjbect有一个eventFilter()函数,用于建立事件过滤器.这个函数的签名如下: virtu

Qt学习之路(12):菜单和工具条

在前面的QMainWindow的基础之上,我们开始着手建造我们的应用程序.虽然现在已经有一个框架,但是,确切地说我们还一行代码没有写呢!下面的工作就不那么简单了!在这一节里面,我们要为我们的框架添加菜单和工具条. 就像Swing里面的Action一样,Qt里面也有一个类似的类,叫做QAction.顾名思义,QAction类保存有关于这个动作,也就是action的信息,比如它的文本描述.图标.快捷键.回调函数(也就是信号槽),等等.神奇的是,QAction能够根据添加的位置来改变自己的样子 --如

Qt学习之路(11):MainWindow

尽管Qt提供了很方便的快速开发工具QtDesigner用来拖放界面元素,但是现在我并不打算去介绍这个工具,原因之一在于我们的学习大体上是依靠手工编写代码,过早的接触设计工具并不能让我们对Qt的概念突飞猛进-- 前面说过,本教程很大程度上依照的是<C++ GUI Programming with Qt4, 2nd Edition>这本书.但是,这本书中接下来的部分用了很大的篇幅完成了一个简单的类似Excel的程序.虽然最终效果看起来很不错,但我并不打算完全依照这个程序来,因为这个程序太大,以至于