除了信号槽,Qt也使用了另一种手段来响应对象,即事件。比如鼠标左键按下事件,键盘某一个按键按下事件。 Qt的主循环QCoreapplication::exec()就是一个事件循环,这个循环捕获本地计算机产生的各种事件然后将这些事件存放到事件队列中,按照FIFO的顺序将每一个事件传递给相应的对象(QObject)。 事件队列中的事件被传递给QObject::event()函数,这个函数是一个集中分配营,它判断参数是哪种类型的事件,然后将该事件传递给相应的事件处理函数进行处理。而event本身并不对事件进行处理 。
事件的传播顺序: 1. 在QCoreApplication::exec()主循环中,Qt捕获计算机产生的各种事件,如果在此之前还有其他事件没有分配,就暂时将该事件放到事件队列中,随后再按照FIFO顺序一个个传播。 2. 事件经过一系列传播后到达该类的事件过滤器eventFilter(),这个函数对该事件进行过滤,如果返回true则传播终止。返回false则告诉Qt不过滤这个事件,继续传播。 3. 如果没有过滤掉,则随后会传播到该类的event()函数(或其父类),在这个函数中会根据事件的所属类型进行分配,调用相应的事件处理函数。如果不需要再向它的父类传播这个事件,则返回true告诉Qt应该处理完这个事件了。否则,调用父类的event函数来保证由父类来处理这个事件,防止其他类型的事件被忽略掉。 4. 特定的事件处理函数进行处理。
接下来我们逐个讨论这几个函数:
eventFilter
bool QObject::eventFilter(QObject *watched, QEvent *event)事件过滤函数,会在event函数之前被调用。返回true则告诉Qt事件被过滤掉,反之继续传播给event函数。通常的实现形式为:
/*判断对象指针watched是否是需要过滤掉事件的那个对象*//*通常和this比较或者和该类的某个成员变量比较*/if(watched == this) //或 if(watched == m_watched){ /*判断事件类型是否是需要过滤的事件*/ if(event->type() == /*某个事件类型*/ ) { return true; }}return false;event
bool QObject::event(QEvent *e)如果成功分配掉事件则返回true;否则,调用父类的event函数防止其他类型事件被忽略掉。通常的实现形式为:
if(e->type() == /*event 1*/){ doThings1(); return true;}else if(e->type() == /*event 2*/){ doThings2(); return true;}//...关心的几个类型的事件分配return QWidget::event(e); //调用父类的函数然后就是特定的事件处理函数,举个例子,如果我们需要对鼠标点击事件进行自定义的处理,那么我们就需要在自定义类中重新实现mousePRessEvent()函数。又因为这个函数是父类的虚函数,我们无需重新实现event()函数,所以可以像这样:
//.h#include <QWidget>#include <QLabel>class MyClass : public QWidget{ Q_OBJECTpublic: MyClass(QWidget *parent = 0);protected: void mousePressEvent(QMouseEvent *event);private: QLabel *label;};//.cppMyClass::MyClass(QWidget *parent) :QWidget(parent){ label = new QLabel(); setCentralWidget(label);}void MyClass::mousePressEvent(QMouseEvent *event){ label->setText(QString("[%1, %2]") .arg(event->x(), event->y()));}新闻热点
疑难解答