Qt自定义事件

14 篇文章 0 订阅

尽管 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 值的指定。这个函数是线程安全的,不必另外添加同步。

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

第一种方式:

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

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

QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);

第二种方式:

QMouseEvent event(QEvent::MouseButtonPress, pos, 0, 0, 0);
QApplication::sendEvent(mainWindow, &event);

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

因为 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 手册。

现在,我们已经能够自定义事件对象,已经能够将事件发送出去,还剩下最后一步:处理自定义事件。即是注册一个事件,事件通过信史发送出去,(好比一个项目下来了,客户提需求,项目经理负责发送下去,剩下的你们就开始执行了),接下来我们就需要定义一个类来实现自定义事件,下面我写一个demo

#include "mydefineevent.h"
#include <QApplication>
#include <qevent.h>
#include <qdebug.h>

//注册事件值
static const QEvent::Type MyEventType = (QEvent::Type)QEvent::registerEventType(QEvent::User+100);
//子类化我的事件
class MyEvent: public QEvent
{
public:
    MyEvent(Type MyEventType):QEvent(MyEventType){}
};


//信使
class MySender: public QCoreApplication
{
public:
    MySender(int argc,char *argv[]):QCoreApplication(argc,argv){}

public:
    bool notify(QObject *receiver, QEvent *event);

};

bool MySender::notify(QObject *receiver, QEvent *event)
{
    // receiver->event(event);
    if(event->type() == MyEventType)
    {
        qDebug()<<"MyEventType is coming!";
       // return true;
        /*这里不能return true,因为重写notify就是在事件被向下传递之前截住它,
        随便搞它,搞完了还得给QCoreApplication::notify向下传递,
               */
    }
    return QCoreApplication::notify(receiver,event);
}

//干活的函数
class MyArmy: public QObject
{
public:
    void MyEventHandler(QEvent *event);
    bool event(QEvent *event);
};
void MyArmy::MyEventHandler(QEvent *event)
{
    qDebug()<<"The event is being handled!";
    event->accept();
}

//自定义事件的处理函数
 bool MyArmy::event(QEvent *event)
{
    if(event->type() == MyEventType)
    {
        qDebug()<<"event() is dispathing MyEvent";
        MyEventHandler(event);//调用事件处理函数
        if((MyEvent*)event->isAccepted())
        {
            qDebug()<<"The event has been handled!";
            return true;
        }
    }
    return QObject::event(event);
}
//监控者
class MyWatcher: public QObject
{
public:
    bool eventFilter(QObject *watched, QEvent *event);
};

bool MyWatcher::eventFilter(QObject *watched, QEvent *event)
{
    //监控并不处理
    if(event->type() == MyEventType)
    {
        qDebug()<<"I don't wanna filter MyEventType";
        return false;
    }
    return QObject::eventFilter(watched,event);
}



int main(int argc, char *argv[])
{
//    QApplication a(argc, argv);
//    myDefineEvent w;
//    w.show();

//    return a.exec();
    MySender mySender(argc,argv);

    MyArmy myArmy;
    MyWatcher myWatcher;
    myArmy.installEventFilter(&myWatcher);//安装事件过滤器

    MyEvent myEvent(MyEventType);
    //mySender.sendEvent(&myArmy,&myEvent);//事件的接受者,事件的类型事件发送下去,重写这个事件就可以执行相关操作
    mySender.postEvent(&myArmy,new MyEvent(MyEventType),Qt::NormalEventPriority);
    qDebug()<<"size :"<<sizeof(myEvent);
    return mySender.exec();//程序将进入事件循环来监听应用程序的事件

}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

漫天飞舞的雪花

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

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

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

打赏作者

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

抵扣说明:

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

余额充值