事件处理机制浅析是通过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 *w = 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 *d = 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 *w = 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 *w = 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 *w = 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事件处理机制浅析
最新推荐文章于 2023-05-13 18:10:41 发布