由于线程问题,Qt Gui 未更新

Posted

技术标签:

【中文标题】由于线程问题,Qt Gui 未更新【英文标题】:Qt Gui not updated because of threading issue 【发布时间】:2017-11-01 17:05:20 【问题描述】:

我正在使用第三方库,它需要 60-90 秒才能动态加载多个库。这是一个不幸的设计选择,但我不能改变谁构建了他们的代码。

我正在尝试使用 QSplashScreen 至少告诉用户在后台执行此一次性加载时等待。问题是启动画面没有绘画。加载库时,我可以看到一个未绘制空间的窗口。之后我可以在关闭它之前看到启动画面。

我查看了类似的问题(例如Qt Splash Screen not showing),但似乎没有任何问题可以解决我的问题。我试过加载一个空的 QPixmap 并给它一个纯色。这也没有出现。

QApplication a(argc, argv);
QPixmap pxl("icon.bmp");
QSplashScreen qss(pxl);
qss.show();
qss.showMessage(QString::fromStdString("Please wait... Loading"));
a.processEvents();

MainWindow w;
//thread is blocked
w.preLoad();//this is where the lengthy process takes place
w.show();

qss.finish(&w);

我想确保它在开始加载过程之前至少绘制一次。

------------编辑----------- ---------

让我重申对 preLoad 的调用正在阻塞线程。这不是一个选择。我已经为该过程尝试了一个单独的线程。我也尝试为启动画面使用单独的线程(打开它,然后在另一个线程完成时完成)。我尝试在两个线程之间使用信号量来完成此操作,虽然一切正常(包括启动屏幕),但加载需要 200-800 秒。这根本是不可接受的。因此我想从这个角度看看它周围是否有距离。

--------------最终解决方案--------- ------------

感谢下面的 cmets,我知道 Qt 有自己的线程功能。我看到的所有问题似乎都是由 std::thread 和 Qt 自己的实现的相互作用引起的。

我有一个可行的部分解决方案。它不像它应该的那样整洁,但我想将它包含在问题线程中。

//in the main method code described above
MainWindow w;
w.preLoad();
while(w.IsLoading())

  //waiting on semaphore signaling loading is complete
  //this part could probably be done better with QThread 
  //and signals, but it is a quick fix for now
  std::this_thread::sleepfor(std::chrono::milliseconds(500));
  a.processEvents();

w.show();

qss.finish(&w);


//In the MainWindow class
void MainWindow::preLoad()

  loading=true;//semaphore to stall main thread
  QFuture<void> future = QtConcurrent::run(this, &MainWindow::LongMethod);


void MainWindow::LongMethod()

  thirdPartyLibrary.impossibleCall();
  loading=false;//this handles my semaphore

【问题讨论】:

什么是preLoad preLoad 是调用第三方库的方法。第一次通话需要 60-90 秒。没有代码可以显示。足以说它在此期间阻塞了线程。 它是否在辅助线程上运行? 我认为这个任务阻塞了 GUI,如果你有一个繁重的任务,建议在第二个线程中执行它显然尊重 Qt 的条件。 我建议您阅读以下内容:doc.qt.io/qt-5/qtconcurrentrun.html 【参考方案1】:

每个 GUI 都在无限循环中执行,因此 Qt 也使用它,但阻塞任务会导致循环未正确执行,显示出与您观察到的行为类似的不充分行为。

如果想要执行阻塞任务,建议在另一个线程中执行它,因为 Qt 提供了几种可能性:

QThread

QThreadPool and QRunnable

QtConcurrent

我推荐以下link 供您选择适合您情况的选项。

如果您想使用另一个线程中生成的信息更新 GUI 视图,建议使用信号和插槽,或使用 QtConcurrent。

GUI Thread and Worker Thread

如前所述,每个程序在启动时都有一个线程。这 线程被称为“主线程”(在 Qt 应用程序)。 Qt GUI 必须在这个线程中运行。所有小部件和 几个相关的类,例如 QPixmap,在辅助中不起作用 线程。辅助线程通常称为“工作线程” 线程”,因为它用于从主线程中卸载处理工作 线程。

另一种方法是强制 GUI 更新,我们可以使用 qApp->processEvents()。

参考资料:

http://doc.qt.io/qt-5/thread-basics.html http://doc.qt.io/qt-5/threads-technologies.html

【讨论】:

以上是关于由于线程问题,Qt Gui 未更新的主要内容,如果未能解决你的问题,请参考以下文章

Python Qt GUI设计:多线程中信号与槽的使用(基础篇—9)

响应式 Qt GUI,即使是线程

用事件队列解决GUI的操作顺序问题(Qt中处理方法)

用事件队列解决QT GUI的操作顺序问题

如何在linux中增加QT Gui线程优先级[重复]

在 Qt GUI 事件线程中检测到“我正在运行”