QT5:如何获取过程输出

发布于 2025-02-11 15:18:07 字数 970 浏览 3 评论 0 原文

#include <iostream>
#include <QProcess>

int main(int argc, char *argv[])
{
    QProcess proc;
    proc.setProgram("/home/weber/exp/qt5/build_bsptrans/bsptrans");
    proc.setCurrentReadChannel(QProcess::StandardOutput);
    proc.start();
    if(!proc.waitForStarted())
    {
        std::clog << "Error start:" << proc.errorString().toStdString() << std::endl;
        return -1;
    }
    char buffer[128];
    qint64 length=proc.read(buffer,128);
    int i=0;
    while(length >=0 && i<10)
    {
        std::cout << length << std::endl;
        i++;
        length=proc.read(buffer,128);
    }
}

BSPTRANS是一个简单的程序,它在Stdout上写数字。上面的代码只需启动该过程,然后尝试读取Stdout。

proc.Read()长度的结果总是0。为什么?

该行为是相同的(Linux QT5.9,Windows QT5.12。)

如何用QT5编写程序M,该程序可以解释Stdout的输出? 目标是一个长期运行的程序将返回Stdout的百分比进度,而调用QT-Programm在Qprogressbar上显示了进度。 上面的代码仅行使处理Qprocess

非常感谢 鲁道夫

#include <iostream>
#include <QProcess>

int main(int argc, char *argv[])
{
    QProcess proc;
    proc.setProgram("/home/weber/exp/qt5/build_bsptrans/bsptrans");
    proc.setCurrentReadChannel(QProcess::StandardOutput);
    proc.start();
    if(!proc.waitForStarted())
    {
        std::clog << "Error start:" << proc.errorString().toStdString() << std::endl;
        return -1;
    }
    char buffer[128];
    qint64 length=proc.read(buffer,128);
    int i=0;
    while(length >=0 && i<10)
    {
        std::cout << length << std::endl;
        i++;
        length=proc.read(buffer,128);
    }
}

bsptrans is a simple program which write numbers on stdout. the code above simply starts the process and try to read the stdout.

The result of proc.read() length is always 0. Why ?

The behaviour is the same (linux Qt5.9, Windows Qt5.12.)

How to write a programm with Qt5, which can interprete the output of the stdout ?
The goal is that a long running program returns the progress in percent on stdout, and the calling QT-Programm displays the progress on a qprogressbar.
The code above only exercises the handling of qprocess

Thank you very much
Rudolf

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

雨落星ぅ辰 2025-02-18 15:18:07

非常感谢您的有趣答案。看来,Readline正在投票。正如Guitarpicva所写的那样,使用信号和插槽是很好的:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>
#include <QRegExp>

namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow
{
   Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
   void procStarted();
   void procFinished(int exitcode,QProcess::ExitStatus exitstatus);
   void procReadStdout();

signals:
   void valueChanged(int);

private slots:
   void on_startButton_clicked();

private:
   Ui::MainWindow *ui;
   QProcess proc_;
   QRegExp reproz_;
};

#endif // MAINWINDOW_H

sourcefile:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    proc_(this),reproz_("(\\d+)%")
{
   ui->setupUi(this);

   proc_.setProgram("/home/weber/exp/qt5/build_bsptrans/bsptrans");
   connect(&proc_,SIGNAL(started()),this, SLOT(procStarted()));
       

    connect(&proc_,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(procFinished(int,QProcess::ExitStatus)));
    connect(&proc_,SIGNAL(readyReadStandardOutput()),this,SLOT(procReadStdout()));
       connect(this,SIGNAL(valueChanged(int)),ui->progressBar,SLOT(setValue(int)));
    proc_.setReadChannel(QProcess::StandardOutput);
}

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

void MainWindow::procStarted()
{
    qDebug() << "Process started ...";
}

void MainWindow::procFinished(int exitcode,QProcess::ExitStatus exitstatus)
{
    qDebug() << "Process finished exitcode=" << exitcode << " Status=" << exitstatus;
}

void MainWindow::procReadStdout()
{
     char  buffer[1024];
     qint64 length = proc_.readLine(buffer,128);
     if(length > 0)
     {
        QString line(buffer);
        qDebug() << line;
        int pos = reproz_.indexIn(line);
        if(pos > -1)
        {
            QString valuestr = reproz_.cap(1);
            qDebug() << valuestr;
            emit valueChanged(valuestr.toInt());
        }
     }
}


void MainWindow::on_startButton_clicked()
{
    proc_.start();
    if(!proc_.waitForStarted())
    {
        qDebug() << "start: " << proc_.errorString();
    }
}

问候
鲁道夫

Thank you very much for the interesting answers. It seems, that readline is polling. As guitarpicva writes, it is good to use the signal and slots:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>
#include <QRegExp>

namespace Ui {
  class MainWindow;
}

class MainWindow : public QMainWindow
{
   Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
public slots:
   void procStarted();
   void procFinished(int exitcode,QProcess::ExitStatus exitstatus);
   void procReadStdout();

signals:
   void valueChanged(int);

private slots:
   void on_startButton_clicked();

private:
   Ui::MainWindow *ui;
   QProcess proc_;
   QRegExp reproz_;
};

#endif // MAINWINDOW_H

The sourcefile:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow),
    proc_(this),reproz_("(\\d+)%")
{
   ui->setupUi(this);

   proc_.setProgram("/home/weber/exp/qt5/build_bsptrans/bsptrans");
   connect(&proc_,SIGNAL(started()),this, SLOT(procStarted()));
       

    connect(&proc_,SIGNAL(finished(int,QProcess::ExitStatus)),this,SLOT(procFinished(int,QProcess::ExitStatus)));
    connect(&proc_,SIGNAL(readyReadStandardOutput()),this,SLOT(procReadStdout()));
       connect(this,SIGNAL(valueChanged(int)),ui->progressBar,SLOT(setValue(int)));
    proc_.setReadChannel(QProcess::StandardOutput);
}

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

void MainWindow::procStarted()
{
    qDebug() << "Process started ...";
}

void MainWindow::procFinished(int exitcode,QProcess::ExitStatus exitstatus)
{
    qDebug() << "Process finished exitcode=" << exitcode << " Status=" << exitstatus;
}

void MainWindow::procReadStdout()
{
     char  buffer[1024];
     qint64 length = proc_.readLine(buffer,128);
     if(length > 0)
     {
        QString line(buffer);
        qDebug() << line;
        int pos = reproz_.indexIn(line);
        if(pos > -1)
        {
            QString valuestr = reproz_.cap(1);
            qDebug() << valuestr;
            emit valueChanged(valuestr.toInt());
        }
     }
}


void MainWindow::on_startButton_clicked()
{
    proc_.start();
    if(!proc_.waitForStarted())
    {
        qDebug() << "start: " << proc_.errorString();
    }
}

Greetings
Rudolf

时光无声 2025-02-18 15:18:07

首先使用QTCreator使其更容易,尽管还有更多文件。从QT Creator的向导启动“控制台项目”,使创建所有适当的文件的简短工作。这样,在添加主类时(在此处展示)时,重要的是要亚班级qobject,因此您可以使用信号和插槽!

首先,showit.pro文件,该文件有助于使用qmake构建makefile。该文件是由QT Creator创建的100%样板。

QT -= gui

CONFIG += c++17 console
CONFIG -= app_bundle

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp \
        showit.cpp

# Default rules for deployment.
qnx: target.path = /tmp/${TARGET}/bin
else: unix:!android: target.path = /opt/${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    showit.h

然后是标题:

#ifndef SHOWIT_H
#define SHOWIT_H

#include <QObject>
#include <QProcess>

class showit : public QObject
{
    Q_OBJECT // <<<<< That macro is key!
public:
    showit();
    QProcess *proc = nullptr;
private slots:
    void on_readyRead();
};

#endif // SHOWIT_H

利用QT对象模型以及信号和插槽的CPP类:

#include "showit.h"
#include <iostream>

showit::showit()
{
    proc = new QProcess();
    proc->setProgram("/home/weber/exp/qt5/build_bsptrans/bsptrans");
    proc->setProcessChannelMode(QProcess::MergedChannels);
    proc->setCurrentReadChannel(QProcess::StandardOutput);
    connect(proc, &QProcess::readyRead, this, &showit::on_readyRead);
    proc->start();
    if (!proc->waitForStarted()) {
        std::clog << "Error start:" << proc->errorString().toStdString() << std::endl;
        return;
    }
}

void showit::on_readyRead()
{
    std::cout << proc->readAll().data();
}

然后main.cpp将其全部踢开!

#include "showit.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    showit q;
    return a.exec();
}

Starting by using QtCreator makes this a bit easier, though a few more files. Starting a "Console project" from Qt Creator's wizard makes short work of creating all of the appropriate files. In doing so, it's important to subclass QObject when adding the main class (showit here), so you may use signals and slots!

First the showit.pro file which helps build the Makefile using qmake. This file is 100% boilerplate created by Qt Creator.

QT -= gui

CONFIG += c++17 console
CONFIG -= app_bundle

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp \
        showit.cpp

# Default rules for deployment.
qnx: target.path = /tmp/${TARGET}/bin
else: unix:!android: target.path = /opt/${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    showit.h

Then the header:

#ifndef SHOWIT_H
#define SHOWIT_H

#include <QObject>
#include <QProcess>

class showit : public QObject
{
    Q_OBJECT // <<<<< That macro is key!
public:
    showit();
    QProcess *proc = nullptr;
private slots:
    void on_readyRead();
};

#endif // SHOWIT_H

The the CPP class which leverages the Qt Object model and signals and slots:

#include "showit.h"
#include <iostream>

showit::showit()
{
    proc = new QProcess();
    proc->setProgram("/home/weber/exp/qt5/build_bsptrans/bsptrans");
    proc->setProcessChannelMode(QProcess::MergedChannels);
    proc->setCurrentReadChannel(QProcess::StandardOutput);
    connect(proc, &QProcess::readyRead, this, &showit::on_readyRead);
    proc->start();
    if (!proc->waitForStarted()) {
        std::clog << "Error start:" << proc->errorString().toStdString() << std::endl;
        return;
    }
}

void showit::on_readyRead()
{
    std::cout << proc->readAll().data();
}

And then main.cpp to kick it all off!

#include "showit.h"
#include <QCoreApplication>
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    showit q;
    return a.exec();
}
日暮斜阳 2025-02-18 15:18:07

我认为您的问题是,当您尝试从Stdout阅读时,该过程尚未写入任何数据。

关键是 Qiodevice :: Read 如果没有可用数据,则立即返回。

我建议您使用 循环,然后 qiodevice :: read 再次在周期中,而数据可用于读取或 qiodevice: :readall 。但是您应该注意, Qiodevice :: waitforreadyread(-1)

块,直到可以读取新数据并发出readyRead()信号为止。

因此,如果您想读取数据,请在GUI中显示它们,并且该应用程序应负责,则应在单独的线程中实现Process的输出的读数。

另一个解决方案是创建一个插槽来处理 您可以在其中实现相同的数据读取算法的信号。

现在,您可以选择最合格的方式。

I think that your problem is that the process have not written any data at that moment, when you try to read it from stdout.

The point is that QIODevice::read method returns immediately if no data available.

I suggest you to use QIODevice::waitForReadyRead(-1) on a while cycle and then QIODevice::read in a cycle again, while data is available for reading, or QIODevice::readAll. But you should note that QIODevice::waitForReadyRead(-1)

blocks until new data is available for reading and the readyRead() signal has been emitted.

So if you would like to read data, show it in GUI and the app should be responsible, you should implement the reading of process's output in a separate thread.

Another solution is to create a slot to handle QIODevice::readyRead signal where you can implement the same data reading algorithm.

Now it's up to you to choose the most eligible way.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文