QProgressBar 完成加载后无法解释的延迟

unexplained delay after QProgressBar finish loading

本文关键字:无法解释 延迟 加载 QProgressBar      更新时间:2023-10-16

我从一个循环(进行一些计算(发出信号,触发位于主GUI上的进度条更新,循环结束后进度条更新为100%(进程结束时进度条变为隐藏(,但比有延迟,进度条保持在100%,有时鼠标变为忙碌, 并且仅在几秒钟后进度条被隐藏(指示我延迟结束(,该循环之后没有任何内容,因此我无法想到任何内容都可以使此延迟。

  • 我应该注意,如果循环计算很轻(意味着不需要做很多计算(,则没有这样的延迟。

发射信号在逻辑层的一个类内,我已经尝试了一些东西,将<QtGui/QApplication>包含在该类中(这对我来说听起来不是正确的做法,因为这是逻辑层,所以为什么它应该需要 QtGui 库,但我只是在测试一些东西(,我将以下代码qApp->processEvents();放在循环中,现在事情似乎窒息了, 没有繁忙的鼠标,但仍然存在延迟(唯一不同的是,当这种延迟发生时,我可以对 GUI 做出反应,但在此延迟结束之前没有更新的结果(。

由于对processEvents()的测试,我认为这与线程有关,但如果是这样,我该如何纠正延迟行为,当然,如果有人认为这可能是其他东西,请告诉。

一些示例代码:

逻辑层类:

#include <QtGui/QApplication>
...
processMethod(...)
{
    Loop(...)
    {
        qApp->processEvents();
        emit processBarSignle(value);
        ...some calculations...
    }
    emit processBarSignle(100);
}

视图层(主窗口(:

on_btn_nextProcess_clicked()
{
    m_ui->pBar_process->setVisible(true);
    LogicClass->processMethod(...);
    m_ui->pBar_process->setVisible(false);
}

谢谢

尝试以下操作:

#include <QtCore/QCoreApplication>
...
processMethod(...)
{
    Loop(...)
    {
        emit processBarSignle(value);
        QCoreApplication::processEvents();
        ...some calculations...
    }
    emit processBarSignle(100);
    QCoreApplication::processEvents();
}

processEvents()是QCoreApplication的一种静态方法,就像它只包含QtCore库中的QCoreApplication就足够了。

此外,您应该在进度条更新后添加processEvents(),而不是在此之前。

请注意,在处理完Qt事件队列中的每个事件之前,processEvents()不会返回。例如,如果有Cancel按钮,则必须检查用户是否在每次调用 .
时实际取消了操作processEvents()您可以使用以下命令排除用户特定的事件,例如鼠标单击/按键

QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents )

但这不允许在循环处于活动状态时单击任何内容(例如取消按钮(。

作为进一步的说明:它应该被称为"processBarSi ng le";-(


关于线程等的说明:

您的整个循环以及任何鼠标点击等仅在一个线程中执行。如果您调用 emit() ,连接到该signalslot会立即执行(除非该插槽实际上在不同的线程中(。同时,循环不会继续!

插槽完成后,循环将继续。在我的示例中,这意味着processEvents()将被调用。现在,如果您的插槽更新了进度条或执行了导致重绘的任何其他操作,则事件队列中将出现重绘事件,并且此重绘现在将发生.
如果在调用槽之前执行processEvents(),则此时不会有可以处理的重绘事件。

同样,循环不会继续,直到processEvents()完全完成。处理完所有挂起事件后,循环将继续计算。

在代码示例中,实际上只有一个线程。 调用 on_btn_nextProcess_clicked() 时,它会显示进度条,然后在同一线程中运行processMethod()。 理想情况下,您希望将 UI 和数据处理逻辑分开。

在初始化中,创建一个单独的QThread,启动它,并通过调用 logicClassObject->moveToThread([您的新线程](将 LogicClass 对象移动到该线程。 然后,将processMethod()变成插槽,在 MainWindow 中创建startProcessing()信号并将两者连接起来。 最后,在MainWindow中创建一个processingDone()插槽,在LogicClass中创建一个finishedProcessing()插槽并连接它们。完成所有设置后,您可以将代码更改为以下内容:

void LogicClass::processMethod(...)
{
    Loop(...)
    {
        emit processBarSignal(value);
        ...some calculations...
    }
    emit processingDone();
}
void MainWindow::on_btn_nextProcess_clicked()
{
    m_ui->pBar_process->setVisible(true);
    emit startProcessing(...);
}
void MainWindow::finishedProcessing()
{
    m_ui->pBar_process->setVisible(false);
}

每当您连接来自两个独立线程的信号和插槽时,都会自动处理多线程。 在一个线程中发出信号会导致另一个线程中的事件被 qeued,该事件仅在第二个线程重新获得控制权时才调用该插槽。

在这种情况下,UI 线程将在处理线程中计划一个事件以开始处理。 然后,处理线程将不断计划进度栏值更新,并最终计划一个事件以在完成后关闭进度栏。 这两个线程将根据操作系统线程计划程序运行,并且处理不会阻止 UI。