如何将QProcess的执行和QProgressBar的前进联系起来,以实现一个非常沉重的计算循环。

问题描述 投票:0回答:1

我有以下的bash脚本要在GUI上执行,通过 QPushButton:

 #!/bin/bash

rostopic echo -b test_LaserScan_PointCloud2_test2.bag -p /scan > test_landing_test_2.csv
rostopic echo -b test_LaserScan_PointCloud2_test2.bag -p /velodyne_points > vel_test_2.csv

脚本会检查每个文件,并提取相关的文件。.csv. 这个过程很重,需要一点时间。问题是 是没有办法知道它需要多长时间,除非我把一个。QProgressBar但我不知道如何正确地连接执行的 QProcess 的进展情况 QProgressBar 正确。

pbar

目前,提取成功,但 QProgressBar 是不会从0开始移动的。

下面我创建了一个最小的可验证的例子,为了完整,源代码可以在这里找到。

mainwindow.h

#include <QMainWindow>
#include <QProcess>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT
    Q_PROPERTY(float progress READ progress NOTIFY progressChanged)
    Q_PROPERTY(bool running READ running NOTIFY runningChanged)
    Q_PROPERTY(bool finished READ finished NOTIFY finishedChanged)

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

    float progress();
    bool running();
    bool finished();

public Q_SLOTS:
    void startComputation();
    void finishComputation();
    void updateProgress(int value);

signals:
    void progressChanged();
    void runningChanged();
    void finishedChanged();

private slots:
    void on_executeBtn_clicked();

private:
    Ui::MainWindow *ui;
    QProcess *executeBash;

    bool m_running = false;
    int m_progressValue = 0;
    bool m_finished = false;
};

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

this->executeBash = new QProcess(this);
    this->executeBash->setProcessChannelMode(QProcess::MergedChannels);
    /*connect(this->executeBash, &QProcess::readyReadStandardOutput, [script = this->executeBash](){
        qDebug() << "[EXEC] DATA: " << script->readAll();
    });*/
    connect(this->executeBash, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
          [script = this->executeBash](int exitCode, QProcess::ExitStatus exitStatus){
        qDebug() << "[EXEC] FINISHED: " << exitCode << exitStatus;
        if(script->bytesAvailable() > 0)qDebug() << "[EXEC] buffered DATA:" << script->readAll();
    });
    connect(this->executeBash, &QProcess::errorOccurred, [script = this->executeBash](QProcess::ProcessError error){
        qDebug() << "[EXEC] error on execution: " << error << script->errorString();
    });

    connect(this->executeBash, &QProcess::readyReadStandardOutput, [this, script = this->executeBash](){

         QString s = QString::fromUtf8(script->readAll());
         qDebug() << "[EXEC] DATA: " << s;
         auto match = QRegularExpression("Stage (\\d+)/(\\d+): (.*)").match(s);
         if (match.hasMatch()) {
             int x = match.captured(1).toInt();
             int y = match.captured(2).toInt();
             QString stage_info = match.captured(3);
             qDebug() << "x = " << x;
             qDebug() << "y = " << y;
             qDebug() << "info = " << stage_info;
             this->updateProgress(x * 100 / y);
         }
    });

    // Initialization of the progressbar
    m_running = false;
    emit runningChanged();
    m_finished = false;
    emit finishedChanged();
    updateProgress(0);

}

MainWindow::~MainWindow()
{
    delete ui;
}


// ProgressBag loading depending on the workload of the .sh file
float MainWindow::progress()
{
  return m_progressValue;
}

bool MainWindow::running()
{
  return m_running;
}

bool MainWindow::finished()
{
  return m_finished;
}

void MainWindow::startComputation()
{
  m_running = true;
  emit runningChanged();
  updateProgress(100);
}

void MainWindow::finishComputation()
{
  m_finished = true;
  emit finishedChanged();

  m_running = false;
  emit runningChanged();
}

void MainWindow::updateProgress(int value)
{
  m_progressValue = value;
  emit progressChanged();

  if (m_progressValue == 100)
      finishComputation();

  ui->progressBarExecuteScript->setValue(value);

}


void MainWindow::on_executeBtn_clicked()
{
    qDebug() << "Button clicked!";
    this->executeBash->start(QStringLiteral("/bin/sh"), QStringList() << QStringLiteral("/home/emanuele/catkin_docking_ws/devel/lib/test.sh")); //will start new process without blocking
    // right after the execution of the script the QProgressBar will start computing
    //ui->progressBarExecuteScript->setValue(executeBash->readAll().toInt());
}

到目前为止,我所做的

1)在设置好所有必要的点后,我遇到了以下情况 本源 在那里,用户遇到了和我一样的问题,但它通过 QDir,不过我不确定这个解决方案。

2) 在翻阅了官方文档后,我发现了关于 未来观察家. 我是这个工具的新手,很难理解如何应用它,这就是为什么我也创建了最小可验证的例子。

3) 我尝试 setValue 根据执行bash文件的进度条。或者更好的是它的推进,如下图所示。

ui->progressBarExecuteScript->setValue(executeBash->readAll().toInt());

我以为这样就能解决这个问题,但是... ... QProgressBar 保持在0值,我不知道为什么。

4) 我咨询了 QProgressBar 官方文档,但我没有找到任何东西来帮助我解决这个问题。

请指出正确的方向来解决这个问题。

c++ qt qt5 qprocess qprogressbar
1个回答
1
投票

首先,修改脚本,输出当前正在做的阶段。

#!/bin/bash
set -e
echo "Stage 1/2: Scan"
rostopic echo -b test_LaserScan_PointCloud2_test2.bag -p /scan > test_landing_test_2.csv
echo "Stage 2/2: Velodyne"
rostopic echo -b test_LaserScan_PointCloud2_test2.bag -p /velodyne_points > vel_test_2.csv

我还添加了 set -e 使其在第一条失败的命令上停止。

现在,你可以在输出流中寻找这些 "阶段xy "标记,然后调用 updateProgress 如果是的话

connect(this->executeBash, &QProcess::readyReadStandardOutput, [this, script = this->executeBash](){
     QString s = QString::fromUtf8(script->readAll());
     auto match = QRegularExpression("Stage (\\d+)/(\\d+): (.*)").match(s);
     if (match.hasMatch()) {
         int x = match.captured(1).toInt();
         int y = match.captured(2).toInt();
         QString stage_info = match.captured(3);
         this->updateProgress(x * 100 / y);
     }
});
© www.soinside.com 2019 - 2024. All rights reserved.