我有以下的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
正确。
目前,提取成功,但 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 官方文档,但我没有找到任何东西来帮助我解决这个问题。
请指出正确的方向来解决这个问题。
首先,修改脚本,输出当前正在做的阶段。
#!/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);
}
});