QEvent

在Qt中,事件也是对象,派生于抽象事件类:QEvent,表示了程序需要知道的某件事情在程序内部或者在


外部是否发生发生.时间可以被QObject的子类接收,但是他们格外与UI框架类相关.这篇文章描述了事


件在一个普通的程序是怎么传递和使用的.


1.怎么传递
当事件发生时,Qt 构造了一个事件类去表示他,这个通过构造了一个合适的QEvent子类,并通过调用


event函数把它传递给特殊的QObject(或者他的子类)实例.
这个函数自己不操作时间.基于传递事件的类型,它为特定的事件类型调用了一个事件处理器.并基于


这个事件是否已经被接收或忽略发送一个响应.
一些事件,比如QMouseEvent 和 QKeyEvent,来自于窗口系统;而一些事件,比如QTimerEvent,来至于其


他的事件源,还有一些来至程序内部.


2.事件的类型
许多事件类型,拥有专门的类,典型如


QResizeEvent,QPaintEvent,QMouseEvent,QKeyEvent,QCloseEvent.每个类都派生于QEvent并且添加


了特定的函数.比如,QResizeEvvent 添加了,size()和oldSize(),来让窗口们知道他们的尺寸是怎么


变化的.


一些类不仅仅支持实际的一种事件类型,QMouseEvent就能支持鼠标按钮的点击,双击,移动和其他的操
作.
每个事件都有一个相关的类型,在QEvent::Type中定义,这能作为一个方便的执行时信息来源,去快速


确定哪一个被给予的事件子类从来生成的.


因为程序需要在多样和复杂的方式下互动,QT的事件传递机制是非常的灵活的.描述


QCoreApplication::notify的文档简明的描述了整个传递流程;Qt的季刊文章Another Look at 


Events又描述了对它的修改,这里足够让我们去解释95%的程序.


一个处理事件的常用的方法是调用一个虚函数,比如,QPaintEvent被QWidget::paintEvent.这个虚函


数很负责任的适当响应,通常通过重新绘制窗口,如果你并不需要在你的虚函数实现中执行所有的必须


工作.你或许需要调用基础的类实现.
举个例子,下面代码处理鼠标左键在一个复选框上,而其他的处理则传递给基类QCheckBox


void MyChectBox::mousePressEvent(QMouseEvent* event)
{
 if(event->button() == Qt::LeftButton)
{
//这里处理左点击
}else{
//其他处理交给基类
QCheckBox::mousePressEvent(Event)
}
}


如果你需要代替基类的处理函数,你必须自己去完全实现他们.怎么说呢,如果你仅为了扩展基类的功


能,那么你去实现你自己需要的功能,而其他的就交给基类的默认处理吧.


这些对象能够实现QObject::event(),作为主要的的事件处理器,并且在通常处理之前或者之后处理他


们的事件或者他们替代整个函数功能.一个非典型的框架既实现Tab键又拥有一个程序特定的自定义时


间:
bool MyWidget::event(QEvent * event)
{
if(event->type()) == QEvent::KeyPress
{
QKeyEvent * ke = static_case<QkeyEvent *>(event)
if(ke - > key() == Qt::Key_Tab)
{
//这里加入你的处理代码
return true;
}
}else if(event->type() == MyCustomEventType)
       {
    MyCustomEvent * myEvent = staic_cast<MyCustomEvent*>(event);
    //为你自定义的事件加入处理代码
    return true;
       }
return QWiget::event(event);
}
注意QWiget::event()依然处理了没有被处理的事件,返回的值指定了这个事件是否被处理,如果是


true那么这个事件在传递给其他的类之前就被阻止了.


Event Fiters(事件过滤器)
某些时候一个类需要监控或者说拦截被传递给其他类的事件,比如说,一个dialog需要拦截按钮事件传


递给其他的widget;再比如,修改Return-key的处理方式.


QObject::installEventFilter()函数通过安装一个事件过滤器帮我们实现了上述可能.致使一个当前


被安装的过滤器类在其QObject::eventFiter函数中收到传递给目标类的事件.一个事件过滤器将在目


标类之前就处理这个时间,这期间,类将被授权去检查和抛弃这个类.一个已经存在的事件过滤器能够


通过QObject::removeEventFiter()函数去卸载它.
当一个过滤器类的evnetFilter()函数被调用了,它就能够接受或者拒收这个事件,能够允许继续或者


不在处理这个时间,如果所有的时间过滤器允许目标类继续处理这个事件,那么就返回false,然后这个


事件就会派送给目标类继续处理.如果它通过返回true来停止继续处理这个事件,那么目标类或者后继


的事件过滤器就收不到这个事件了


bool Filter::Object::eventFilter(QObject* objcet,QEvent * event)
{
if(object == target && event->type() == QEvent::KeyPress)
{
QKeyEvent * keyEvent = static_cast <QKeyEvent *>(event);
if(keyEvent->key() == Qt::Key_table)
{
//加入需要对tab键处理的代码
return true;
}else
return false;
}
return false;
}


上面的代码给出了其他的方式去阻止Tab键事件传递给其他的widget.这种情况下,过滤器处理相关的


类并返回true去阻止他们在其他的类中被处理.对于不需要拦截的事件,我们返回false让他们到目的


类中处理,当然这也需要经过其他类的过滤器.
当然,过滤所有程序的事件也是可能的,通过在QApplication或者QCoreApplication类中,这种全局化


的事件过滤器在特定类的过滤器过滤前就已经执行了.这非常的强大,但它也减慢了每个特定的时间的


传递速度;技术讨论其应该一致被其他的方式替代.


发送事件
许多程序需要创造和发送他们自己的事件.你可以与Qt事件循环完全相同的方式发送事件,通过构造一


个合适的事件对象并用QCoreApplication::sendEvent和 QCoreApplication::postEvent发送。
sendEvent()立刻处理事件.当其返回的时候,过滤器或类本身已经处理完这个事件.对于许多事件处理


器,一个叫 isAccepted()的函数能告诉你这个事件是否被接收或者拒绝,通过最后一个处理函数的结


果.


postEvent 发布这个时间在事件队列上用于稍后的派送.稍后Qt的主事件循环运行的时候,循环派送所


有的类型的事件,处于某些最优化的目的.比如说,这里有几个resize时间,它们将被压缩成为一个,同


样的处理也被应用至paint事件:QWidget::update()调用的就是postEvent(),这样就消除了闪烁并且


避免不停的重绘提高了速度.


postEvent() 同样在类的初始化时也被类使用.因为派送事件在每个类初始化之后就派送了出去.当应


用一个框架类时,意识到一点:事件能在框架生存周期内够极早的传递出去.在它的构造函数中,,在他


们接收到一个事件之前,一定要早点初始化成员变量.


构造一个自定义的事件类型,你需要定义一个事件的编号,这必须大于QEvent::User.而且为了传递特


定的自定义事件信息,你需要继承至QEvent这个类.这点,请参考QEvent文档说明了解详细的信息.
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值