【Qt笔记】自定义事件

尽管 Qt 已经提供了不少事件,但对于更加变幻无穷的需求来讲,有限的事件都是不够的。例如,我要支持一种新的设备,这个设备提供一种崭新的交互方式,那么,这种事件如何处理呢?因此,容许建立本身的事件 类型也就势在必行。即使是不说那种很是极端的例子,在多线程的程序中,自定义事件也是尤为有用。固然,事件也并非局限在多线程中,它能够用在单线程的程序中,做为一种对象间通信的机制。那么,为何我须要使用事件,而不是信号槽呢?主要缘由是,事件的分发既能够是同步的,又能够是异步的,而函数的调用或者说是槽的回调老是同步的。事件的另一个好处是,它可使用过滤器。安全

 

Qt 自定义事件很简单,同其它类库的使用很类似,都是要继承一个类进行扩展。在 Qt 中,你须要继承的类是QEvent多线程

继承QEvent类,最重要的是提供一个QEvent::Type类型的参数,做为自定义事件的类型值。回忆一下,这个 type 是咱们在处理事件时用于识别事件类型的代号。好比在event()函数中,咱们使用QEvent::type()得到这个事件类型,而后与咱们定义的实际类型对比。异步

QEvent::TypeQEvent定义的一个枚举。所以,咱们能够传递一个 int 值。可是须要注意的是,咱们的自定义事件类型不能和已经存在的 type 值重复,不然会有不可预料的错误发生。由于系统会将你新增长的事件当作系统事件进行派发和调用。在 Qt 中,系统保留 0 – 999 的值,也就是说,你的事件 type 要大于 999。这种数值固然很是难记,因此 Qt 定义了两个边界值:QEvent::UserQEvent::MaxUser。咱们的自定义事件的 type 应该在这两个值的范围之间。其中,QEvent::User的值是 1000,QEvent::MaxUser的值是 65535。从这里知道,咱们最多能够定义 64536 个事件。经过这两个枚举值,咱们能够保证咱们本身的事件类型不会覆盖系统定义的事件类型。可是,这样并不能保证自定义事件相互之间不会被覆盖。为了解决这个问题,Qt 提供了一个函数:registerEventType(),用于自定义事件的注册。该函数签名以下:函数

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

这个函数是 static 的,所以可使用QEvent类直接调用。函数接受一个 int 值,其默认值是 -1;函数返回值是向系统注册的新的 Type 类型的值。若是 hint 是合法的,也就是说这个 hint 不会发生任何覆盖(系统的以及其它自定义事件的),则会直接返回这个值;不然,系统会自动分配一个合法值并返回。所以,使用这个函数便可完成 type 值的指定。这个函数是线程安全的,没必要另外添加同步。post

咱们能够在QEvent子类中添加本身的事件所须要的数据,而后进行事件的发送。Qt 中提供了两种事件发送方式:线程

static bool QCoreApplication::sendEvent(QObject *receiver,
                                        QEvent *event);

1. 直接将event事件发送给receiver接受者,使用的是QCoreApplication::notify()函数。函数返回值就是事件处理函数的返回值。在事件被发送的时候,event对象并不会被销毁。一般咱们会在栈上建立event对象,例如:code

QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);
static void QCoreApplication::postEvent(QObject *receiver,
                                        QEvent *event);

2. 将event事件及其接受者receiver一同追加到事件队列中,函数当即返回。orm

由于 post 事件队列会持有事件对象,而且在其 post 的时候将其 delete 掉,所以,咱们必须在堆上建立event对象。当对象被发送以后,再试图访问event对象就会出现问题(由于 post 以后,event对象就会被 delete)。对象

当控制权返回到主线程循环时,保存在事件队列中的全部事件都经过notify()函数发送出去。继承

事件会根据 post 的顺序进行处理。若是你想要改变事件的处理顺序,能够考虑为其指定一个优先级。默认的优先级是Qt::NormalEventPriority

这个函数是线程安全的。

Qt 还提供了一个函数:

static void QCoreApplication::sendPostedEvents(QObject *receiver,
                                               int event_type);

这个函数的做用是,将事件队列中的接受者为receiver,事件相似为 event_type 的全部事件当即发送给 receiver 进行处理。须要注意的是,来自窗口系统的事件并不禁这个函数进行处理,而是processEvent()。详细信息请参考 Qt API 手册。

如今,咱们已经可以自定义事件对象,已经可以将事件发送出去,还剩下最后一步:处理自定义事件。处理自定义事件,同前面咱们讲解的那些处理方法没有什么区别。咱们能够重写QObject::customEvent()函数,该函数接收一个QEvent对象做为参数:

void QObject::customEvent(QEvent *event);

咱们能够经过转换 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);
}
相关文章
相关标签/搜索