[原]Qt事件处理机制浅析

[原]Qt事件处理机制浅析

 

[原]Qt事件处理机制浅析
    
事件处理机制浅析是通过WM_ACTIVATE消息来分析的
// 调用堆栈
WinMainCRTStartup()  
__tmainCRTStartup() 
WinMain()  
main(
int  argc = 1 char   **  argv)  
QtGuid4.dll
! QApplication::exec()  
QtCored4.dll
! QCoreApplication::exec()  
QtCored4.dll
! QEventLoop::exec()  
QtCored4.dll
! QEventLoop::processEvents()  
QtGuid4.dll
! QGuiEventDispatcherWin32::processEvents() 
QtCored4.dll
! QEventDispatcherWin32::processEvents()  
user32.dll
! _PeekMessageW@ 20 ()   // 说明1,调用PeekMessage,非阻塞的取消息!
QtGuid4.dll ! QtWndProc(HWND__  *  hwnd, unsigned  int  message = 6 , unsigned  int  wParam = 2 long  lParam = 0 )   // 即 WM_ACTIVATE 消息
QtGuid4.dll ! QApplication::winFocus(QWidget  *  widget,  bool  gotFocus = true )  
QtGuid4.dll
! QApplication::setActiveWindow(QWidget  *  act) 
QtCored4.dll
! QCoreApplication::sendSpontaneousEvent(QObject  *  receiver, QEvent  *   event )  
QtCored4.dll
! QCoreApplication::notifyInternal(QObject  *  receiver, QEvent  *   event )  
QtGuid4.dll
! QApplication::notify(QObject  *  receiver, QEvent  *  e)  
QtGuid4.dll
! QApplicationPrivate::notify_helper(QObject  *  receiver, QEvent  *  e) 
QtGuid4.dll
! QApplication:: event (QEvent  *  e)  
QtCored4.dll
! QCoreApplication:: event (QEvent  *  e)  
QtCored4.dll
! QObject:: event (QEvent  *  e) 


说明2:
//  QtWndProc() receives all messages from the main event loop
extern   " C "  LRESULT QtWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    
switch  (message) {
        
// case 消息的处理
        
// 1538行->1670行 
    }
    
if  ( ! widget)
        widget 
=  (QETWidget * )QWidget::find(hwnd);
    
if  ( ! widget)                                 //  don't know this widget
         goto  do_default;
        
    
if  (qt_is_translatable_mouse_event(message)) { 
            
// message=512 第3个消息
            
// #define WM_MOUSEFIRST 0x0200
            
// #define WM_MOUSEMOVE  0x0200
         if  ( ! qt_tabletChokeMouse) {
            result 
=  widget -> translateMouseEvent(msg);         //  mouse event
        }            
    }
    
else  {
        
switch  (message) {    
        
// message = 136 第4个消息  #define WM_SYNCPAINT 0x0088
        
// message = 133,第5个消息    #define WM_NCPAINT 0x0085 
        
// message = 28 ,第6个消息 #define WM_ACTIVATEAPP 0x001C
        
// message = 6  ,第7个消息 #define WM_ACTIVATE 0x0006 =>进入 qApp->winFocus(widget, true);  // 说明3    
        
// #define WM_NCHITTEST 0x0084 第1个消息,result = false, 进入do_default标记中的DefWindowProc处理
        
// #define WM_SETCURSOR 0x0020 第2个消息,result = false, 进入do_default标记中的DefWindowProc处理
         case  WM_NCHITTEST: 
        
case  WM_SETCURSOR: 
    }
    
if  (result)
        RETURN(
false );
do_default:
    RETURN(QWinInputContext::DefWindowProc(hwnd,message,wParam,lParam))            
}

// 说明3
void  QApplication::winFocus(QWidget  * widget,  bool  gotFocus)
{
    
if  (gotFocus) {
        setActiveWindow(widget);
    }
}    
void  QApplication::setActiveWindow(QWidget *  act)
{    
    
if  ( ! previousActiveWindow) {
        QEvent appActivate(QEvent::ApplicationActivate); 
// 关键是这里,appActivate 对象
        sendSpontaneousEvent(qApp,  & appActivate);
    }
   
for  ( int  i  =   0 ; i  <  toBeActivated.size();  ++ i) {  
           
// 这里会继续调用
        QWidget  * =  toBeActivated.at(i);
        sendSpontaneousEvent(w, 
& windowActivate);
        sendSpontaneousEvent(w, 
& activationChange);
    } 
    
}
inline 
bool  QCoreApplication::sendSpontaneousEvent(QObject  * receiver, QEvent  * event )

    
if  ( event event -> spont  =   true return  self  ?  self -> notifyInternal(receiver,  event ) :  false
}

/* !
  \internal
  This function is here to make it possible for Qt extensions to
  hook into event notification without subclassing QApplication
*/
bool  QCoreApplication::notifyInternal(QObject  * receiver, QEvent  * event )
{
    
//  Make it possible for Qt Jambi and QSA to hook into events even
    
//  though QApplication is subclassed
     bool  result  =   false ;
    
void   * cbdata[]  =  { receiver,  event & result };
    
if  (QInternal::activateCallbacks(QInternal::EventNotifyCallback, cbdata)) {
        
return  result;
    }

    
//  Qt enforces the rule that events can only be sent to objects in
    
//  the current thread, so receiver->d_func()->threadData is
    
//  equivalent to QThreadData::current(), just without the function
    
//  call overhead.
    QObjectPrivate  * =  receiver -> d_func();
    QThreadData 
* threadData  =  d -> threadData;
    
++ threadData -> loopLevel;

    
bool  returnValue;
    QT_TRY {
        returnValue 
=  notify(receiver,  event );   // 大名鼎鼎的notify(),处理后,调用notify_helper继续处理
    } QT_CATCH () {
        
-- threadData -> loopLevel;
        QT_RETHROW;
    }
    
-- threadData -> loopLevel;
    
return  returnValue;
}



bool  QApplication::notify(QObject  * receiver, QEvent  * e)
{
    
//
    
//  walk through parents and check for gestures
     if  (d -> gestureManager) {
        
switch  (e -> type()) {
        
case  QEvent::Paint:
        
case  QEvent::DynamicPropertyChange:
        
case  QEvent::NetworkReplyUpdated:
        
//
             break ;
        
default :
            
if  (receiver -> isWidgetType()) {
                
if  (d -> gestureManager -> filterEvent(static_cast < QWidget  *> (receiver), e))
                    
return   true ;
            } 
else  {
                
//  a special case for events that go to QGesture objects.
                
//  We pass the object to the gesture manager and it'll figure
                
//  out if it's QGesture or not.
                 if  (d -> gestureManager -> filterEvent(receiver, e))
                    
return   true ;
            }
        }
    }

    
//  User input and window activation makes tooltips sleep
     switch  (e -> type()) {
    
case  QEvent::Wheel:
    
case  QEvent::ActivationChange:
    
//
     default :
        res 
=  d -> notify_helper(receiver, e);
        
break ;
    }
    
return  res;
}


bool  QApplicationPrivate::notify_helper(QObject  * receiver, QEvent  *  e)
{
    
//  send to all application event filters
     if  (sendThroughApplicationEventFilters(receiver, e))
        
return   true ;

    
if  (receiver -> isWidgetType()) {
        QWidget 
* widget  =  static_cast < QWidget  *> (receiver);
        
// .
         if  (QLayout  * layout = widget -> d_func() -> layout) {
            layout
-> widgetEvent(e);
        }
    }

    
//  send to all receiver event filters 
    
// 说明4:这里也是关键的地方
     if  (sendThroughObjectEventFilters(receiver, e))
        
return   true ;

    
//  deliver the event
     bool  consumed  =  receiver -> event (e);  // 说明5,receiver->event()调用
    e -> spont  =   false ;
    
return  consumed;
}

bool  QCoreApplicationPrivate::sendThroughObjectEventFilters(QObject  * receiver, QEvent  * event )
{
    Q_Q(QCoreApplication);
    
if  (receiver  !=  q) {
        
for  ( int  i  =   0 ; i  <  receiver -> d_func() -> eventFilters.size();  ++ i) {
            register QObject 
* obj  =  receiver -> d_func() -> eventFilters.at(i);
            
if  ( ! obj)
                
continue ;
            
if  (obj -> d_func() -> threadData  !=  receiver -> d_func() -> threadData) {
                qWarning(
" QCoreApplication: Object event filter cannot be in a different thread. " );
                
continue ;
            }
            
if  (obj -> eventFilter(receiver,  event ))
                
return   true ;
        }
    }
    
return   false ;
}


bool  QCoreApplicationPrivate::sendThroughApplicationEventFilters(QObject  * receiver, QEvent  * event )
{
    
if  (receiver -> d_func() -> threadData  ==   this -> threadData) {
        
//  application event filters are only called for objects in the GUI thread
         for  ( int  i  =   0 ; i  <  eventFilters.size();  ++ i) {
            register QObject 
* obj  =  eventFilters.at(i);
            
if  ( ! obj)
                
continue ;
            
if  (obj -> d_func() -> threadData  !=  threadData) {
                qWarning(
" QCoreApplication: Application event filter cannot be in a different thread. " );
                
continue ;
            }
            
if  (obj -> eventFilter(receiver,  event ))
                
return   true ;
        }
    }
    
return   false ;
}
bool  QApplication:: event (QEvent  * e)
{
    Q_D(QApplication);
    
if (e -> type()  ==  QEvent::Close) {
        QCloseEvent 
* ce  =  static_cast < QCloseEvent *> (e);
        ce
-> accept();
        closeAllWindows();

        QWidgetList list 
=  topLevelWidgets();
        
for  ( int  i  =   0 ; i  <  list.size();  ++ i) {
            QWidget 
* =  list.at(i);
            
if  (w -> isVisible()  &&   ! (w -> windowType()  ==  Qt::Desktop)  &&   ! (w -> windowType()  ==  Qt::Popup)  &&
                 (
! (w -> windowType()  ==  Qt::Dialog)  ||   ! w -> parentWidget())) {
                ce
-> ignore();
                
break ;
            }
        }
        
if  (ce -> isAccepted()) {
            
return   true ;
        } 
else  {
        }
    } 
else   if (e -> type()  ==  QEvent::LanguageChange) {
        QWidgetList list 
=  topLevelWidgets();
        
for  ( int  i  =   0 ; i  <  list.size();  ++ i) {
            QWidget 
* =  list.at(i);
            
if  ( ! (w -> windowType()  ==  Qt::Desktop))
                postEvent(w, 
new  QEvent(QEvent::LanguageChange));
        }
    } 
else   if  (e -> type()  ==  QEvent::Timer) {
        QTimerEvent 
* te  =  static_cast < QTimerEvent *> (e);
        Q_ASSERT(te 
!=   0 );
        
if  (te -> timerId()  ==  d -> toolTipWakeUp.timerId()) {
            d
-> toolTipWakeUp.stop();
            
if  (d -> toolTipWidget) {
                QWidget 
* =  d -> toolTipWidget -> window();
                
//  show tooltip if WA_AlwaysShowToolTips is set, or if
                
//  any ancestor of d->toolTipWidget is the active
                
//  window
                 bool  showToolTip  =  w -> testAttribute(Qt::WA_AlwaysShowToolTips);
                
while  (w  &&   ! showToolTip) {
                    showToolTip 
=  w -> isActiveWindow();
                    w 
=  w -> parentWidget();
                    w 
=  w  ?  w -> window() :  0 ;
                }
                
if  (showToolTip) {
                    QHelpEvent e(QEvent::ToolTip, d
-> toolTipPos, d -> toolTipGlobalPos);
                    QApplication::sendEvent(d
-> toolTipWidget,  & e);
                    
if  (e.isAccepted())
                        d
-> toolTipFallAsleep.start( 2000 this );
                }
            }
        } 
else   if  (te -> timerId()  ==  d -> toolTipFallAsleep.timerId()) {
            d
-> toolTipFallAsleep.stop();
        }
    }
    
return  QCoreApplication:: event (e);  /// /说明6,最终QObject::event()调用
}

bool  QCoreApplication:: event (QEvent  * e)
{
    
if  (e -> type()  ==  QEvent::Quit) {
        quit();
        
return   true ;
    }
    
return  QObject:: event (e);
}

 

你可能感兴趣的:([原]Qt事件处理机制浅析)