【问题标题】:How to update QMainWindow step by step?如何逐步更新 QMainWindow?
【发布时间】:2019-01-11 04:23:42
【问题描述】:
我想逐步更新我的 QMainWindow。我使用睡眠方法,但我看不到变化。我希望每 3 秒查看一次更改。
void MainWindow::updateScreen()
{
ui->pushButton1->show();
QThread::sleep(3);
ui->pushButton2->show();
QThread::sleep(3);
ui->pushButton3->show();
QThread::sleep(3);
}
但 9 秒后,所有更改都会立即生效。
【问题讨论】:
标签:
c++
qt
qt5
qmainwindow
【解决方案1】:
你永远不会在主线程中使用QThread::sleep(),因为它会阻止 GUI 收到有关事件的通知,因此行为不正确,其他问题争论正确,所以我不会专注于它,我的答案将居中在给你一个我认为最适合使用QTimeLine的解决方案:
const QWidgetList buttons{ui->pushButton1, ui->pushButton2, ui->pushButton3};
QTimeLine *timeLine = new QTimeLine( 3000*buttons.size(), this);
timeLine->setFrameRange(0, buttons.size());
connect(timeLine, &QTimeLine::frameChanged, [buttons](int i){
buttons[i-1]->show();
});
connect(timeLine, &QTimeLine::finished, timeLine, &QTimeLine::deleteLater);
timeLine->start();
我不建议使用processEvents(),因为许多初学者滥用它,认为它是神奇的解决方案,例如the @cbuchart solution 是不正确,因为它解决了眼前的问题但不是背景,例如尝试在这 9 秒内更改窗口的大小。你能做到吗?好吧,不是因为 QThread::sleep() 是阻塞的。
考虑在 GUI 线程中使用QThread::sleep() 是一种不好的做法,如果您在某处看到它,则表示不信任。
【解决方案2】:
我建议你使用QTimer::singleShot静态方法。
void MainWindow::updateScreen()
{
QTimer::singleShot(3000, [this](){ui->pushButton1->show();});
QTimer::singleShot(6000, [this](){ui->pushButton2->show();});
QTimer::singleShot(9000, [this](){ui->pushButton3->show();});
}
【解决方案3】:
在实际绘制窗口之前,应用的更改不会变得可见。通过在主 UI 线程上休眠,您可以完全阻止系统进行任何绘图,因此您在 9 秒后再次离开更新功能之前无法看到更新。
您想要做的是有一个不阻塞主 UI 线程的 单独 线程,它每三秒发出一次信号,导致各个按钮出现。确保将这些信号放在小部件上的 QueuedConnection to avoid race conditions 上。
或者,如果您不想浪费线程,您还可以有一个持续更新事件,该事件检查自当前更新周期开始以来已经过去了多少时间,并仅在足够的时间过去后显示相应的按钮. QTimer class 提供了一种方便的方式来执行此操作。请确保不要通过执行繁重的计算或在同一线程上休眠来阻塞事件循环,否则您将再次无法看到更新。