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.
CodePudding user response:
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.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>
CodePudding user response:
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.