3

Probelm: I have been trying to run an executable file using QProcess triggering the executable file using a QPushButton and showing the whole result of the output on QTextEdit but without success.

*The error: I don't see the whole output despite, following the official documentation I used this->executeJuliaCheck->readAllStandardOutput()

I have an executable file called check_julia.sh which is located in /home/esoMars/Alignsys/scripts/check_julia.sh which is in the qrc folder of a standard Qt5 project. The file is very simple and is below:

#!/bin/bash

echo "Checking"
cd /home/esoMars/julia-1.7.3/bin
julia

If I type on my home folder the command (base) eso@eso-Oryx-Pro:~$ julia the folloing output appears:

   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.7.3 (2022-05-06)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

julia> 

All this happens because I use the command line.

Desired goal: I would like NOT to use a command line, but rather I am trying to use a small graphical user interface where to show the output of the same command(base) eso@eso-Oryx-Pro:~$ julia

The way I am doing it is by using a QPushButton that check if julia is installed and show the output on a QTextEdit.

Below what I have done so far:

main.cpp

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QProcess>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void check_julia_installation();

private slots:
    void on_juliaCheckBtn_clicked();

private:
    Ui::MainWindow *ui;
    QProcess *executeJuliaCheck;
    void executeJulia(QString command);
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QDir>
#include <QStringLiteral>
#include <iostream>

using namespace std;

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    // Check Julia Installation
    check_julia_installation();
}

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

void MainWindow::check_julia_installation()
{
    // Execution of the QProcess
    this->executeJuliaCheck = new QProcess(this);
    this->executeJuliaCheck->setProcessChannelMode(QProcess::MergedChannels);
    QObject::connect(this->executeJuliaCheck, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
            [this](int exitCode, QProcess::ExitStatus exitStatus){
            qDebug() << "CODE " << exitCode << exitStatus;

                if(exitCode == 0)
                {
                    QString stdOutput = QString::fromUtf8(this->executeJuliaCheck->readAllStandardOutput());
                    qDebug() << stdOutput;
                    ui->textEdit->setText(stdOutput);
                    ui->outputLineEdit->setText("SUCCESS: JULIA IS PROPERLY INSTALLED");
                }
                else
                {
                    QString stdErr = QString::fromUtf8(this->executeJuliaCheck->readAllStandardError());
                    qDebug() << stdErr;
                    QString stdOutput = QString::fromUtf8(this->executeJuliaCheck->readAllStandardOutput());
                    qDebug() << stdOutput;
                    ui->textEdit->setText(stdErr + "\n" + stdOutput);
                    ui->outputLineEdit->setText("CONNECTION ERROR: JULIA NOT PRESENT");
                }
                ui->juliaCheckBtn->setEnabled(true);
    });
}


void MainWindow::on_juliaCheckBtn_clicked()
{
  this->executeJuliaCheck->start("sh",QStringList() << "-c" << "echo /home/esoMars/Alignsys/scripts/check_julia.sh");

  if(! this->executeJuliaCheck->waitForStarted()) //default wait time 30 sec
      qWarning() << " cannot start process ";

  int waitTime = 60000 ; //60 sec
  if (! this->executeJuliaCheck->waitForFinished(waitTime))
           qWarning() << "timeout .. ";
  this->executeJuliaCheck->waitForFinished();

ui->juliaCheckBtn->setEnabled(true);

}

Updates

A user suggested to reduce the clicked button to the following statement. I tried that but unfortunately the QProcess does not do anything:

void MainWindow::on_juliaCheckBtn_clicked()
{
    this->executeJuliaCheck->waitForStarted();
    this->executeJuliaCheck->start("sh",QStringList() << "-c" << "echo /home/esoMars/Alignsys/scripts/check_julia.sh");
    ui->juliaCheckBtn->setEnabled(true);
}

I looked up QProcess quite a while before writing and searched a lot. I found quite a few posts that I read and studied to understand the problem. One post suggested to look at setWorkingDirectory which I did but that didn't help much.

Another posts suggested to use for waitForFinished() just in case other processes are running but it is not my case. Despite a clean exit I don't see the whole output. However, for debugging reasons I put this->executeJuliaCheck->start("sh",QStringList() << "-c" << "echo /home/esoMars/Alignsys/scripts/check_julia.sh"); so that I could confirm the executable file read. However, I still can't see the whole output

I looked also at additional posts such as this one but I still could not figure out how to show the whole output.

Thanks for pointing in the right direction.

EsoMars
  • 337
  • 3
  • 14
  • You said several times "I don't see the whole output" What output do you see? – drescherjm Aug 23 '22 at 19:47
  • @drescherjm, I refer to the out put of `julia`, which means show the banner on the screen. I would like to do it through a `QPushbutton` that triggers the executable I mentioned above. Hope that clarifies more. – EsoMars Aug 23 '22 at 20:17
  • Your calls to waitForFinished() are probably part of the problem especially since the answer says julia will wait for input meaning the spawned process wont finish. Also in Qt the GUI will not update until your function exits (so it returns to the Qt message loop) so waitForFinished() is usually a not the best practice in a GUI application outside a destructor. – drescherjm Aug 23 '22 at 20:24
  • Thanks for the comments @drescherjm, I have read several posts but still I could not find a solution to the problem. Could you please post how the code should be modified? That would really help a lot. I have been struggling a bit in the past couple of days to understand `QProcess` – EsoMars Aug 23 '22 at 20:24
  • Try commenting out both calls for `waitForFinished()` that you have in `on_juliaCheckBtn_clicked()` you also need to add an additional connect to this signal: [https://doc.qt.io/qt-5/qprocess.html#readyReadStandardOutput](https://doc.qt.io/qt-5/qprocess.html#readyReadStandardOutput) – drescherjm Aug 23 '22 at 20:26
  • if I comment out both `waitForFinished()` in `on_juliaCheckBtn_clicked()` and only remain with one i does not start the process unfortunately and I don't understand why. – EsoMars Aug 23 '22 at 20:31
  • `this->executeJuliaCheck->waitForStarted()` should ensure the process is started if possible. – drescherjm Aug 23 '22 at 20:31
  • Here is an additional QProcess example: [https://stackoverflow.com/questions/60016900/how-to-read-when-qprocess-need-user-input-with-qt](https://stackoverflow.com/questions/60016900/how-to-read-when-qprocess-need-user-input-with-qt) – drescherjm Aug 23 '22 at 20:40
  • I updated the answer with your suggestions but the `QProcess` does not start. In the question I added *Updates*. What am I missing? – EsoMars Aug 23 '22 at 20:43
  • In any case, the executable does not seem to be triggered, and I don't know why... – EsoMars Aug 23 '22 at 20:44
  • `"sh"` you may need the full path to `sh` – drescherjm Aug 23 '22 at 20:47
  • `this->executeJuliaCheck->waitForStarted();` must be after `start()` not before. – drescherjm Aug 23 '22 at 20:48
  • Sorry it is not working. I keep trying and hopefully I will find a solution. – EsoMars Aug 23 '22 at 21:55

1 Answers1

0

I believe you want to see the Julia banner in order to show it to the user. The problem is that once started, the Julia process is waiting for the input.

This can be simply circumvented as:

$ echo "exit()" | julia --banner=yes
               _
   _       _ _(_)_     |  Documentation: https://docs.julialang.org
  (_)     | (_) (_)    |
   _ _   _| |_  __ _   |  Type "?" for help, "]?" for Pkg help.
  | | | | | | |/ _` |  |
  | | |_| | | | (_| |  |  Version 1.8.0 (2022-08-17)
 _/ |\__'_|_|_|\__'_|  |  Official https://julialang.org/ release
|__/                   |

$

The above command produces the banner (so you can collect it by reading the standard output of your process) and then immediately exits.

Przemyslaw Szufel
  • 40,002
  • 3
  • 32
  • 62
  • Thanks for the comment. Yes I would like to show the output. Can you also add in the answer how should the code be modified? Thanks so much for your time. – EsoMars Aug 23 '22 at 20:16
  • I understand you are running `check_julia.sh` - so this is the command you should execute (`echo "exit()" | julia --banner=yes`). You could also send the `"exit()"` via the standard input stream directly from the C code. You will get the output on standard output stream (the code is for an example here https://stackoverflow.com/questions/17344807/read-qprocess-output-to-string). You could redirect it to file instead and read the file eg. `echo "exit()" | julia --banner=yes > file.txt` – Przemyslaw Szufel Aug 23 '22 at 20:26
  • Thanks for he additional comment. Could you please update your answer adding what you suggested please? – EsoMars Aug 23 '22 at 20:34
  • In any case, the executable does not seem to be triggered, and I don't understand why. – EsoMars Aug 23 '22 at 20:45
  • shouldn't you execute that simply as `bash /home/esoMars/Alignsys/scripts/check_julia.sh`? rather than use `-c` parameter etc? – Przemyslaw Szufel Aug 23 '22 at 21:38
  • That is exactly what I thought. But the executable won't start. Yes I tried without `-c` too but that didn't anything. I don't understand what I am missing. – EsoMars Aug 23 '22 at 21:54