qtqt5qprocess

QT5: How to get process output


#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


Solution

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