如何逐步更新QMainWindow?

5

我想逐步更新我的QMainWindow。我使用了sleep方法,但我无法看到更改。我希望每3秒钟都能看到更改。

void MainWindow::updateScreen()
{
    ui->pushButton1->show();
    QThread::sleep(3);

    ui->pushButton2->show();
    QThread::sleep(3);

    ui->pushButton3->show();
    QThread::sleep(3);
}

但是在9秒后,所有更改将立即生效。

3个回答

6

在主线程中不要使用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(),因为很多初学者滥用它,认为这是一个“魔法解决方案”。例如cbuchart的解决方案是错误的,因为它只解决了立即的问题而没有解决后台的问题。例如在这9秒钟内尝试改变窗口大小,你能做到吗?不行,因为QThread::sleep()是阻塞的。

在GUI线程中使用QThread::sleep()是一种不良实践,如果你在某个地方看到它,请保持警惕。


2
谢谢您介绍 QTimeLine,我以前从未听说过它。 - Andrii

5
我建议您使用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();});
}

1
应用更改只有在窗口实际绘制时才会变得可见。通过在主 UI 线程上休眠,您阻止系统进行任何绘制,因此在更新函数完成后 9 秒之前无法看到更新发生。
相反,您需要有一个单独的线程,不会阻塞主 UI 线程,每三秒发出信号,使各个按钮出现。确保将这些信号放在 QueuedConnection 上以避免小部件上的竞争条件。
或者,如果您不想浪费线程,也可以有一个持续的更新事件,检查自当前更新周期开始以来经过了多少时间,并仅在足够的时间过去后显示相应的按钮。QTimer 类 提供了一种方便的方法来实现这一点。只需确保不要通过在同一线程上执行重型计算或休眠来阻塞事件循环,否则您将再次无法看到更新。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接