nick
nick

Reputation: 63

Get Output in Qt: 'QProcess::start()' and 'QProcess:readAllStandardOutPut()'

Platform:Windows10 I use QProcess::start execute the Python file(in same diretory),but i can't get results from readAllStandardOutput function.

Python file code :

test.py

print “hello,world”

Qt:

#include <QProcess>
#include <QStringList>
#include <QByteArray>
#include <QDebug>

void fun1(){
    QProcess process;
    process.start("python test.py");
    process.waitForFinished();
    QByteArray a = process.readAllStandardOutput();


    qDebug()<<a;
}

int main(){
    fun1();
}

I can get output when I execute test.py, but when I use readAllStandardOutput I can't get it. It a just print "" without data.

#include <QProcess>
#include <QStringList>
#include <QByteArray>
#include <iostream>
#include <QDebug>

void fun2(){
    QStringList args("F:/test.py");
    QProcess process;
    process.execute(QString("Python.exe"), args);
    QByteArray a = process.readAllStandardOutput();
    process.waitForFinished();
    qDebug()<<a;

}

int main(){
    fun1();
    qDebug<<"--------";
    fun2();
}

In fun2 function, the function execute() can print "hello,world" at Qt terminal, but I can't get the standard output with readAllStandardOutput function. The a also print "" without data i don't know why?

Because I want to use the python module "requests" to visit a url directly, so I want my C++ code can execute this python file. So, if you have a better way, tell me please.

Upvotes: 2

Views: 5879

Answers (3)

Gabriella Giordano
Gabriella Giordano

Reputation: 1238

When QProcess::start() is used, the process is started in another thread and it is executed asynchronously, to avoid blocking the GUI thread of your application (if you have a GUI). Using the waitForReadyRead() will block the execution of your application as well, till the process ends.

You may consider using Qt's signal/slot system to catch the output of your process when available, without blocking the main thread.

This version of fun1() requires C++11:

void fun1(){
    // instantiate dynamically to avoid stack unwinding before the process terminates
    QProcess* process = new QProcess(); 

    // catch data output
    QObject::connect(process, &QProcess::readyRead, [process] () {
        QByteArray a = process->readAll();
        qDebug() <<  a;
    });

    // delete process instance when done, and get the exit status to handle errors.
    QObject::connect(process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
                     [=](int exitCode, QProcess::ExitStatus /*exitStatus*/){
        qDebug()<< "process exited with code " << exitCode;
        process->deleteLater();
    });

    // start the process after making signal/slots connections 
    process->start("python test.py");
}

In this way you could also manage execution errors, or at least make the user aware of it.

Upvotes: 4

HAC
HAC

Reputation: 11

use waitForReadyRead() Process API to read data. waitForReadyRead() blocks until new data is available for reading on the current read channel.

void fun1(){
    QProcess process;
    process.start("python test.py");
    process.waitForReadyRead();
    QByteArray a = process.readAllStandardOutput();


    qDebug()<<a;
}

Upvotes: 0

TheSHEEEP
TheSHEEEP

Reputation: 3132

Getting process output is a bit cumbersome in Qt, unfortunately.

Here's how I do it in one project:

QProcess process;
process.setProcessChannelMode(QProcess::MergedChannels);
process.start(processToStart, arguments)

// Get the output
QString output;
if (process.waitForStarted(-1)) {
    while(process.waitForReadyRead(-1)) {
        output += process.readAll();
    }
}
process.waitForFinished();

This probably raises a few questions:

setProcessChannelMode(QProcess::MergedChannels) will merge the output channels. Various programs write to different outputs. Some use the error output for their normal logging, some use the "standard" output, some both. Better to merge them.

readAll() reads everything available so far.

It is put in a loop with waitForReadyRead(-1) (-1 means no timeout), which will block until something is available to read. This is to make sure that everything is actually read.
Simply calling readAll() after the process is finished has turned out to be highly unreliable (buffer might already be empty).

Upvotes: 0

Related Questions