版权声明
请尊重原创作品。转载请保持文章完整性,并以超链接形式注明原始作者“”和主站点地址,方便其他朋友提问和指正。
QT源码解析(一) QT创建窗口程序、消息循环和WinMain函数
QT源码解析(二)深入剖析QT元对象系统和信号槽机制
QT源码解析(三)深入剖析QT元对象系统和信号槽机制(续)
QT源码解析(四)剖析Qt的事件机制原理
QT源码解析(五)QLibrary跨平台调用动态库的实现
QT源码解析(六)Qt信号槽机制与事件机制的联系
QT源码解析(七)Qt创建窗体的过程
QT源码解析(八)Qt是如何处理windows消息的
QT源码解析(九)解析QDateTime
在用Qt写Gui程序的时候,在main函数里面最后依据都是app.exec();很多书上对这句的解释是,使Qt程序进入消息循环。下面我们就到exec()函数内部,来看一下他的实现原理。
首先来到QTDIR\src\corelib\kernel\qcoreapplication.cpp
- int QCoreApplication::exec()
-
{
-
if (!QCoreApplicationPrivate::checkInstance("exec"))
-
return -1;
-
//获取线程数据
-
QThreadData *threadData = self->d_func()->threadData;
-
//判断是否在主线程创建
-
if (threadData != QThreadData::current()) {
-
qWarning("%s::exec: Must be called from the main thread", self->metaObject()->className());
-
return -1;
-
}
-
//判断eventLoop是否已经创建
-
if (!threadData->eventLoops.isEmpty()) {
-
qWarning("QCoreApplication::exec: The event loop is already running");
-
return -1;
-
}
-
-
threadData->quitNow = false;
-
QEventLoop eventLoop;
-
self->d_func()->in_exec = true;
-
//创建eventLoop
-
int returnCode = eventLoop.exec();
-
threadData->quitNow = false;
-
if (self) {
-
self->d_func()->in_exec = false;
-
//退出程序
-
emit self->aboutToQuit();
-
sendPostedEvents(0, QEvent::DeferredDelete);
-
}
-
return returnCode;
-
}
-
再来到qeventloop.cpp中。
-
int QEventLoop::exec(ProcessEventsFlags flags)
-
{
-
Q_D(QEventLoop);
-
if (d->threadData->quitNow)
-
return -1;
-
//已经调用过exec了。
-
if (d->inExec) {
-
qWarning("QEventLoop::exec: instance %p has already called exec()", this);
-
return -1;
-
}
-
d->inExec = true;
-
d->exit = false;
-
++d->threadData->loopLevel;
-
//将事件类对象压入线程结构体中
-
d->threadData->eventLoops.push(this);
-
-
// remove posted quit events when entering a new event loop
-
// 这句不用翻译了把!
-
if (qApp->thread() == thread())
-
QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
-
-
#if defined(QT_NO_EXCEPTIONS)
-
while (!d->exit)
-
//这里才是关键,我们还要继续跟踪进去。
-
processEvents(flags | WaitForMoreEvents);
-
#else
-
try {
-
while (!d->exit)
-
processEvents(flags | WaitForMoreEvents);
-
} catch (...) {
-
//如果使用了EXCEPTION,则继续对下一条时间进行处理。
-
qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
-
"exceptions from an event handler is not supported in Qt. You must\n"
-
"reimplement QApplication::notify() and catch all exceptions there.\n");
-
throw;
-
}
-
#endif
-
//退出eventloop前,将时间对象从线程结构中取出。
-
QEventLoop *eventLoop = d->threadData->eventLoops.pop();
-
Q_ASSERT_X(eventLoop == this, "QEventLoop::exec()", "internal error");
-
Q_UNUSED(eventLoop); // --release warning
-
-
d->inExec = false;
-
--d->threadData->loopLevel;
-
//退出事件循环。
-
return d->returnCode;
-
}
-
-
来到了processEvents函数:
-
bool QEventLoop::processEvents(ProcessEventsFlags flags)
-
{
-
Q_D(QEventLoop);
-
//判断事件分派器是否为空。
-
if (!d->threadData->eventDispatcher)
-
return false;
-
if (flags & DeferredDeletion)
-
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
-
//调用不同平台下的事件分派器来处理事件。
-
return d->threadData->eventDispatcher->processEvents(flags);
-
}
-
-
processEvents是在QAbstractEventDispatcher类中定义的纯虚方法。在QEventDispatcherWin32类有processEvents的实现。
-
-
-
bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
-
{
-
Q_D(QEventDispatcherWin32);
-
//内部数据创建。registerClass注册窗口类,createwindow创建窗体。
-
//注册socket notifiers,启动所有的normal timers
-
if (!d->internalHwnd)
-
createInternalHwnd();
-
-
d->interrupt = false;
-
emit awake();
-
-
bool canWait;
-
bool retVal = false;
-
do {
-
QCoreApplicationPrivate::sendPostedEvents(0, 0, d->threadData);
-
-
DWORD waitRet = 0;
-
HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1];
-
QVarLengthArray<MSG> processedTimers;
-
while (!d->interrupt) {
-
DWORD nCount = d->winEventNotifierList.count();
-
Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
-
-
MSG msg;
-
bool haveMessage;
-
-
if (!(flags & QEventLoop::ExcludeUserInputEvents) && !d->queuedUserInputEvents.isEmpty()) {
-
// process queued user input events处理用户输入事件,放入队列中。
-
haveMessage = true;
-
msg = d->queuedUserInputEvents.takeFirst();
-
} else if(!(flags & QEventLoop::ExcludeSocketNotifiers) && !d->queuedSocketEvents.isEmpty()) {
-
// process queued socket events 处理socket事件,放入队列中。
-
haveMessage = true;
-
msg = d->queuedSocketEvents.takeFirst();
-
} else {
-
//从消息队列中取消息,同PeekMessage
-
haveMessage = winPeekMessage(&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)) {
-
// queue user input events for later processing
-
haveMessage = false;
-
d->queuedUserInputEvents.append(msg);
-
}
-
if (haveMessage && (flags & QEventLoop::ExcludeSocketNotifiers)
-
&& (msg.message == WM_USER && msg.hwnd == d->internalHwnd)) {
-
// queue socket events for later processing
-
haveMessage = false;
-
d->queuedSocketEvents.append(msg);
-
}
-
}
-
阅读(2210) | 评论(0) | 转发(1) |