-
Event Listeners
We know that the program requires Qt () function creates a QApplication object in the main, and then call its exec () function. This function is the beginning of Qt event loop. After executing the exec () function, the program will enter the event loop to listen for the event of the application. Let's analyze how Qt event is listening.
First, of course is to analyze the QApplication source, the following is QApplication realization :: exec () is:
int QApplication::exec()
{
return eventLoop()->exec();// 直接交给QEventLoop::exec()
}
It shows a direct call QEventLoop the exec () function, look QEventLoop :: exec (), QEventLoop :: Exec calls () in QEventLoop :: enterLoop () method, enter enterLoop after () is really into the event monitor cycle.
int QEventLoop::exec()
{
d->reset();
enterLoop();//进入事件监听循环
// cleanup
d->looplevel = 0;
d->quitnow = FALSE;
d->exitloop = FALSE;
d->shortcut = FALSE;
// don't reset quitcode!
return d->quitcode;
}
-
Qt how the user's keyboard, mouse clicks are converting to Qt events?
Let's analyze QEventLoop :: enterLoop methods, which use a while loop, constantly calling processEvents handle the event.
int QEventLoop::enterLoop()
{
// save the current exitloop state
bool old_exitloop = d->exitloop;
d->exitloop = FALSE;
d->shortcut = FALSE;
d->looplevel++;
while ( ! d->exitloop )//循环获取事件
processEvents( AllEvents | WaitForMore );
d->looplevel--;
// restore the exitloop state, but if quitnow is TRUE, we need to keep
// exitloop set so that all other event loops drop out.
d->exitloop = old_exitloop || d->quitnow;
d->shortcut = d->quitnow;
if ( d->looplevel < 1 ) {
d->quitnow = FALSE;
d->exitloop = FALSE;
d->shortcut = FALSE;
emit qApp->aboutToQuit();
// send deferred deletes
QApplication::sendPostedEvents( 0, QEvent::DeferredDelete );
}
return d->looplevel;
}
Let's look at QEventLoop :: processEvents () is how to deal with, where we mainly analyze how the windows are processed. Here is QEventLoop :: processEvents () source code, showing its call winPeekMessage get messages from the operating system message queue, call DispatchMessage will get the message to be distributed to our Qt window for processing. Qt when seen from the operating system is already acquired through the encapsulated message, converts the message to a user operation is done by the operating system, only you need to use Qt winPeekMessage taken from the operating system can be in the message queue. winPeekMessage and DispatchMessage is the contents of the Windows system programming, not within the scope of this article, no in-depth study.
bool QEventLoop::processEvents( ProcessEventsFlags flags )
{
MSG msg;
#if defined(QT_THREAD_SUPPORT)
QMutexLocker locker( QApplication::qt_mutex );
#endif
emit awake();
emit qApp->guiThreadAwake();
QApplication::sendPostedEvents();
bool canWait = d->exitloop || d->quitnow ? FALSE : (flags & WaitForMore);
if ( canWait ) { // can wait if necessary
if ( numZeroTimers ) { // activate full-speed timers
int ok = FALSE;
while ( numZeroTimers &&
!(ok=winPeekMessage(&msg,0,0,0,PM_REMOVE)) ) {// 从windows消息队列中读一条消息
activateZeroTimers();
}
if ( !ok ) { // no event
return FALSE;
}
} else {
if (!winPeekMessage(&msg, 0, 0, 0, PM_NOREMOVE))// 从windows消息队列中读一条消息
emit aboutToBlock();
#ifdef QT_THREAD_SUPPORT
locker.mutex()->unlock();
#endif // QT_THREAD_SUPPORT
if ( !winGetMessage(&msg,0,0,0) ) {
#ifdef QT_THREAD_SUPPORT
locker.mutex()->lock();
#endif // QT_THREAD_SUPPORT
exit( 0 ); // WM_QUIT received
return FALSE;
}
#ifdef QT_THREAD_SUPPORT
locker.mutex()->lock();
#endif // QT_THREAD_SUPPORT
}
} else { // no-wait mode
if ( !winPeekMessage(&msg,0,0,0,PM_REMOVE) ) { // no pending events
if ( numZeroTimers > 0 ) { // there are 0-timers
activateZeroTimers();
}
return FALSE;
}
}
bool handled = FALSE;
if ( msg.message == WM_TIMER ) { // timer message received
if ( dispatchTimer( msg.wParam, &msg ) )//定时器事件处理,处理完后直接返回
return TRUE;
} else if ( msg.message && (!msg.hwnd || !QWidget::find(msg.hwnd)) ) {
long res = 0;
handled = qt_winEventFilter( &msg, res );
}
if ( !handled ) {// 其余事件处理
bool ignore = false;
if (flags & ExcludeUserInput) {
ignore = (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
|| (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)
|| msg.message == WM_MOUSEWHEEL;
}
if (!ignore) {
QInputContext::TranslateMessage( &msg ); // translate to WM_CHAR
QT_WA( {
DispatchMessage( &msg ); // 将事件发给QtWndProc
} , {
DispatchMessageA( &msg ); // 将事件发给 QtWndProc
} );
} else if (msg.message == WM_LBUTTONUP
|| msg.message == WM_MBUTTONUP
|| msg.message == WM_RBUTTONUP
|| msg.message == WM_XBUTTONUP) {
qt_releaseAutoCapture();
}
}
if ( !(flags & ExcludeSocketNotifiers ) )
activateSocketNotifiers();
if ( configRequests ) // any pending configs?
qWinProcessConfigRequests();
QApplication::sendPostedEvents();
return TRUE;
}
-
Qt message processing flow of the operating system
Speaking of the above, Qt calls DispatchMessage from the operating system to get the message distributed to our Qt window for processing.
LRESULT CALLBACK QtWndProc( HWND hwnd, UINT message, WPARAM wParam,
LPARAM lParam )
{
......
#if defined(QT_TABLET_SUPPORT)
if ( !chokeMouse ) {
#endif
widget->translateMouseEvent( msg );
......
}
bool QETWidget::translateMouseEvent( const MSG &msg )
{
......
QApplication::sendSpontaneousEvent(popup, &e);
......
}
inline bool QApplication::sendEvent( QObject *receiver, QEvent *event )
{ if ( event ) event->spont = FALSE; return qApp ? qApp->notify( receiver, event ) : FALSE; }
inline bool QApplication::sendSpontaneousEvent( QObject *receiver, QEvent *event )
{ if ( event ) event->spont = TRUE; return qApp ? qApp->notify( receiver, event ) : FALSE; }
bool QApplication::notify( QObject *receiver, QEvent *e )
{
......
internalNotify( receiver, e );
......
}
bool QApplication::internalNotify( QObject *receiver, QEvent * e)
{
if ( eventFilters ) {
QObjectListIt it( *eventFilters );
register QObject *obj;
while ( (obj=it.current()) != 0 ) { // send to all filters
++it; // until one returns TRUE
if ( obj->eventFilter(receiver,e) )
return TRUE;
}
}
bool consumed = FALSE;
bool handled = FALSE;
if ( receiver->isWidgetType() ) {
QWidget *widget = (QWidget*)receiver;
// toggle HasMouse widget state on enter and leave
if ( e->type() == QEvent::Enter || e->type() == QEvent::DragEnter )
widget->setWState( WState_HasMouse );
else if ( e->type() == QEvent::Leave || e->type() == QEvent::DragLeave )
widget->clearWState( WState_HasMouse );
// throw away any mouse-tracking-only mouse events
if ( e->type() == QEvent::MouseMove &&
(((QMouseEvent*)e)->state()&QMouseEvent::MouseButtonMask) == 0 &&
!widget->hasMouseTracking() ) {
handled = TRUE;
consumed = TRUE;
} else if ( !widget->isEnabled() ) { // throw away mouse events to disabled widgets
switch(e->type()) {
case QEvent::MouseButtonPress:
case QEvent::MouseButtonRelease:
case QEvent::MouseButtonDblClick:
case QEvent::MouseMove:
( (QMouseEvent*) e)->ignore();
handled = TRUE;
consumed = TRUE;
break;
#ifndef QT_NO_DRAGANDDROP
case QEvent::DragEnter:
case QEvent::DragMove:
( (QDragMoveEvent*) e)->ignore();
handled = TRUE;
break;
case QEvent::DragLeave:
case QEvent::DragResponse:
handled = TRUE;
break;
case QEvent::Drop:
( (QDropEvent*) e)->ignore();
handled = TRUE;
break;
#endif
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
( (QWheelEvent*) e)->ignore();
handled = TRUE;
break;
#endif
case QEvent::ContextMenu:
( (QContextMenuEvent*) e)->ignore();
handled = TRUE;
break;
default:
break;
}
}
}
if (!handled)
consumed = receiver->event( e );//最终调用event()函数进而调用相应的事件处理器
e->spont = FALSE;
return consumed;
}
After writing an article is also found online to do a similar analysis of the article: http: //mobile.51cto.com/symbian-272816.htm