Qt 学习之路:自定义事件
尽管 Qt 已经提供了很多事件,但对于更加千变万化的需求来说,有限的事件都是不够的。例如,我要支持一种新的设备,这个设备提供一种崭新的交互方式,那么,这种事件如何处理呢?所以,允许创建自己的事件 类型也就势在必行。即便是不说那种非常极端的例子,在多线程的程序中,自定义事件也是尤其有用。当然,事件也并不是局限在多线程中,它可以用在单线程的程序中,作为一种对象间通讯的机制。那么,为什么我需要使用事件,而不是信号槽呢?主要原因是,事件的分发既可以是同步的,又可以是异步的,而函数的调用或者说是槽的回调总是同步的。事件的另外一个好处是,它可以使用过滤器。
Qt 自定义事件很简单,同其它类库的使用很相似,都是要继承一个类进行扩展。在 Qt 中,你需要继承的类是QEvent。
继承QEvent类,最重要的是提供一个QEvent::Type类型的参数,作为自定义事件的类型值。回忆一下,这个 type 是我们在处理事件时用于识别事件类型的代号。比如在event()函数中,我们使用QEvent::type()获得这个事件类型,然后与我们定义的实际类型对比。
QEvent::Type是QEvent定义的一个枚举。因此,我们可以传递一个 int 值。但是需要注意的是,我们的自定义事件类型不能和已经存在的 type 值重复,否则会有不可预料的错误发生。因为系统会将你新增加的事件当做系统事件进行派发和调用。在 Qt 中,系统保留 0 – 999 的值,也就是说,你的事件 type 要大于 999。这种数值当然非常难记,所以 Qt 定义了两个边界值:QEvent::User和QEvent::MaxUser。我们的自定义事件的 type 应该在这两个值的范围之间。其中,QEvent::User的值是 1000,QEvent::MaxUser的值是 65535。从这里知道,我们最多可以定义 64536 个事件。通过这两个枚举值,我们可以保证我们自己的事件类型不会覆盖系统定义的事件类型。但是,这样并不能保证自定义事件相互之间不会被覆盖。为了解决这个问题,Qt 提供了一个函数:registerEventType(),用于自定义事件的注册。该函数签名如下:
|
1
|
static int QEvent::registerEventType ( int hint = -1 );
|
这个函数是 static 的,因此可以使用QEvent类直接调用。函数接受一个 int 值,其默认值是 -1;函数返回值是向系统注册的新的 Type 类型的值。如果 hint 是合法的,也就是说这个 hint 不会发生任何覆盖(系统的以及其它自定义事件的),则会直接返回这个值;否则,系统会自动分配一个合法值并返回。因此,使用这个函数即可完成 type 值的指定。这个函数是线程安全的,不必另外添加同步。
我们可以在QEvent子类中添加自己的事件所需要的数据,然后进行事件的发送。Qt 中提供了两种事件发送方式:
- 12static bool QCoreApplication::sendEvent(QObject *receiver,QEvent *event);
直接将
event事件发送给receiver接受者,使用的是QCoreApplication::notify()函数。函数返回值就是事件处理函数的返回值。在事件被发送的时候,event对象并不会被销毁。通常我们会在栈上创建event对象,例如:12QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);QApplication::sendEvent(mainWindow, &event); - 12static void QCoreApplication::postEvent(QObject *receiver,QEvent *event);
将
event事件及其接受者receiver一同追加到事件队列中,函数立即返回。因为 post 事件队列会持有事件对象,并且在其 post 的时候将其 delete 掉,因此,我们必须在堆上创建
event对象。当对象被发送之后,再试图访问event对象就会出现问题(因为 post 之后,event对象就会被 delete)。当控制权返回到主线程循环是,保存在事件队列中的所有事件都通过
notify()函数发送出去。事件会根据 post 的顺序进行处理。如果你想要改变事件的处理顺序,可以考虑为其指定一个优先级。默认的优先级是
Qt::NormalEventPriority。这个函数是线程安全的。
Qt 还提供了一个函数:
12static void QCoreApplication::sendPostedEvents(QObject *receiver,int event_type);这个函数的作用是,将事件队列中的接受者为
receiver,事件类似为 event_type 的所有事件立即发送给 receiver 进行处理。需要注意的是,来自窗口系统的事件并不由这个函数进行处理,而是processEvent()。详细信息请参考 Qt API 手册。
现在,我们已经能够自定义事件对象,已经能够将事件发送出去,还剩下最后一步:处理自定义事件。处理自定义事件,同前面我们讲解的那些处理方法没有什么区别。我们可以重写QObject::customEvent()函数,该函数接收一个QEvent对象作为参数:
|
1
|
void QObject::customEvent(QEvent *event);
|
我们可以通过转换 event 对象类型来判断不同的事件:
|
1
2
3
4
|
void CustomWidget::customEvent(QEvent *event) {
CustomEvent *customEvent = static_cast<CustomEvent *>(event);
// ...
}
|
当然,我们也可以在event()函数中直接处理:
|
1
2
3
4
5
6
7
8
|
bool CustomWidget::event(QEvent *event) {
if (event->type() == MyCustomEventType) {
CustomEvent *myEvent = static_cast<CustomEvent *>(event);
// processing...
return true;
}
return QWidget::event(event);
}
|
Qt 学习之路:自定义事件的更多相关文章
- Qt 学习之路 :事件
事件(event)是由系统或者 Qt 本身在不同的时刻发出的.当用户按下鼠标.敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件.一些事件在对用户操作做出响应时发出,如键盘事件等:另一些事 ...
- Qt 学习之路 :自定义只读模型
model/view 模型将数据与视图分割开来,也就是说,我们可以为不同的视图,QListView.QTableView和QTreeView提供一个数据模型,这样我们可以从不同角度来展示数据的方方面面 ...
- Qt 学习之路 2(23):自定义事件
Qt 学习之路 2(23):自定义事件 豆子 2012年10月23日 Qt 学习之路 2 21条评论 尽管 Qt 已经提供了很多事件,但对于更加千变万化的需求来说,有限的事件都是不够的.例如, ...
- Qt 学习之路 2(53):自定义拖放数据
Qt 学习之路 2(53):自定义拖放数据 豆子 2013年5月26日 Qt 学习之路 2 13条评论上一章中,我们的例子使用系统提供的拖放对象QMimeData进行拖放数据的存储.比如使用QM ...
- Qt 学习之路 2(18):事件
Home / Qt 学习之路 2 / Qt 学习之路 2(18):事件 Qt 学习之路 2(18):事件 豆子 2012年9月27日 Qt 学习之路 2 60条评论 事件(event)是由系统 ...
- Qt 学习之路 2(72):线程和事件循环
Qt 学习之路 2(72):线程和事件循环 <理解不清晰,不透彻> -- 有需求的话还需要进行专题学习 豆子 2013年11月24日 Qt 学习之路 2 34条评论 前面一章我 ...
- Qt 学习之路 2(50):自定义可编辑模型
Home / Qt 学习之路 2 / Qt 学习之路 2(50):自定义可编辑模型 Qt 学习之路 2(50):自定义可编辑模型 豆子 2013年5月13日 Qt 学习之路 2 13条评论 上一章我们 ...
- Qt 学习之路 2(49):自定义只读模型
Qt 学习之路 2(49):自定义只读模型 豆子 2013年5月5日 Qt 学习之路 2 18条评论 model/view 模型将数据与视图分割开来,也就是说,我们可以为不同的视图,QListView ...
- Qt 学习之路 2(22):事件总结
Qt 学习之路 2(22):事件总结 豆子 2012年10月16日 Qt 学习之路 2 47条评论 Qt 的事件是整个 Qt 框架的核心机制之一,也比较复杂.说它复杂,更多是因为它涉及到的函数众多,而 ...
- Qt 学习之路 2(19):事件的接受与忽略
Home / Qt 学习之路 2 / Qt 学习之路 2(19):事件的接受与忽略 Qt 学习之路 2(19):事件的接受与忽略 豆子 2012年9月29日 Qt 学习之路 2 140条评论 ...
随机推荐
- 学习总结之Log4NET
通过在网上查找了一些资料,用了些时间学习了log4NET,做了一个小小的总结,说一下它的特点吧 首先呢log4NET是.Net下一个非常优秀的开源日志记录组件.它可以将日志分成不同等级,也可以按照我们 ...
- 学习Swift -- 可选链
可空链式调用 可空链式调用是一种可以请求和调用属性.方法及下标的过程,它的可空性体现于请求或调用的目标当前可能为空(nil).如果可空的目标有值,那么调用就会成功:如果选择的目标为空(nil),那么这 ...
- ios8新特性widget开发-b
os8发布已经有一段时间了,伴随着ios8同时也出现了许多新的特性,ios系统将会越来越开放,这是好事.其中一个新特性就是在下拉通知栏里加入了个性的widget,开发者可以自己定义widget的样式内 ...
- JNI-Test
//testdll.h/* DO NOT EDIT THIS FILE - it is machine generated */ #include <jni.h> /* Header fo ...
- constant属性详解
/**是否使用开发模式,不在开发模式下变为false*/ (常用) <constant name = "struts.devmode" value = "true& ...
- Action类一般情况为何要继承ActionSupport
struts2中的action可以继承ActionSupport,也可以不继承ActionSupport.不继承ActionSupport的情况只需要有一个方法,返回String,即可,记住,在继承A ...
- BZOJ 4008 亚瑟王
Description 小K不慎被LL邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑. 他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂亮.众所周知,亚瑟王是一个看脸的游 ...
- 如何在DJANGO里,向有外键(一对多和多对多)的DB里插入数据?
需要插入的数据表结构如下: class UserInfo(models.Model): user_id =models.AutoField(primary_key=True) user_name=mo ...
- Error creating bean with name 'bookDao'
“Error creating bean with name 'bookDao' defined in ServletContext resource [/WEB-INF/applicationCon ...
- development period