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

Qt Gui not updated because of threading issue

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

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

我查看了类似的问题(例如 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 秒。这简直是​​不能接受的。所以我想从这个角度看看周围有没有。

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

多亏了下面的评论,我才知道 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
}

每个 GUI 都是在无限循环中执行的,因此 Qt 也使用它,但是阻塞任务会导致循环执行不正确,表现出与您观察到的不适当的行为。

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

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

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

GUI Thread and Worker Thread

As mentioned, each program has one thread when it is started. This thread is called the "main thread" (also known as the "GUI thread" in Qt applications). The Qt GUI must run in this thread. All widgets and several related classes, for example QPixmap, don't work in secondary threads. A secondary thread is commonly referred to as a "worker thread" because it is used to offload processing work from the main thread.

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

参考文献: