深入了解事件处理系统对于每个学习Qt人来说非常重要,可以说,Qt是以事件驱动的UI工具集。 大家熟知Signals/Slots在多线程的实现也依赖于Qt的事件处理机制。
在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生、分发、接受和处理事件:
1.谁来产生事件: 最容易想到的是我们的输入设备,比如键盘、鼠标产生的
keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件(他们被封装成QMouseEvent和QKeyEvent),这些事件来自于底层的操作系统,它们以异步的形式通知Qt事件处理系统,后文会仔细道来。当然Qt自己也会产生很多事件,比如QObject::startTimer()会触发QTimerEvent.
用户的程序可还以自己定制事件。
2.谁来接受和处理事件:答案是QObject。在Qt的内省机制剖析一文已经介绍QObject
类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责(内存管理、内省(intropection)与事件处理制)之一。任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的处理权转给父类。
3. 谁来负责分发事件:对于non-GUI的Qt程序,是由QCoreApplication负责将QEvent分发给QObject的子类-Receiver.
对于Qt GUI程序,由QApplication来负责。
接下来,将通过对代码的解析来看看QT是利用event loop从事件队列中获取用户输入事件,又是如何将事件转义成QEvents,并分发给相应的QObject处理。
-
#include<QApplication>
-
#include"widget.h"
-
-
intmain(intargc,char*argv[])
-
{
-
QApplicationapp(argc,argv);
-
Widgetwindow;
-
window.show();
-
returnapp.exec();
-
}
-
-
intQApplication::exec()
-
{
-
-
-
returnQCoreApplication::exec();
-
}
-
-
intQCoreApplication::exec()
-
{
-
-
QThreadData*threadData=self->d_func()->threadData;
-
if(threadData!=QThreadData::current()){
-
qWarning("%s::exec:Mustbecalledfromthemainthread",self->metaObject()->className());
-
return-1;
-
}
-
-
if(!threadData->eventLoops.isEmpty()){
-
qWarning("QCoreApplication::exec:Theeventloopisalreadyrunning");
-
return-1;
-
}
-
...
-
QEventLoopeventLoop;
-
self->d_func()->in_exec=true;
-
self->d_func()->aboutToQuitEmitted=false;
-
-
intreturnCode=eventLoop.exec();
-
....
-
}
-
returnreturnCode;
-
}
-
-
intQEventLoop::exec(ProcessEventsFlagsflags)
-
{
-
-
Q_D(QEventLoop);
-
try{
-
-
while(!d->exit)
-
processEvents(flags|WaitForMoreEvents|EventLoopExec);
-
}catch(...){}
-
}
-
-
boolQEventLoop::processEvents(ProcessEventsFlagsflags)
-
{
-
Q_D(QEventLoop);
-
if(!d->threadData->eventDispatcher)
-
returnfalse;
-
if(flags&DeferredDeletion)
-
QCoreApplication::sendPostedEvents(0,QEvent::DeferredDelete);
-
-
returnd->threadData->eventDispatcher->processEvents(flags);
-
}
-
-
-
-
-
boolQEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlagsflags)
-
{
-
Q_D(QEventDispatcherWin32);
-
if(!d->internalHwnd)
-
createInternalHwnd();
-
d->interrupt=false;
-
emitawake();
-
boolcanWait;
-
boolretVal=false;
-
boolseenWM_QT_SENDPOSTEDEVENTS=false;
-
boolneedWM_QT_SENDPOSTEDEVENTS=false;
-
do{
-
DWORDwaitRet=0;
-
HANDLEpHandles[MAXIMUM_WAIT_OBJECTS-1];
-
QVarLengthArray<MSG>processedTimers;
-
while(!d->interrupt){
-
DWORDnCount=d->winEventNotifierList.count();
-
Q_ASSERT(nCount<MAXIMUM_WAIT_OBJECTS-1);
-
MSGmsg;
-
boolhaveMessage;
-
if(!(flags&QEventLoop::ExcludeUserInputEvents)&&!d->queuedUserInputEvents.isEmpty()){
-
-
haveMessage=true;
-
-
msg=d->queuedUserInputEvents.takeFirst();
-
}elseif(!(flags&QEventLoop::ExcludeSocketNotifiers)&&!d->queuedSocketEvents.isEmpty()){
-
-
haveMessage=true;
-
msg=d->queuedSocketEvents.takeFirst();
-
}else{
-
haveMessage=PeekMessage(&msg,0,0,0,PM_REMOVE);
-
if(haveMessage&&(flags&QEventLoop::ExcludeUserInputEvents)
-
&&((msg.message>=WM_KEYFIRST
-
&&msg.message<=WM_KEYLAST)
-
||(msg.message>=WM_MOUSEFIRST
-
&&msg.message<=WM_MOUSELAST)
-
||msg.message==WM_MOUSEWHEEL
-
||msg.message==WM_MOUSEHWHEEL
-
||msg.message==WM_TOUCH
-
#ifndefQT_NO_GESTURES
-
||msg.message==WM_GESTURE
-
||msg.message==WM_GESTURENOTIFY
-
#endif
-
||msg.message==WM_CLOSE)){
-
-
haveMessage=false;
-
d->queuedUserInputEvents.append(msg);
-
}
-
if(haveMessage&&(flags&QEventLoop::ExcludeSocketNotifiers)
-
&&(msg.message==WM_QT_SOCKETNOTIFIER&&msg.hwnd==d->internalHwnd)){
-
-
haveMessage=false;
-
d->queuedSocketEvents.append(msg);
-
}
-
}
-
....
-
if(!filterEvent(&msg)){
-
TranslateMessage(&msg);
-
-
-
DispatchMessage(&msg);
-
}
-
}
-
}
-
}while(canWait);
-
...
-
returnretVal;
-
}
-
-
extern"C"LRESULTQT_WIN_CALLBACKQtWndProc(HWNDhwnd,UINTmessage,WPARAMwParam,LPARAMlParam)
-
{
-
...
-
-
result=widget->translateMouseEvent(msg);
-
...
-
}
-
从Section 1~Section7, Qt进入QApplication的event loop,经过层层委任,最终QEventloop的processEvent将通过与平台相关的QAbstractEventDispatcher的子类QEventDispatcherWin32获得用户的用户输入事件,并将其打包成message后,通过标准Windows
API ,把消息传递给了Windows OS,Windows OS得到通知后回调QtWndProc,至此事件的分发与处理完成了一半的路程。
在下文中,我们将进一步讨论当我们收到来在Windows的回调后,事件又是怎么一步步打包成QEvent并通过QApplication分发给最终事件的接受和处理者QObject::event.
在Qt中,事件被封装成一个个对象,所有的事件均继承自抽象类QEvent. 接下来依次谈谈Qt中有谁来产生、分发、接受和处理事件:
1.谁来产生事件: 最容易想到的是我们的输入设备,比如键盘、鼠标产生的
keyPressEvent,keyReleaseEvent,mousePressEvent,mouseReleaseEvent事件(他们被封装成QMouseEvent和QKeyEvent),这些事件来自于底层的操作系统,它们以异步的形式通知Qt事件处理系统,后文会仔细道来。当然Qt自己也会产生很多事件,比如QObject::startTimer()会触发QTimerEvent.
用户的程序可还以自己定制事件。
2.谁来接受和处理事件:答案是QObject。在Qt的内省机制剖析一文已经介绍QObject
类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责(内存管理、内省(intropection)与事件处理制)之一。任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的处理权转给父类。
3. 谁来负责分发事件:对于non-GUI的Qt程序,是由QCoreApplication负责将QEvent分发给QObject的子类-Receiver.
对于Qt GUI程序,由QApplication来负责。
接下来,将通过对代码的解析来看看QT是利用event loop从事件队列中获取用户输入事件,又是如何将事件转义成QEvents,并分发给相应的QObject处理。
-
#include<QApplication>
-
#include"widget.h"
-
-
intmain(intargc,char*argv[])
-
{
-
QApplicationapp(argc,argv);
-
Widgetwindow;
-
window.show();
-
returnapp.exec();
-
}
-
-
intQApplication::exec()
-
{
-
-
-
returnQCoreApplication::exec();
-
}
-
-
intQCoreApplication::exec()
-
{
-
-
QThreadData*threadData=self->d_func()->threadData;
-
if(threadData!=QThreadData::current()){
-
qWarning("%s::exec:Mustbecalledfromthemainthread",self->metaObject()->className());
-
return-1;
-
}
-
-
if(!threadData->eventLoops.isEmpty()){
-
qWarning("QCoreApplication::exec:Theeventloopisalreadyrunning");
-
return-1;
-
}
-
...
-
QEventLoopeventLoop;
-
self->d_func()->in_exec=true;
-
self->d_func()->aboutToQuitEmitted=false;
-
-
intreturnCode=eventLoop.exec();
-
....
-
}
-
returnreturnCode;
-
}
-
-
intQEventLoop::exec(ProcessEventsFlagsflags)
-
{
-
-
Q_D(QEventLoop);
-
try{
-
-
while(!d->exit)
-
processEvents(flags|WaitForMoreEvents|EventLoopExec);
-
}catch(...){}
-
}
-
-
boolQEventLoop::processEvents(ProcessEventsFlagsflags)
-
{
-
Q_D(QEventLoop);
-
if(!d->threadData->eventDispatcher)
-
returnfalse;
-
if(flags&DeferredDeletion)
-
QCoreApplication::sendPostedEvents(0,QEvent::DeferredDelete);
-
-
returnd->threadData->eventDispatcher->processEvents(flags);
-
}
-
-
-
-
-
boolQEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlagsflags)
-
{
-
Q_D(QEventDispatcherWin32);
-
if(!d->internalHwnd)
-
createInternalHwnd();
-
d->interrupt=false;
-
emitawake();
-
boolcanWait;
-
boolretVal=false;
-
boolseenWM_QT_SENDPOSTEDEVENTS=false;
-
boolneedWM_QT_SENDPOSTEDEVENTS=false;
-
do{
-
DWORDwaitRet=0;
-
HANDLEpHandles[MAXIMUM_WAIT_OBJECTS-1];
-
QVarLengthArray<MSG>processedTimers;
-
while(!d->interrupt){
-
DWORDnCount=d->winEventNotifierList.count();
-
Q_ASSERT(nCount<MAXIMUM_WAIT_OBJECTS-1);
-
MSGmsg;
-
boolhaveMessage;
-
if(!(flags&QEventLoop::ExcludeUserInputEvents)&&!d->queuedUserInputEvents.isEmpty()){
-
-
haveMessage=true;
-
-
msg=d->queuedUserInputEvents.takeFirst();
-
}elseif(!(flags&QEventLoop::ExcludeSocketNotifiers)&&!d->queuedSocketEvents.isEmpty()){
-
-
haveMessage=true;
-
msg=d->queuedSocketEvents.takeFirst();
-
}else{
-
haveMessage=PeekMessage(&msg,0,0,0,PM_REMOVE);
-
if(haveMessage&&(flags&QEventLoop::ExcludeUserInputEvents)
-
&&((msg.message>=WM_KEYFIRST
-
&&msg.message<=WM_KEYLAST)
-
||(msg.message>=WM_MOUSEFIRST
-
&&msg.message<=WM_MOUSELAST)
-
||msg.message==WM_MOUSEWHEEL
-
||msg.message==WM_MOUSEHWHEEL
-
||msg.message==WM_TOUCH
-
#ifndefQT_NO_GESTURES
-
||msg.message==WM_GESTURE
-
||msg.message==WM_GESTURENOTIFY
-
#endif
-
||msg.message==WM_CLOSE)){
-
-
haveMessage=false;
-
d->queuedUserInputEvents.append(msg);
-
}
-
if(haveMessage&&(flags&QEventLoop::ExcludeSocketNotifiers)
-
&&(msg.message==WM_QT_SOCKETNOTIFIER&&msg.hwnd==d->internalHwnd)){
-
-
haveMessage=false;
-
d->queuedSocketEvents.append(msg);
-
}
-
}
-
....
-
if(!filterEvent(&msg)){
-
TranslateMessage(&msg);
-
-
-
DispatchMessage(&msg);
-
}
-
}
-
}
-
}while(canWait);
-
...
-
returnretVal;
-
}
-
-
extern"C"LRESULTQT_WIN_CALLBACKQtWndProc(HWNDhwnd,UINTmessage,WPARAMwParam,LPARAMlParam)
-
{
-
...
-
-
result=widget->translateMouseEvent(msg);
-
...
-
}
-
从Section 1~Section7, Qt进入QApplication的event loop,经过层层委任,最终QEventloop的processEvent将通过与平台相关的QAbstractEventDispatcher的子类QEventDispatcherWin32获得用户的用户输入事件,并将其打包成message后,通过标准Windows
API ,把消息传递给了Windows OS,Windows OS得到通知后回调QtWndProc,至此事件的分发与处理完成了一半的路程。
在下文中,我们将进一步讨论当我们收到来在Windows的回调后,事件又是怎么一步步打包成QEvent并通过QApplication分发给最终事件的接受和处理者QObject::event.
分享到:
相关推荐
事件是窗口系统或者qt对不同情况的响应...QWidget::event()虚函数是各种事件的一个大管家,负责把大多数常用类型的事件传递给特定的事件处理器(事件处理函数,也都是虚拟函数,便于其继承子类对于该事件处理的编程),
类是整个Qt对象模型的心脏,事件处理机制是QObject三大职责( 内存管理、内省intropection、事件处理制)之一。 任何一个想要接受并处理事件的对象均须继承自QObject,可以选择重载QObject::event()函数或事件的...
Qt事件机制浅析
这是一个Qt事件处理系统,目前只实现了鼠标事件的处理,后续将添加键盘事件,绘图事件,定时事件等等的处理过程。程序比较简单,适合初学者。程序开发环境:win7+qt5.7.0
查看了很多资料,对qt的消息处理机制做了整理,相信对qt学习者会有很大的帮助
这是一本描写Qt中的事件机制的PDF文档。
1. #include 5. { 6. QApplication app(argc, argv)
qt用预编译器和宏来保证强大的跨平台能力,信号机制则是其中最精妙之处。本文分析了几种常见的信号处理机制,然后详细介绍了Qt的Signal/Slot机制。
QT信号与槽机制浅析Qt的信号和槽机制是Qt的一大特点,实际上这是和MFC中的消息映射机制相似的东西,要完成的事情也差不多,就是发送一个消息然后让其它窗口响应,当然,这里的消息是广义的 说法,简单点说就是如何在一个类...
关于Qt事件处理和定时器的详细内容,参考博客:http://blog.csdn.net/rl529014/article/details/53440211
QT的显示机制,可以看看,比较不错 QT的显示机制,可以看看,比较不错 QT的显示机制,可以看看,比较不错
在 Qt Quick 中,事件处理通常涉及到对输入事件(如鼠标点击、键盘输入、触摸事件等)的响应。这些事件可以通过 Qt 的事件系统或信号与槽机制进行处理。鼠标、键盘、触摸……每一种用户可能使用的与计算机或手机交互...
2. QApplication::exec() 3. QCoreApplication::exec() 4. QEventLoop::exec(ProcessE
个人吐血整理,从源码剖析Qt框架,绝对给力!
它也是目前流行的Linux桌面环境KDE的基础,KDE是Linux发行版的主要一个标准组件。2008年,奇趣科技被诺基亚公司收购,Qt成为诺基亚旗下的编程语言工具。2012年,Qt又被Digia公司收购。2014年,Digia宣布成立“The Qt...
QT 中 QEvent 和 QKeyEvent事件的处理,其中QEvent包含QKeyEvent和QMouseEvent事件处理,在event中处理QKeyEvent事件将影响单独的QKeyEvent的事件处理函数
qt事件处理qt事件处理qt事件处理
Qt 使用QMetaObject实现反射机制代码demo
QT内部工作机制,深入进入QT底层实现细节. 对于想深入了解QT工作原理的,值得一看!
使用Qt的相关机制,保障Oracle数据库的链接机制