Home > Back-end >  QT5: How to get process output
QT5: How to get process output

Time:07-02

#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

CodePudding user response:

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.

CodePudding user response:

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();
}
  • Related