【问题标题】:Qt Gui not updated because of threading issue由于线程问题,Qt Gui 未更新
【发布时间】: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

标签: c++ qt qthread qtconcurrent qsplashscreen


【解决方案1】:

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

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

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

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

GUI Thread and Worker Thread

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

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

参考资料:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-26
    • 2021-01-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-02-27
    相关资源
    最近更新 更多