【问题标题】:How to run several QDialogs simultaneously in different threads?如何在不同的线程中同时运行多个 QDialogs?
【发布时间】:2015-11-06 19:25:04
【问题描述】:

我正在使用 Qt Creator 开发 Qt 5.5。 我有一个名为 settingsWindow 的大类,顾名思义,它负责各种设置。然后这些设置用于启动一些 QDialogs,这些 QDialogs 在 qGraphicsView 内的场景上显示非常复杂的动画,通过 QCoreApplication::processEvents() 不断更新,这反过来又保持 GUI 响应。动画是通过 QDialog 的 start() 方法启动的。 我想同时运行这些 QDialogs,例如通过一个按钮 start 来同时启动它们。我尝试使用包装器,即从 QObject 继承的简单类,每次将其分配给不同的线程,但如果我启动 QDialog 一切正常,当我启动第二个时,第一个“块”(动画停止并且仅在第二个 Qdialog 中动画可见)。 我唯一的解决方案是为它们中的每一个启动一个单独的 QProcess(这样我可以确定它们分别运行并且在不同的线程上),但我需要重写逻辑(每个 QDialog 的单独程序)。

有更简单的解决方案吗?提前谢谢你。

【问题讨论】:

  • 如何显示对话框?你打电话给QDialog::exec()吗?
  • 我调用QDialog::show(),然后调用name_of_the_dialog->start(),开始动画。

标签: c++ multithreading qt qdialog


【解决方案1】:

它不能在单个进程中完成。任何触及QWidget 的东西都只能在主线程中运行。您的代码恰好运行完全是巧合,您依赖于未定义的行为,而 Qt 从来没有打算以这种方式使用。对此没有任何测试,等等:您只能靠自己,您必须深入研究 Qt 代码才能弄清楚要更改哪些内容才能允许这样做。

如果您制作的动画过于复杂而无法在 GUI 线程中渲染,并且您坚持使用旧版小部件,则必须使用 QPainter 将它们渲染到 QImage 中,作为异步工作通过QtConcurrent::run。然后,异步工作人员会将图像发送给对话框,后者随后会将它们传送到屏幕上。

有关两个相关示例的链接,请参阅 this answer

否则,请使用 QML。对于大多数事情,从 CPU 的角度来看,QML 动画几乎是无操作的。 GPU 完成了所有的渲染,它的表现令人钦佩。

多处理方法当然也是可行的。随意使用指定用于进程间通信的管道的随机名称的参数启动相同的可执行文件,并修改行为(第一个与第二个对话框等)。请参阅this answer,了解如何轻松启动自己。

【讨论】:

  • “您的代码运行完全是巧合”到底是什么意思?您是说试图在线程中移动 QDialog 吗?我想我会继续我的想法,即每个 QDialog 都有一个单独的过程。关于 QDialogs 之间的通信,我不需要进程间通信(它们实际上不返回任何内容,并且它们处理与 settingsWindow 完全不同的变量)。 “动画”实际上是一个图形构造,从源节点开始,尝试到达目标节点,在场景中添加新的点和线。 QPainter 是渲染它的好方法吗?
  • 您的意思是试图在线程中移动 QDialog 吗? 是的。不要那样做。它不应该工作,它不受支持,如果您有任何问题,您实际上是靠自己的(当然,除非您雇用某人)。 “动画”实际上是一个图形构造,从源节点开始并尝试到达目标节点 将数据和在其上运行的算法与可视化分开。那是你的问题。渲染不会太慢,很有可能。不过,您的计算正在减慢渲染速度。
【解决方案2】:

没有发布任何代码很难提供帮助。

您可以尝试为每个对话框创建一个线程,然后将一个对话框移动到每个线程(使用QObject::moveToThread)。

每个线程必须不时给其他线程执行指令的机会(调用QThread::yieldCurrentThreadQThread::sleep)。否则,如果一个线程在一个巨大的循环中做某事,它永远不会给其他线程做某事的机会。

【讨论】:

  • 是的,事实上正是这个巨大的循环导致一个线程阻塞了另一个线程。我以为,由于我有一个多核处理器,每个生成的线程都会自动分配给另一个核,但似乎不是这种情况。奇怪的是,无论如何 GUI 在每个 QDialog 中都有响应(我在每个 QDialog 中也有一个简单的计时器,显示自开始以来经过的时间,并且它继续平稳运行)。您如何建议实现一个线程的停止以让另一个线程继续? QTimer 每 100 毫秒从一个线程交换到另一个线程?不会造成开销吗?
  • 尝试从线程调用yieldCurrentThread,这会将控制权传递给另一个。
  • 怎么样?如果我创建了两个 QDialogs,然后做 QThread* t1 = new QThread; QThread* t2 = new QThread; dialog1->moveToThread(t1); dialog2->moveToThread(t2); dialog1->show(); dialog2->show(); dialog1->start(); dialog2->start(); 我应该使用 QTimer 和每个 n 毫秒睡眠/产生一个线程并继续另一个?
  • 是的,试试类似的方法。或者在你的处理循环中插入一个 yield 指令。
猜你喜欢
  • 1970-01-01
  • 2012-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-13
  • 1970-01-01
  • 2018-06-02
  • 1970-01-01
相关资源
最近更新 更多