Unsolved run a sh shell while clicking button in QML with QT5.15.0
-
What do you mean by "run shell"? What are you trying to achieve?
If you want to run an external process, use QProcess. If you want to show a terminal inside your app, it will be harder. You can probably use KDE's frameworks to get a Konsole inside your app, like Dolphin, Yakuake and others do.
-
Hi, I just want to run an external process which is just a binary file. I write a shell script to run that binary file and want to run this shell while clicking the button in QML.
Do you have any demo codes? -
@lxy12345
Hi
did you try
http://71.254.128.33/qml/process.html -
@mrjj Hi, I followed your post but an error occured.
I copied the process.h file.
Here below is my main.cpp:
#include <QGuiApplication>
#include <QQuickView>
#include <QQmlEngine>
#include <QtQml>
#include "process.h"int main(int argc, char* argv[])
{
QGuiApplication app(argc,argv);
QQuickView view;
view.setResizeMode(QQuickView::SizeRootObjectToView);
// Qt.quit() called in embedded .qml by default only emits
// quit() signal, so do this (optionally use Qt.exit()).
QObject::connect(view.engine(), &QQmlEngine::quit,
qApp, &QGuiApplication::quit);
qmlRegisterType<Process>("Process",1,0,"Process");view.setSource(QUrl("qrc:///main.qml")); //view.resize(1000, 480); view.show(); return app.exec();
}
Here below is my qml file:
Item {
id: usbcam2
signal clicked
x:10
y:450
width : 140
height: 70BorderImage { id: buttonImage2 source: "images/toolbutton.sci" width: usbcam2.width height: usbcam2.height } MouseArea { id: mouseRegion2 anchors.fill: buttonImage2 onClicked: process.start("/bin/cat", [ "/proc/uptime" ]); } Text { id: btnText2 anchors.fill: buttonImage2 anchors.margins: 5 text: "USBcam2" horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight color: "white" font.bold: true style: Text.Raised styleColor: "black" font.pixelSize: 14 } }
}
When I click the button, the error showed:
qrc:/main.qml:99: ReferenceError: process is not defined
what's that meanning? -
@lxy12345 said in run a sh shell while clicking button in QML with QT5.15.0:
Here below is my qml file:
you did not create a Process item
Process { id: process }
-
@LeLev I don't really understand this code:
onReadyRead: text.text = readAll();
Is onReadyRead a signal? or something like onCliked in button? -
@lxy12345 said in run a sh shell while clicking button in QML with QT5.15.0:
Is onReadyRead a signal?
yes
-
@jsulm Hi, jsulm. I have tried your post but I misunderstand somewhere maybe.
I don't understand the singal "onReadyRead", I googled which said that this signal is for TCP/IP??? I am not very sure about that.
what and where should I modify in your post? -
@lxy12345 said in run a sh shell while clicking button in QML with QT5.15.0:
onReadyRead
Hi
Its also for other things.
" QProcess emits readyRead() when data is available on the current read channel. It also emits readyReadStandardOutput() when new standard output data is available"https://doc.qt.io/qt-5/qprocess.html
in the Communicating via Channels section -
@jsulm when I tried the code ,
Text {
id: text
}Process{ id: process onReadyRead: text.text = readAll(); } Timer { interval: 10 repeat: true triggeredOnStart: true running: true onTriggered: process.start("/bin/cat", [ "/proc/uptime" ]); }
it outputs:
QProcess::start: Process is already running
QProcess::start: Process is already running
QProcess::start: Process is already running
QProcess::start: Process is already running
QProcess::start: Process is already running
QProcess::start: Process is already running
QProcess::start: Process is already running
QProcess::start: Process is already runningI think that the shell here is just "cat /proc/uptime", it should output some numbers.
Maybe I should read and understand Qprocess class first? -
@lxy12345
I don't know anything about QML, butQProcess::start: Process is already running
means that you have a
QProcess
instance where you have set of astart()
but it has not yet completed and you have not waited for it, and now you're trying to set off a newstart()
. You either need to wait for completion of the process instance, or you need to use a new instance ofQProcess
each time. As I say, i don't know QML how to do that, but that's the cause/reason. -
Hi
Since you set the timer to repeat, it will start a new QProcess each time and
10 ms might be too short. try raising it so the other Qprocess gets change to finished.Timer {
interval: 10
repeat: true -
@mrjj
Really it ought have a handler for "process finished" signal, to be robust. I don't know how you do that from QML.OP might have a go at the naughty:
onTriggered: process.start("/bin/cat", [ "/proc/uptime" ]); process.waitForFinished();
with all the caveats. I don't know if that would work simpler.
-
@JonB
Yes i agree as guessing on execution time is bound to fail in many other cases. -
@mrjj finally, I found the reason. I should add console.log() to show output . The post is correct, thanks guys
-
@lxy12345 said in run a sh shell while clicking button in QML with QT5.15.0:
The post is correct
What post is correct?
-
@JonB http://71.254.128.33/qml/process.html This post.
-
@lxy12345
Ah, I see. Yes, that looks reasonable. However, it has no code for waiting for theQProcess::finished
signal. I admitted earlier I do not know how QML works with regard to instances. But if it does not create newQProcess
instances, and if you re-use the one instance before thecat
OS command has completed, you will get theQProcess::start: Process is already running
error you showed earlier. Since the/bin/cat /proc/uptime
completes "quickly" you may get away with it for a while.You may well be using this as just an example to play with
QProcess
, I don't know. But be aware that if you are really trying to do/bin/cat /proc/uptime
, that is a waste of time! All that does is an OS command to read the contents of the file. You would be better doing this by just opening the file/proc/uptime
and reading its content from QML, without anyQProcess
OS command at all. -
@JonB thanks for replying me. The "cat /proc/uptime" cmd is just an example. I change the cmd in my project, I use this code to open a shell which controls some peripherals.
-
Basically close/kill / terminate the process before running a new process
here an example I extracted from one of my projects as I keep "bash" process alive till closing the app itself.
so try to find where you wan to stop the process and close it.cmd.h
#pragma once #include <QProcess> #include <QVariant> class Process : public QProcess { Q_OBJECT public: explicit Process( QObject* parent = Q_NULLPTR ) : QProcess( parent ) { } // If want to use Start with arguments Q_INVOKABLE void start( const QString& program, const QVariantList& arguments ) { QStringList args; // convert QVariantList from QML to QStringList for QProcess for ( const auto& temp : arguments ) { args << temp.toString(); } QProcess::setProcessChannelMode( QProcess::MergedChannels ); QProcess::start( program, args ); } // If wan to start without arguments for Qt > 5.14 Q_INVOKABLE void start( const QString& program ) { QProcess::setProcessChannelMode( QProcess::MergedChannels ); QProcess::setProgram( program ); QProcess::start(); QProcess::open( QProcess::ReadWrite ); } Q_INVOKABLE QByteArray readAll() { return QProcess::readAll(); } Q_INVOKABLE QByteArray readLine() { return QProcess::readLine(); } // if you want to write to an active process, not fully tested! Q_INVOKABLE qint64 write( const QString& data ) { return QProcess::write( qPrintable( data ) ); } private: Q_DISABLE_COPY( Process ) };
In
main.h
qmlRegisterType<Process>( "Process", 1, 0, "Process" );
In
main.qml
import QtQuick 2.15 import QtQuick.Controls 2.15 import QtQuick.Layouts 1.15 import Qt.labs.platform 1.1 import Process 1.0 ApplicationWindow { visible: true width: 640 height: 480 title: qsTr("Hello World") Component.onCompleted: { py.start("bash") } // use py.close() or py.kill(0 or py.terminate() to kill the process Component.onDestruction: py.close() Process { id: py property string output: "" onStarted: print("Started") onFinished: print("Closed") onErrorOccurred: console.log("Error Ocuured: ", error) onReadyReadStandardOutput: { output = py.readAll() term.text += output } } Page { anchors.fill: parent ScrollView { id: view anchors.fill: parent TextArea { id: term textFormat: TextArea.RichText } } footer: RowLayout { Layout.fillWidth: true TextField { id: input Layout.fillWidth: true } Button { text: "Send!" property string command: input.text.trim() + "\n" onClicked: { py.write(command) term.text += ("<br /><b>" + command + " : </b>") } } } } }
I have run
cat /proc/uptime
as one program command.