skip to Main Content

I have Embedded Qt applicaiton runing on my HMI screen.
I am trying to execute some commands to execute in cmd.
I am calling this c++ function simply from QML.
Everytime I call it it hangs on process.start().
Do anyone have any experience for such issue? please help.
I have ceated a simple function to print out date and it still hangs at process.start() regardless what cmd I execute.

cmd.sprintf("date +%%F' '%%X");
qDebug() << "cmd: " << cmd;
process.start("sh", QStringList()<<"-c"<<cmd);
process.waitForFinished(1000);
dtval = process.readAllStandardOutput();
process.close();

I am using Qt 5.9 on Ubuntu 18.04.6LTS platform.

2

Answers


  1. Chosen as BEST ANSWER

    What I found on my side is, the issue was debug mode. If I create release and press the run button (Ctlr + R) then it is absolutely fine (Not the debug button but Run button on QtCreator). Without any changes to my code. I have no idea what that would make the difference on application though.


  2. I did some further troubleshooting, and I think I found a mistake in your start command. It should be:

        process.start("/bin/sh", QStringList()<<"-c"<<"date"<<"+%F +%X");
    

    Your mistake was your command date was joined to its arguments whereas it should have been separate.

    Since you were interested in QML, I mocked up the following C++ application where I invoked a similar command:

        process.start("/bin/sh", ["-c", "date", "+%F +%X"], Process.ReadOnly);
    

    I also made the program listen and wait for either onReadyReadStandardOutput and/or onReadyReadStandardError before calling process.readAllStandardOutput() and/or process.readAllStandardError() respectively.

    For convenience, I also mapped the OpenMode flags so that they can be used in QML.

    When you run the program there’s a "Go!" button in the footer. When you click on it, it runs the process.start(), and the output, be it either regular output or error gets displayed in the ListView above. When I run it, I see an output like this:

    qt-process-app

    #qt-process-app.pro
    QT += quick
    
    CONFIG += c++11
    
    # 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 += 
            Process.cpp 
            main.cpp
    
    RESOURCES += qml.qrc
    
    # Additional import path used to resolve QML modules in Qt Creator's code model
    QML_IMPORT_PATH =
    
    # Additional import path used to resolve QML modules just for Qt Quick Designer
    QML_DESIGNER_IMPORT_PATH =
    
    # Default rules for deployment.
    qnx: target.path = /tmp/$${TARGET}/bin
    else: unix:!android: target.path = /opt/$${TARGET}/bin
    !isEmpty(target.path): INSTALLS += target
    
    HEADERS += 
        Process.h
    
    //main.cpp
    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include "Process.h"
    int main(int argc, char *argv[])
    {
    #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
       QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    #endif
        qmlRegisterType<Process>("qt.process.app", 1, 0, "Process");
        QGuiApplication app(argc, argv);
        QQmlApplicationEngine engine;
        const QUrl url(QStringLiteral("qrc:/main.qml"));
        QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                         &app, [url](QObject *obj, const QUrl &objUrl) {
            if (!obj && url == objUrl)
                QCoreApplication::exit(-1);
        }, Qt::QueuedConnection);
        engine.load(url);
        return app.exec();
    }
    
    //Process.h
    #ifndef __Process__
    #define __Process__
    #include <QProcess>
    #include <QIODevice>
    #include <QObject>
    class Process : public QObject
    {
        Q_OBJECT
    public:
        enum OpenModeFlag {
            NotOpen = QIODevice::NotOpen,
            ReadOnly = QIODevice::ReadOnly,
            WriteOnly = QIODevice::WriteOnly,
            ReadWrite = QIODevice::ReadWrite,
            Append = QIODevice::Append,
            Truncate = QIODevice::Truncate,
            Text = QIODevice::Text,
            Unbuffered = QIODevice::Unbuffered,
            NewOnly = QIODevice::NewOnly,
            ExistingOnly = QIODevice::ExistingOnly
        };
        Q_DECLARE_FLAGS(OpenMode, OpenModeFlag)
    signals:
        void readyReadStandardError();
        void readyReadStandardOutput();
    public:
        Process(QObject* parent = nullptr);
        virtual ~Process();
        Q_INVOKABLE void start(const QString& program, const QStringList& arguments = QStringList(), OpenMode mode = ReadWrite);
        Q_INVOKABLE QByteArray readAllStandardError();
        Q_INVOKABLE QByteArray readAllStandardOutput();
    protected:
        QProcess* m_Process;
        void newProcess();
        void deleteProcess();
    };
    #endif
    
    //Process.cpp
    #include "Process.h"
    Process::Process(QObject* parent) :
        QObject(parent),
        m_Process(nullptr)
    {
    }
    
    Process::~Process()
    {
        deleteProcess();
    }
    
    void Process::newProcess()
    {
        if (m_Process) return;
        m_Process = new QProcess();
        connect(m_Process, &QProcess::readyReadStandardError, this, &Process::readyReadStandardError);
        connect(m_Process, &QProcess::readyReadStandardOutput, this, &Process::readyReadStandardOutput);
    }
    
    void Process::deleteProcess()
    {
        if (!m_Process) return;
        disconnect(m_Process, &QProcess::readyReadStandardError, this, &Process::readyReadStandardError);
        disconnect(m_Process, &QProcess::readyReadStandardOutput, this, &Process::readyReadStandardOutput);
        delete m_Process;
        m_Process = nullptr;
    }
    
    void Process::start(const QString& program, const QStringList& arguments, OpenMode mode)
    {
        if (!m_Process) newProcess();
        m_Process->start(program, arguments, static_cast<QIODevice::OpenMode>((static_cast<int>(mode))));
    }
    
    QByteArray Process::readAllStandardError()
    {
        return m_Process ? m_Process->readAllStandardError() : QByteArray();
    }
    
    QByteArray Process::readAllStandardOutput()
    {
        return m_Process ? m_Process->readAllStandardOutput() : QByteArray();
    }
    
    //main.qml
    import QtQuick 2.15
    import QtQuick.Controls 2.15
    import QtQuick.Layouts 1.15
    import qt.process.app 1.0
    
    ApplicationWindow {
        width: 640
        height: 480
        visible: true
        title: qsTr("Hello World")
    
        Page {
            anchors.fill: parent
            ListView {
                id: listView
                anchors.fill: parent
                clip: true
                model: ListModel {
                    id: _console
                    function appendMsg(msg, col) {
                        append({msg, col});
                        listView.currentIndex = count - 1;
                    }
                    function log(...params) {
                        console.log(...params);
                        appendMsg(params.join(" "), "black");
                    }
                    function error(...params) {
                        console.error(...params);
                        appendMsg(params.join(" "), "red");
                    }
                }
                ScrollBar.vertical: ScrollBar {
                    width: 20
                    policy: ScrollBar.AlwaysOn
                }
                delegate: Frame {
                    width: ListView.view.width - 20
                    background: Rectangle {
                        color: (index & 1) ? "#eee" : "#ccc"
                    }
                    Text {
                        width: parent.width
                        text: msg
                        color: col
                    }
                }
            }
            footer: Frame {
                Button {
                    text: qsTr("Go!")
                    onClicked: go()
                }
            }
        }
    
        Process {
            id: process
            onReadyReadStandardError: {
                let data = readAllStandardError();
                _console.error(data);
            }
            onReadyReadStandardOutput: {
                let data = readAllStandardOutput();
                _console.log(data);
            }
        }
    
        function go() {
            process.start("/bin/sh", ["-c", "date", "+%F +%X"], Process.ReadOnly);
        }
    }
    

    qtquickcontrols2.conf:

    [Controls]
    Style=Material
    
    [Material]
    Theme=Light
    

    And qml.qrc:

    <RCC>
        <qresource prefix="/">
            <file>main.qml</file>
            <file>qtquickcontrols2.conf</file>
        </qresource>
    </RCC>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search