免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1464 | 回复: 0
打印 上一主题 下一主题

QT Embedded二三事之QObject的event [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2009-02-24 00:41 |只看该作者 |倒序浏览

                               
3. event机制
   在面象对象编程中,对象是核心。对象之间的需要通讯,对象A需要给对象B发消息。A对象向怎么才能向B对象发消息message? 一般需要把message定义成B对象的一个函数,然后由A对象调用b->message.这种实现不灵活,每个message都要定义函数。
   在UI系统中,不同的widget会经常发各种消息,要用上面的方式肯定是不行的。通常UI系统都会把这些消息和消息参数规范化。QT把消息类型和消息参数都封装到QEvent及其子类中,同时定义了QObject::event(QEvent *e)函数来处理各种QEvent,并且在此基础上实现了消息钩子和消息拦截等功能。这就是QT的event机制,下面详细介绍一下具体实现。
    
  1.QEvent
    QEvent封装了消息类型和消息参数,还有一些属性。下面是其实现代码:
class Q_EXPORT QEvent: public Qt                // event base class
{
public:
    enum Type {
 None = 0,                                // invalid event
 Timer = 1,                                // timer event
 MouseButtonPress = 2,                        // mouse button pressed
 MouseButtonRelease = 3,                        // mouse button released
 MouseButtonDblClick = 4,                // mouse button double click
 MouseMove = 5,                                // mouse move
 KeyPress = 6,                                // key pressed
 KeyRelease = 7,                                // key released
 FocusIn = 8,                                // keyboard focus received
 FocusOut = 9,                                // keyboard focus lost
 Enter = 10,                                // mouse enters widget
 Leave = 11,                                // mouse leaves widget
 ..................
 WindowStateChange = 96,                        // window state has changed
 IconDrag = 97,                          // proxy icon dragged
 User = 1000,                                // first user event id
 MaxUser = 65535                                // last user event id
    };
    QEvent( Type type ) : t(type), posted(FALSE), spont(FALSE) {}
    virtual ~QEvent();
    Type  type() const        { return t; }
    bool spontaneous() const         { return spont; }
protected:
    Type  t;
private:
    uint posted : 1;
    uint spont : 1;
    friend class QApplication;
    friend class QAccelManager;
    friend class QBaseApplication;
    friend class QETWidget;
};
 QEvent首先将各种消息编号,如KeyPress,KeyRelease,FocusIn,FocusOut,Show,并用变量t标识类型,同时还有两个属性:posted用来标识QEvent是由sendEvent发出还是由postEvent发出的;spont的含义不明,从代码上看,只有通过sendSpontaneousEvent发出的QEvent的spont才是true;
 
 2.QObject::event(QEvent *e)
 QObject::event是QT的消息处理函数。下面分析其实现:
bool QObject::event( QEvent *e )
{
#if defined(QT_CHECK_NULL)
    if ( e == 0 )
 qWarning( "QObject::event: Null events are not permitted" );
#endif
 //这里的消息钩子和消息拦截
    if ( eventFilters ) {                        // try filters
 if ( activate_filters(e) )                // stopped by a filter
     return TRUE;
    }
 //下面就是分发消息了
    switch ( e->type() ) {
    case QEvent::Timer:
 timerEvent( (QTimerEvent*)e );
 return TRUE;
    case QEvent::ChildInserted:
    case QEvent::ChildRemoved:
 childEvent( (QChildEvent*)e );
 return TRUE;
    case QEvent::DeferredDelete:
 delete this;
 return TRUE;
    default:
 if ( e->type() >= QEvent::User ) {
     customEvent( (QCustomEvent*) e );
     return TRUE;
 }
 break;
    }
    return FALSE;
}
    从实现上看,QObject::event函数相当于所有消息的一个分发函数,根据e->type的类型再分别调用,其相应的函数,如timerEvent,keyPressEvent等。
  3.消息钩子和消息拦截
    UI系统中,经常需要知道是否某一个widget收到某一类型的消息,例如没有focus的widget想接收当前keypress或keyrelease事件,这就需要在当前有foucs的widget上面安装一个钩子hook,并且在适当的时候截断这个消息,使得即使有focus的widget也不能收到事件。这就是消息钩子和消息拦截功能。在QT中,这是通过eventFilter来实现的。
 首先,需要调用QObject::installEventFilter安装eventFilter,即focuswidget->installEventFilter(nonfocuswidget)。
    下面,我们看看当有QEvent到来时发生了什么。根据QObject::event的实现,QObject::event会首先检查是否有eventFilter,如果有就会执行activate_filters,下面是activate_filters的实现。
bool QObject::activate_filters( QEvent *e )
{
    if ( !eventFilters )                        // no event filter
 return FALSE;
    QObjectListIt it( *eventFilters );
    register QObject *obj = it.current();
    while ( obj ) {                                // send to all filters
 ++it;                                        //   until one returns TRUE
 if ( obj->eventFilter(this,e) ) {
     return TRUE;
 }
 obj = it.current();
    }
    return FALSE;                                // don't do anything with it
}
    
    activate_filters会依次执行每个安装的QObject::eventFilter,这是一个虚函数。这样用户可以改eventFilter,加上自已的逻辑实现,这样nonfocuswidget就知道目前发生了一个keypress事件。
 从代码中,还可以看出,如果有一个eventFilter函数返回值是TRUE,将会停止执行eventFilter函数,并返加TRUE到QObject::event,然后QObject::event也不会继续执行,这样就使实现了消息拦截功能。
    4.QEvent与Win32的消息对比
 Win32中,也对所有的消息进行了封装,也有消息处理函数,不过Win32的实现与QT的实现差别还是很大的:
 (1)Win32提供的是C接口,所以没有把消息封装成类,这个即使是MFC也没有。Win32中,消息类型是一个UINT,消息参数固定成两个参数(WPARAM wParam, LPARAM lParam)。
 (2)Win32的消息处理函数WindowProc也是一个C接口的函数,它的原型如下:
 LRESULT CALLBACK WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
    其中uMsg是消息类型,wParam和lParam是两个消息参数。从这点来看,Win32的实现简洁一些。
 (3)Win32中的消息是围绕window定义,window是处理消息的主体。在QT中,消息处理定义到了QObject这一层,而不是在QWidget上,因此所有的QObject都可以处理消息。QT中的消息也不仅局限于窗口消息,如ChildInserted和ChildRemoved就是处理两个QObject之间父子关系的。
 (4)Win32中的消息钩子功能要比eventFilter强大,不公能拦截本进程内窗口的消息,还能拦截整个系统内所有窗口的消息。
 5.event和signal/slot的对比
 event和signal/slot都是QT提供的两种对象间通讯的方式,下面是一些不同点:
 (1)signal/slot的需要元对象模型的支持,需要声明Q_OBJECT。event与元对象模型无关。
 (2)emit signal是一种同步直接调用,对于event来说,sendEvent是同步直接调用,postEvent是异步调用。
 (3)用户可以自定义signal/slot的类型,event的类型都是提前定义好的,从这一点上看,signal/slot更为灵活。
 (4)signal/slot缺少消息钩子和消息拦截功能
               
               
               
               
               
               

本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u3/92787/showart_1840433.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP