熟悉的陌生人

Qt 是事件驱动的,所以当你用Qt的时候,几乎时时刻刻和 QEventLoop 打交道、,只是你可能没有意识到:

  • QCoreApplicaton::exec()
  • QApplication::exec()
  • QDialog::exec()
  • QThread::exec()
  • QDrag::exec()
  • QMenu::exec()
  • ...

在前面列出的这些常见函数的背后,都有各自的QEventLoop,可能是我们很少有机会想到自己显式使用QEventLoop的缘故吧,对这个类似乎总是有些陌生。

在  如何让 Qt 程序的 Sleep   和  QDialog 模态对话框与事件循环   两个短文中,我们可以看到 QEventLoop 的使用。那么?如何自己使用 QEventLoop 的,又有什么用呢?

QEventLoop

Manual 中说的很简洁

At any time, you can create a QEventLoop object and call exec() on it to start a local event loop. From within the event loop, calling exit() will force exec() to return.

在任何时候,你都可以创建一个QEventLoop的对象,然后调用它的exec() 来开始一个局部的事件循环。

看Manual容易让人头大,那么,看例子吧:

让主线程等待100ms?

直接sleep一下行么,显然,如果你的用户不介意你的程序界面不响应用户操作,没问题!可是如果介意呢?

此时,开启一个局部的事件循环,让其执行100ms后自己退出,似乎很不错。写来看看:

QEventLoop eventloop;
QTimer::singleShot(100, &eventloop, SLOT(quit()));
eventloop.exec();
  • 创建事件循环
  • 启动定时器,让其100ms后触发事件循环的quit()槽
  • 启动事件循环

注:让主线程等待有其他方法,此处略过。

窗口一闪而过?

不少人遇到过这个问题:在一个槽函数内创建了一个窗口对象,却没有看到窗口弹出来,或者看到窗口一闪而过。比如:

void XXXX::slot1()
{
QDialog dlg;
dlg.show()
}

当然,大家都知道原因:因为到了后面的大括号处,dlg因为出作用域,会被析构掉。解决方法很简单,增大w的生存时间即可。比如:

  • 将 dlg 作为类的成员,而不是函数的局部变量
  • 将 dlg 前面添加 static,作为静态成员
  • 将 dlg 用 new 分配到 heap 中
  • ...

能否用 QEventLoop 来解决呢?答案是,可以

void XXXX::slot1()
{
QDialog dlg;
dlg.show()
QEventLoop loop;
connect(&dlg, SIGNAL(finished(int)), &loop, SLOT(quit()));
loop.exec(QEventLoop::ExcludeUserInputEvents);
}

恩至此,问题解决。其实,这也是 QDialog::exec() 内部所做的事情,只不过此处不是模态对话框而已。

http://blog.csdn.net/dbzhang800/article/details/6300519

Qt源代码:

int QEventLoop::exec(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
//we need to protect from race condition with QThread::exit
QMutexLocker locker(&static_cast<QThreadPrivate *>(QObjectPrivate::get(d->threadData->thread))->mutex);
if (d->threadData->quitNow)
return -; if (d->inExec) {
qWarning("QEventLoop::exec: instance %p has already called exec()", this);
return -;
} struct LoopReference {
QEventLoopPrivate *d;
QMutexLocker &locker; bool exceptionCaught;
LoopReference(QEventLoopPrivate *d, QMutexLocker &locker) : d(d), locker(locker), exceptionCaught(true)
{
d->inExec = true;
d->exit.storeRelease(false);
++d->threadData->loopLevel;
d->threadData->eventLoops.push(d->q_func());
locker.unlock();
} ~LoopReference()
{
if (exceptionCaught) {
qWarning("Qt has caught an exception thrown from an event handler. Throwing\n"
"exceptions from an event handler is not supported in Qt.\n"
"You must not let any exception whatsoever propagate through Qt code.\n"
"If that is not possible, in Qt 5 you must at least reimplement\n"
"QCoreApplication::notify() and catch all exceptions there.\n");
}
locker.relock();
QEventLoop *eventLoop = d->threadData->eventLoops.pop();
Q_ASSERT_X(eventLoop == d->q_func(), "QEventLoop::exec()", "internal error");
Q_UNUSED(eventLoop); // --release warning
d->inExec = false;
--d->threadData->loopLevel;
}
};
LoopReference ref(d, locker); // remove posted quit events when entering a new event loop
QCoreApplication *app = QCoreApplication::instance();
if (app && app->thread() == thread())
QCoreApplication::removePostedEvents(app, QEvent::Quit); while (!d->exit.loadAcquire())
processEvents(flags | WaitForMoreEvents | EventLoopExec); ref.exceptionCaught = false;
return d->returnCode.load();
} void QEventLoop::processEvents(ProcessEventsFlags flags, int maxTime)
{
Q_D(QEventLoop);
if (!d->threadData->eventDispatcher.load())
return; QElapsedTimer start;
start.start();
while (processEvents(flags & ~WaitForMoreEvents)) {
if (start.elapsed() > maxTime)
break;
}
} bool QEventLoop::processEvents(ProcessEventsFlags flags)
{
Q_D(QEventLoop);
if (!d->threadData->eventDispatcher.load())
return false;
return d->threadData->eventDispatcher.load()->processEvents(flags);
}

局部QEventLoop帮助QWidget不消失(也就是有一个局部事件循环始终在运行,导致程序被卡住那里,但仍可以接受事件。说白了就是有一个while语句死活不肯退出,直到收到退出信号)的更多相关文章

  1. iphone按home键后,正在运行的程序是否退出了呢?

    是否一直有个疑问,当iphone手机正在运行一个APP,如果按Home键后,那么原来正在运行的程序还在运行吗?如果开发过ios程序,可能不是问题,如果没有开发过的,可能会疑惑了,我就简单的说一下.以几 ...

  2. HP平台由于变量声明冲突导致程序退出时的core

    最近遇到一个莫名的问题,在HP-UX B.11.31 U ia64平台下,程序PetriService在接收到产品化退出或Ctrl-C时,程序在main函数返回后析构全局的CTQueue<SMs ...

  3. Qt窗口退出与事件循环退出的问题

    我在Qt主程序中开启一个线程,线程中使用信号-槽来产生QMainWindow(GUI),main函数代码如下:int main(int argc, char *argv[]){ QApplicatio ...

  4. JS事件 卸载事件 当用户退出页面时(页面关闭、页面刷新等),触发onUnload事件,同时执行被调用的程序。注意:不同浏览器对onunload事件支持不同。

    卸载事件(onunload) 当用户退出页面时(页面关闭.页面刷新等),触发onUnload事件,同时执行被调用的程序. 注意:不同浏览器对onunload事件支持不同. 如下代码,当退出页面时,弹出 ...

  5. 深入理解QStateMachine与QEventLoop事件循环的联系与区别

    最近一直在倒腾事件循环的东西,通过查看Qt源码多少还是有点心得体会,在这里记录下和大家分享.总之,对于QStateMachine状态机本身来说,需要有QEventLoop::exec()的驱动才能支持 ...

  6. 除了信号触发线程与接收者线程相同的情况能直接调用到slot,其它情况都依赖事件机制(解决上面代码收不到信号的问题其实很简单,在线程的run();函数中添加一个事件循环就可以了,即加入一句exec();),信号槽不就是一个回调函数嘛

    MainWindow::MainWindow(QWidget *parent) :   QMainWindow(parent)   {   pThreadCon = new CSerialThread ...

  7. 事件循环和线程没有必然关系(就像Windows子线程默认没有消息循环一样),模态对话框和事件循环也没有必然关系(QWidget直接就可以)

    周末天冷,索性把电脑抱到床上上网,这几天看了 dbzhang800 博客关于 Qt 事件循环的几篇 Blog,发现自己对 Qt 的事件循环有不少误解.从来只看到现象,这次借 dbzhang800 的博 ...

  8. 迁移到MSYS2 与 Qt 工具链注意的几个事情(g++在链接时,符号依赖项查找遵循从左至右的顺序,但qmake会自动合并造成错误。使用脚本给Mingw32-make创造出一个局部的VC编译环境)

    Microsoft Visual Studio 2015社区版提供了强大的开发体验,且 Qt 提供了预编译版本.然而,由于客户提出兼容Windows XP ~ Windows 8.1 这样宽泛的环境要 ...

  9. Qt事件机制浅析(定义,产生,异步事件循环,转发,与信号的区别。感觉QT事件与Delphi的事件一致,而信号则与Windows消息一致)

    Qt事件机制 Qt程序是事件驱动的, 程序的每个动作都是由幕后某个事件所触发.. Qt事件的发生和处理成为程序运行的主线,存在于程序整个生命周期. Qt事件的类型很多, 常见的qt的事件如下: 键盘事 ...

随机推荐

  1. [WASM] Call a JavaScript Function from WebAssembly

    Using WASM Fiddle, we show how to write a simple number logger function that calls a consoleLog func ...

  2. [慕课笔记]mongodb入门篇

    一:对mongodb有一个系统的完备的了解,只有概念清楚了,才能更好的使用 二:学会mongodb数据库的搭建 首先:了解如何部署数据库的服务 搭建简单的单机服务到搭建具有冗余容错功能的复制集再到搭建 ...

  3. stm32的DMA重新工作

    下面是在战舰V3寄存器程序例子中找到的: //开启一次DMA传输void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx){    DMA_CHx->CCR&a ...

  4. Vue.js如何划分组件

    常见的一些页面,大家坐在一起敲代码就可以了,做完这个页面再做别的页面,但是作为一个功能复杂的系统,尤其是使用一些适合模块化开发的框架,这样会显得效率很低,那么我们就单纯的看在Vue里面如何划分组件的. ...

  5. Wampserver 2.5 多网站配置方法

    写在开头:本文适用于wampserver2.5版本号,和wamp的老版本号配置有语法上的差别,笔者正是由于被老版本号的配置办法给整迷糊了所以才总结了一篇针对2.5版本号的配置方法,假设您还停留在1.x ...

  6. css强制不换行 多出的字省略号

    width: 100%;//需要指定宽度 overflow: hidden;//溢出隐藏 text-overflow: ellipsis; white-space: nowrap;//强制不换行 te ...

  7. mysql 序列号生成器 (自定义函数)

    https://yq.aliyun.com/articles/42600 http://bbs.csdn.net/topics/360203885 http://www.tuicool.com/art ...

  8. 为什么 qt 成为 c++ 界面编程的第一选择?

    为什么qt成为c++界面编程的第一选择 一.前言 为什么现在QT越来越成为界面编程的第一选择,笔者从事qt界面编程已经有接近8年,在这之前我做C++界面都是基于MFC,也做过5年左右.当时为什么会从M ...

  9. jquery的mouseover和mouseout闪烁问题

    $(document).ready(function(){ $(".anli").hover( function(){ var $div = $(this); t = setInt ...

  10. AngularJS之ng-class指令

    ng-class是AngularJS预设的一个指令,用于动态自定义dom元素的css class name. 在angular中为我们提供了3种方案处理class: 1:scope变量绑定. < ...