在插槽中调用 QDialog::exec 会阻塞主事件循环吗?

Posted

技术标签:

【中文标题】在插槽中调用 QDialog::exec 会阻塞主事件循环吗?【英文标题】:Does calling QDialog::exec in a slot block the main event loop? 【发布时间】:2016-02-09 20:47:36 【问题描述】:

我的 Qt 应用程序的主窗口是一个普通的 QMainWindow 子类。在那个窗口中,我有几个按钮;每个都有其clicked 信号连接到自己的插槽,每个插槽创建一个不同的QDialog,如下所示:

void onButtonA_clicked()

    MyADialog* dialog = new MyADialog(this);
    dialog->exec();
    delete dialog;

我一直在阅读这篇文章:https://wiki.qt.io/Threads_Events_QObjects#Events_and_the_event_loop 并且作者说

你永远不应该阻塞事件循环

这让我很担心; exec 是一个阻塞函数,所以根据他所说的(他的例子是Worker::doWork,它做了很多工作并且需要一些时间来完成)我的代码阻塞了事件循环,但我没有注意到任何会建议这个;相反,主窗口似乎表现正常,当我更改代码以使用show() 方法时没有任何区别。

我是否阻塞了事件循环?我应该在这里使用不同的方法吗?

【问题讨论】:

据我所知,int QDialog::exec() 不会阻止 Qt 应用程序,只会阻止父窗口,并且仅当对话框是窗口模式时。 @Tarod 嗯,它是一个阻塞函数(因为它在 QDialog 关闭之前不会返回),这就是我不确定的原因。 【参考方案1】:

QDialog::exec() 阻塞了主事件循环,是的。但它不会阻止 UI,因为它会在 exec() 内部打开一个本地事件循环,该循环会在对话框打开时处理事件。这可能是令人讨厌的错误的来源:(几乎)任何事情都可能在exec() 返回之前发生,外部事件(计时器、网络、IPC 等)可以调用插槽、导致其他对话框出现等。只是用户的方式鉴于大多数此类对话框的模态性质,直接做意想不到的事情通常是有限的。

在调用exec() 时,需要注意可能的问题,不要让应用程序处于不一致的状态,也不要指望事后保持原样。

或者,调用非阻塞QDialog::open() 并连接到finished() 信号。

【讨论】:

一个后续问题 - 将 QMessageBox 与 exec() 一起使用时是否适用相同的情况?使用静态函数 API 实例化的 QMessageBox 怎么样:int ret = QMessageBox::warning... @riverofwind 以上都适用

以上是关于在插槽中调用 QDialog::exec 会阻塞主事件循环吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 QDialog::exec() 期间使用 QThreads 执行 QWidget::grab()

如何在不冻结 GUI 的情况下在单个插槽中实现阻塞进程?

阻止和隐藏 QDialog:exec_() 的替代方案?

在辅助线程中调用 select()/pselect() 会导致主线程阻塞吗?

如何追踪阻塞主(UI)线程的调用?

子线程怎么不阻塞主线程