【发布时间】:2020-05-13 21:32:18
【问题描述】:
我有以下 bash 脚本要通过 QPushButton 在 GUI 上执行:
#!/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 正确。
到目前为止,提取已成功进行,但 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) 设置完所有必要的点后,我遇到了this source,用户遇到了与我现在相同的问题,但通过QDir 解决了,不过我不确定这个解决方案。
2) 在查看了官方文档后,我发现了future watcher。我是这个工具的新手,很难理解如何应用它,这也是我创建最小可验证示例的原因。
3)我尝试setValue的进度条基于bash文件的执行。或者更好的推进如下图:
ui->progressBarExecuteScript->setValue(executeBash->readAll().toInt());
我认为这可以解决问题,但 QProgressBar 保持在 0 值,我不知道为什么。
4)我查阅了QProgressBar官方文档,但没有找到任何可以帮助我解决问题的东西。
请指出正确的方向来解决这个问题。
【问题讨论】:
-
我认为不可能获得
QProcess的推进,因为您不知道该过程可以存在多少时间。所以一个可能的解决方案是将进度条的最小值、最大值和当前值设置为 0,以获得无限的进度 -
感谢您阅读问题。您的意思是在此期间无限进展正在工作,何时完成将值设置为 100?
-
@Emanuele QProgressBar 只显示进度(它是一个小部件),它不计算它。计算的任务是你的工作,例如,如果你下载 100 个文件,那么你可以指出每个文件是 1%,但另一个开发人员可以计算所有文件的大小(以字节为单位),然后将进度计算为下载百分比bytes 显然这两个数字是不同的,所以如果你不知道如何计算它,那么其他人是不可能帮助你的。在这些中最好设置
progressbar->setRange(0, 0),这将成为一个忙碌的酒吧 -
@eyllanesc,感谢您阅读问题。问题是我不知道第一个命令何时结束(即我不知道提取
.csv的物理时间)并且我不知道第二个命令何时结束(即开始第二次提取及其持续时间)将发生。 -
看来
QProcess不是一个好选择?
标签: c++ qt qt5 qprocess qprogressbar