问题
之前在分析Qt事件循环源码时,相比很多人都会有疑问,当主线程(GUI 线程)在接受到某些命令时会弹出一个对话框,这个对话框会阻塞主界面的响应,这时候是不是有个子线程在处理弹出对话框的消息(毕竟这和多线程处理很像)?
概念普及
什么是模态对话框?
对于用户分成模态对话框和非模态对话框(如下解释源于百度百科)
- 模态对话框:又叫做模式对话框,是指在用户想要对对话框以外的应用程序进行操作时,必须首先对该对话框进行响应。如单击【确定】或【取消】按钮等将该对话框关闭。
- 非模态对话框:又叫做无模式对话框,当用户打开非模态对话框时,依然可以操作其他窗口。例如,Windows提供的记事本程序中的【查找】对话框。【查找】对话框不会垄断用户的输入,打开【查找】对话框后,仍可与其他用户界面对象进行交互。
Qt中的模态对话框
- 模态对话框,会阻塞当前主界面及其他窗体,后续代码必须等到当前窗体关闭后方可执行
QDialog* pDialog = new QDialog(this);
pDialog->setWindowTitle(QString::fromUtf8("模态对话框"));
pDialog->exec();
qDebug() << __FUNCTION__ <<"模态对话框";
- 非模态对话框,不会阻塞当前主界面及其他窗体,不影响后续代码立即执行
QDialog* pDialog = new QDialog(this);
pDialog->setWindowTitle(QString::fromUtf8("非模态对话框"));
pDialog->show();
qDebug() << __FUNCTION__ <<"非模态对话框";
- 半模态对话框,会阻塞当前主界面及其他窗体,同时不影响后续代码立即执行
QDialog* pDialog = new QDialog(this);
pDialog->setWindowTitle(QString::fromUtf8("半模态对话框"));
pDialog->open();
qDebug() << __FUNCTION__ <<"半模态对话框";
问题解析
解析的问题会从浅到深
弹出的窗体是什么?
模态对话框/非模态对话框
是否有子线程在处理弹出对话框的消息?
没有!且只有一个主线程
是否可以在子线程中更新UI?
不可以!和很多GUI开发类似,均不支持在子线程中更新GUI,如果想更新,可以通过信号槽机制,在槽函数(主线程)中更新UI
弹出的对话框上是如何响应各种事件的?
如果是QDialog::exec()(模态对话框),主线程的事件循环(QEventLoop)处于挂起状态,并且会在主消息循环上开一个子消息循环,直到这个消息循环被退出,外部的主消息循环才会继续。整个过程可以类比成两个嵌套的while循环
while(主事件循环){
processEvents(创建对话框事件){
dialog new_dlg;
while(子事件循环){
};
};
}
事件循环与线程的关系?
一个线程可以有多个事件循环 (1对多)
事件循环的特点?
- 一个线程可以有多个事件循环,但所有的事件循环是嵌套关系,一层套一层。当前QEventLoop被激活时,父QEventLoop会被中断,直到子事件循环结束,父QEventLoop才会继续执行;
- 子事件循环会拥有父事件循环的所有功能,这也是当弹出dialog,GUI不会被卡住的原因;
总结
作为Qt开发经常会搞混线程和事件(消息)循环的关系,如果你真的想让你的程序避免出现异常(crash),那你必须理解这两个的关系。(多看源码,多写demo)
- 主线程=GUI线程
- 一个线程可以有多个事件循环
- 事件循环之间的关系是嵌套
|