Qt-事件循环 & 模态窗口
本文最后更新于:2022年10月21日 晚上
前情提要
質問:
为什么模态对话框会阻塞其他窗口的交互?
众所周知,调用QDialog::exec
会开启一个模态对话框,阻塞后续代码,并阻止其他窗口的交互
But Why?
1 |
|
观察源码可知,exec
方法将窗口设置为了模态(Modal),并开启了局部事件循环
那么,究竟是局部事件循环阻止了与其他窗口的交互,还是Modal
属性的仕業(しわざ)呢
EventLoop
首先来看看什么是事件循环
我们在Qt
桌面程序的main
函数里就能看到QApplicaion::exec()
其内部就开了一个事件循环,也称为Qt
程序的主循环
1 |
|
1 |
|
实际上,事件循环的本质就是一个死循环,不断接收内部外部的各种消息,并派发到对应的函数进行处理
所以exec
之后的(同一函数内的)代码在循环结束前是不会得到执行机会的(阻塞)
事件循环的本质就是以队列的方式再次分配线程时间片
嵌套循环
事件循环还有一个重要性质,ta是可以被嵌套的
也就是在QApplicaion::exec()
主循环内还可以开启局部事件循环
1 |
|
就像while
循环一样,局部事件循环运行时,父循环就处于停滞状态
局部事件循环跳出后,父循环继续运行
不过,问题不大,事件循环本身就只是派发事件,与谁父谁子无关,局部循环同样能承担一样的职能
Qt
会把事件分发到生效的事件循环中去
所以,虽然eventLoop.exec();
后的代码被阻塞,但是UI
交互、Timer
等等各类事件都是正常执行的
也就是一个函数被阻塞,但是千千万万个函数在阻塞前的那行代码内运行
时间停止了?不,世界仍在运行,只有你停滞不前 —— 蔡姬
正因为如此,局部事件循环的妙用就是在不阻塞UI
的前提下,实现函数的同步执行
例如:等待服务器响应,计算超时等等
综上
事件循环并不阻塞UI
,不可能导致对话框阻塞其他窗口的交互
迷
那究竟是谁,干了这好事(恼)
只有模态属性了吧
1 |
|
确实如此,只要设置模态属性,就能实现交互阻塞
而且还有两种模式:
模式 | 效果 |
---|---|
Qt::ApplicationModal | 阻塞应用程序的所有窗口 |
Qt::WindowModal | 阻塞父窗口、祖先窗口及它们的子窗口 |
始作俑者
但是,为什么
难道说
我真傻,真的
我一直以为阻塞是不得已而为之,却忘了人心险恶
这极有可能是Qt
在内部手动屏蔽了其他窗口的交互,只为了强制用户专心于模态窗口
www 我真傻 真的
补充
对了,还有一点
QEventLoop::ProcessEventsFlags
的枚举值在Qt
文档中被刻意隐藏了一些
比如Qt
源码中的QEventLoop::DialogExec
原因未知
Peace
Ref
Qt事件循环详解(一)_一只向前的程序猿的博客-CSDN博客_qt循环
Qt 之 模态、非模态、半模态窗口的介绍及 实现QDialog的exec()方法 - maxiongying - 博客园 (cnblogs.com)
Qt 之 模态、非模态、半模态窗口的介绍及 实现QDialog的exec()方法_前行中的小猪的博客-CSDN博客_qdialog模态显示
QDialog 模态对话框与事件循环(exec其实就是调用了show和eventLoop.exec) - findumars - 博客园 (cnblogs.com)
QT中使用QEventLoop来实现事件循环_「已注销」的博客-CSDN博客_qeventloop
Qt | 模态对话框和非模态对话框 QDialog - 知乎 (zhihu.com)
Qt 模态窗口 - 索智源 - 博客园 (cnblogs.com)
Qt Object模型及其线程和事件处理_szonebit的博客-CSDN博客
event handling - Undocumented ProcessEventsFlag enums in QT - Stack Overflow