Qt 自定义事件的实现

初学Qt,用了Qt自带的事件,然后想怎么才能定义自己的事件呢?又如何使用自定义事件呢?看了篇文章,说先要子类化QEvent,然后定义自己的QEvent::Type,然后重写QWidget::event()函数,然后就可以调用QCoreApplication::sendEvent()或者QCoreApplication:;postEvent()发送事件就好了。但我比较笨,还是云山雾罩,不知道怎么下手。

怎么子类化QEvent?在哪里定义自己的QEvent::Type?在哪里重写QWidget::event()函数?在哪里调用QCoreApplication::sendEvent()或者QCoreApplication:;postEvent()发送事件?

在百度里搜索开了篇文章对我有启发http://bluemask.net/p/1215/ ,在google中搜索how to subclass QEvent也搜到一篇对我有启发的http://www.java2s.com/Code/Cpp/Qt/SubclassQEvent.htm 。(google的英文搜索真不错!)

后来我就想,那Qt的发明人是怎么定义事件的呢?其实站在Qt发明人的角度,QEvent就是他们的“自定义事件”!Ok!这就好办了!看看Qt发明人怎么定义的QEvent,看看他们怎么用自己定义的QEvent,不就回答了文章开头的俩问题了嘛!O(∩_∩)O~

我把整个过程总结为“长官定义事件”----->“信使传递事件”---->“军队接收并响应事件”。

我通过Qt Assistant查找那些与事件相关的类,总结如下:

1、Qt中定义事件的长官:QEvent

QEvent的任务就是定义一些事件类型Type,它们都定义在了一个enum里。这就是教程中告诉我们的要子类化QEvent,派生出MyEvent,然后在MyEvent中定义事件类型QEvent::Type。

我们子类化的时候模仿一个QEvent就好了,而且是继承,好些都不用子类做了,看一下QEvent类中的成员变量和成员函数,就这些东西:

好了,我们通过子类化QEvent,把派生出来的MyEvent看做长官,它定义了具体某个事件。下面看谁是信使。

2、Qt中传递事件的信使:QCoreApplication(QApplication继承自QCoreApplication)

我们看看QCoreApplication中定义的一些函数,这些函数就是我们经常遇到的那些与传递事件和过滤事件有关的函数,见下图:

Public Functions

Static Public Members:

所以,到这里我们就可以明确了,你要用QCoreApplication的static public类型的函数入sendEvent或postEvent函数来传递送信,要注意:当使用sendEvent时,你的事件要在栈上建立sendEvent会直接调用notify把事件传递给士兵,不走事件队列;而用postEvent时,你的事件要在堆上建立,即要用new来创建postEvent会把你的事件追加进事件队列(详细过程请看http://blog.csdn.net/michealtx/article/details/6865891)。你还可以通过重载notify来影响送信过程。

注意C++:在函数内下列声明

一种是在栈上创建类对象,形式如下:CSomeClass someObject;

一种是在堆上创建(动态分配),形式如下:CSomeClass *pSomeObject = new CSomeClass();

具体一定要看这一篇文章:https://www.devbean.net/2014/02/cpp-create-object-on-heap-or-stack/    《C++:在堆上创建对象,还是在栈上?》

3、Qt中接收响应事件的军队:QWidget(这是Qt中的widget之母,诸如QMainWindow、QPushBUtton等等都是继承自QWidget)

我们看看QWidget中与事件有关的成员:

看到了吗?这些就是event handler,即事件处理函数,这是干活的那帮人。里面有我们熟悉的mousePressEvent()、keyPressEvent()等常用的事件处理函数,它们都是protected virtual 类型的,可以重载。所以呀,我们可以子类化QWidget,从而继承得到好些个event handler,当然也可以自己定义event handler!相当于自己创造士兵来响应事件。通过山寨QWidget,就可以创造自己的军队!

还有一点就是,当事件到达军队的时候,要先审查再分发,审查就是要经过事件过滤,分发就是通过对经过审查的事件进行判断再把它分给那个相应的士兵这就又涉及到一个类QObject,这是Qt的万类之母,这个类中有两个函数一个是eventFilter(),另一个是event()。要先子类化QObject来创建一个监控者,这个监控者重载eventFilter(),来为军队过滤事件然后还要在军队(QWidget)通过调用installEventFilter ( QObject * filterObj )来安装过滤器参数中的filterOb即为监控者最后在军队(QWidget)中重载event()来分发事件,把事件分给对应会干这个活的士兵(event handler)。

好了,我理解的大体过程就是这样,我是Qt新手,可能有错的地方,希望路过的大牛能给与指正,我将不胜感激!

什么话也不如来个例程给力!:

我建立的是Qt Console Application,工程叫MyEvent,下面是main.cpp中的代码:

  1 #include <QtGui/QApplication>
  2 #include <QCoreApplication>
  3 #include <QEvent>
  4 #include <QObject>
  5 #include <QDebug>
  6 
  7 //声明、定义、注册自定义事件类型,事件ID为自定义事件ID起点QEvent::User +100=1100
  8 static const QEvent::Type MyEventType = (QEvent::Type)QEvent::registerEventType(QEvent::User+100);
  9 
 10 //长官
 11 class MyEvent: public QEvent
 12 {
 13 public:
 14     MyEvent(Type myeventtype):QEvent(myeventtype){}
 15 };
 16 
 17 //信使
 18 class MySender: public QCoreApplication
 19 {
 20 public:
 21     MySender(int argc,char *argv[]):QCoreApplication(argc,argv){}
 22 
 23 public:
 24     bool notify(QObject *receiver, QEvent *event);
 25 
 26 };
 27 
 28 bool MySender::notify(QObject *receiver, QEvent *event)
 29 {
 30     if(event->type() == MyEventType)
 31     {
 32         qDebug()<<"MyEventType is coming!";
 33         //return true;
 34         /*这里不能return true,因为重写notify就是在事件被向下传递之前截住它,
 35         随便搞它,搞完了还得给QCoreApplication::notify向下传递,除非在mySender.notify
 36         实现了事件向下传递的那一套。直接返回的话myArmy就收不到这个事件,因为执行完这个
 37         mySender.notify的return true后,事件传递被人为的在半截终止了
 38         (见Qt事件处理的五个层次http://blog.csdn.net/michealtx/article/details/6865891 )
 39         ,下面的myArmy的安装的过滤器和它自己的event都不会收到这个事件,更甭提最后干活
 40         的myEventHandler了。所以在主函数中执行完mySender.sendEvent把myEvent
 41         交给mySender.notify这个败家子儿后,就执行mySender.exec进入其它事件的循环了。这就是
 42         问题http://topic.csdn.net/u/20111012/19/78036d16-c163-40f9-a05c-3b7d6f4e9043.html
 43         出现的原因。感谢1+1=2大牛!非常感谢!
 44         */
 45     }
 46     return QCoreApplication::notify(receiver,event);
 47 }
 48 
 49 //军队
 50 class MyArmy: public QObject
 51 {
 52 public:
 53     void MyEventHandler(QEvent *event);//自定义事件函数
 54     bool event(QEvent *event);
 55 };
 56 
 57 void MyArmy::MyEventHandler(QEvent *event)
 58 {
 59     qDebug()<<"The event is being handled!";
 60     event->accept();
 61 }
 62 
 63 bool MyArmy::event(QEvent *event)
 64 {
 65     if(event->type() == MyEventType)
 66     {
 67         qDebug()<<"event() is dispathing MyEvent";
 68         MyEventHandler(event);//调用事件处理函数
 69         if((MyEvent*)event->isAccepted())
 70         {
 71             qDebug()<<"The event has been handled!";
 72             return true;
 73         }
 74     }
 75     return QObject::event(event);
 76 }
 77 
 78 //监控者
 79 class MyWatcher: public QObject
 80 {
 81 public:
 82     bool eventFilter(QObject *watched, QEvent *event);
 83 };
 84 
 85 bool MyWatcher::eventFilter(QObject *watched, QEvent *event)
 86 {
 87     if(event->type() == MyEventType)
 88     {
 89         qDebug()<<"I don't wanna filter MyEventType";
 90         return false;
 91     }
 92     return QObject::eventFilter(watched,event);
 93 }
 94 
 95 
 96 int main(int argc, char *argv[])
 97 {
 98     //QCoreApplication a(argc, argv);
 99     MySender mySender(argc,argv);
100 
101     MyArmy myArmy;
102     MyWatcher myWatcher;
103     myArmy.installEventFilter(&myWatcher);//安装事件过滤器
104 
105     MyEvent myEvent(MyEventType);
106     mySender.sendEvent(&myArmy,&myEvent);
107     return mySender.exec();
108 }

运行结果:

好了,就这样了!可能有错误或不准确的地方!望路过的大牛指点!

转自:http://blog.csdn.net/MichealTX/article/details/6866094

原文地址:https://www.cnblogs.com/liushui-sky/p/5733525.html