首页 > 解决方案 > QProgressBar如何表达QProcess的延迟操作?

问题描述

我使用 QProcess 调用 Ping 命令,并使用 waitForFinished 等待命令执行结束。现在想用一个QProgressBar进度条connect_gress来表示初始状态的范围是(0, 100),当QProcess开始启动的时候就变成了(0, 0),也就是busy状态,命令调用由 QProcess 结束。时间变回 (0, 100)

void web::gress_begin(){
ui->connect_gress->setRange(0, 0);
}

void web::gress_finish(){
ui->connect_gress->setRange(0, 100);
ui->connect_gress->setValue(100);
}

这是 QProcess 的一部分

QProcess excping;

connect(&excping, SIGNAL(started()), this, SLOT(gress_begin()));
connect(&excping, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(gress_finish()));

excping.start(cmdstr);
excping.waitForStarted();
excping.waitForFinished(-1);

但是程序运行的时候,我按下按钮,主界面的connect_gress并没有进入busy状态,直到命令结束,connect_gress的值会变成100,也就是gress_finish执行成功,显示成功, gress_start 也是执行了,但是没有成功显示。

标签: qtqt5

解决方案


QProcess::waitForFinished阻塞当前线程。我相信你在主线程又名 GUI 线程中调用它。所以主线程永远不会改变处理事件,包括paintEvent。在 ping 进程运行时 GUI 也被冻结。所以用户此时不能做任何事情,我不知道这是否是你的意图。

解决它的最简单方法根本不等待完成。但在这种情况下,用户可以在 ping 时玩弄 ui。excping是一个堆栈变量,因此在这种情况下它可能会在发出完成之前死亡。我们可以在堆中创建它并在完成信号后删除。

auto excping = new QProcess(this);

connect(excping, SIGNAL(started()), this, SLOT(gress_begin()));
connect(excping, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(gress_finish()));
connect(excping, SIGNAL(finished(int, QProcess::ExitStatus)), excping, SLOT(deleteLater()));

excping->start(cmdstr);
excping->waitForStarted();
// no waitForFinished

另一种解决阻塞的简单方法是强制事件循环处理事件。我不赞成processEvents。文档也不鼓励使用它。所以请不要养成像某种魔法酱一样折腾的习惯。

void web::gress_begin(){
    ui->connect_gress->setRange(0, 0);
    QCoreApplication::processEvents();
}

您还可以调整函数的执行延迟。签出 Qt::QueuedConnectionQMetaObject::invokeMethod


推荐阅读