1

我从一个循环(进行一些计算)发出信号,该信号触发位于主 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);
}

谢谢

4

2 回答 2

0

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

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

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);
}

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

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

于 2013-01-18T13:50:29.400 回答
0

尝试以下操作:

#include <QtCore/QCoreApplication>
...

processMethod(...)
{
    Loop(...)
    {
        emit processBarSignle(value);
        QCoreApplication::processEvents();
        ...some calculations...
    }
    emit processBarSignle(100);
    QCoreApplication::processEvents();
}

processEvents()QCoreApplication的静态方法,就像只包含库QCoreApplication的一部分就足够了QtCore

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

请注意,processEvents()直到处理完 Qt 事件队列中的每个事件后才会返回。如果有例如一个Cancel按钮,您将不得不检查用户是否真的在您每次调用时取消了操作processEvents()
您可以通过使用排除特定于用户的事件,例如鼠标单击/按键

QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents )

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

作为进一步的说明:它应该被称为“processBarSingle ;-)


澄清线程等:

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

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

processEvents()再一次,循环在完全完成之前不会继续。处理完所有未决事件后,循环继续进行您的计算。

于 2013-01-18T11:58:33.287 回答