19

I want to run a system command from inside my application. It's suppose to run a command on a remote server using SSH. But that's not really the point. The point is that I don't know how to run any kind of command from the app. I asked in the mail list and they referred me to build a QML extension using C++. But I don't know C++ and it seems that I have to learn so much only to run a simple command.

In Python (as in PHP) it's easy to run a system command. Is there any other way of doing it in my Touch app, or is there someone that could help me even more? Or perhaps have a better solution to my problem?

1
  • 1
    Can you remove all the content not having to do with the core of your question, such as the "Minecraft Server", How you are learning this "Just for fun", etc? The reason I ask is because these details are beside the issue and pretty distracting, respectfully.
    – Anon
    Apr 19, 2014 at 10:50

5 Answers 5

13

This isn't something that QML supports, the typical answer is to write a C++ plugin to handle that kind of thing.

However, the SDK team is planning out various extensions to provide to QML app developers, and this may be something that they implement in a generic plugin that you can use.

4
  • 2
    That would be much appreciated! I've instead started to look for a way to call a Python script, but I can only find a Python script that runs QML, and not the other way around. Apr 30, 2013 at 15:01
  • What I finally did was that I made some changes to my webui for the same function as the new app, and pull the info I need from that using XML. Pretty neat. May 2, 2013 at 19:59
  • 2
    I've tried the QProcess Launcher concept in 14.04 and it works fine: askubuntu.com/a/446736/20275
    – int_ua
    Apr 12, 2014 at 4:38
  • @mhall119 Please correct me if I am wrong, but you can not actually do this with QML on the phone because of AppArmor. It will prevent you from doing this.
    – Anon
    Jan 8, 2015 at 19:34
11
+50

Update: For 14.04 see the much simplified answer by int_ua.

Original Text:

At http://talk.maemo.org/showthread.php?t=87580 there is a basic overview of how to add the extension to QML. I decided to give it a shot using the ubuntu-sdk instead, which is slightly different. I'll document below.

For this project I selected Ubuntu Touch/Simple UI with C++ Backend in QtCreator. This creates a project with two separate parts, the backend and the touchui frontend written in QML. To the backend we are going to add two files for the Launcher class.

launcher.h:

#ifndef LAUNCHER_H
#define LAUNCHER_H

#include <QObject>
#include <QProcess>

class Launcher : public QObject
{
    Q_OBJECT
public:
    explicit Launcher(QObject *parent = 0);
    Q_INVOKABLE QString launch(const QString &program);

private:
    QProcess *m_process;
};

#endif // LAUNCHER_H

launcher.cpp:

#include "launcher.h"

Launcher::Launcher(QObject *parent) :
    QObject(parent),
    m_process(new QProcess(this))
{
}

QString Launcher::launch(const QString &program)
{
    m_process->start(program);
    m_process->waitForFinished(-1);
    QByteArray bytes = m_process->readAllStandardOutput();
    QString output = QString::fromLocal8Bit(bytes);
    return output;
}

This class simply uses QProcess to execute a program, waits for it to finish, reads its stdout, and returns it as a string.

Next we need to modify backend/backend.cpp to include the class. This requires two lines. Append an include:

#include "launcher.h"

and in BackendPlugin::registerTypes add a line:

qmlRegisterType<Launcher>(uri, 1, 0, "Launcher");

There should already be a line for MyType, which is the included example. After this we should be able to build the backend. The only thing that remains is to use it in the main.qml file. For this I added a line:

Launcher { id: myLauncher }

and to the Button's onClick handler, set:

myType.helloWorld = myLauncher.launch("date");

At this point all that remains is to start it up and test it out. Here is where I ran into a problem, since QtCreator doesn't seem to set everything up properly by default. As I workaround, in the terminal navigate to your QtCreator project directory and:

mkdir -p Ubuntu/Example

Then copy the libUbuntuExample.so file from ProjectBuildDir/backend to Ubuntu/Example, and the qmldir file from ProjectName/backend/qmldir. Then you can run:

qmlscene -I . ProjectName/touchui/main.qml

I'm sure there is probably a simple way to rig this all up so Build/Run just works.

1
7

Ubuntu 14.04

The concept of QProcess Launcher type is now working without problems in Trusty with ubuntu-sdk-team PPA. Just create QML Extension Library + Tabbed UI project (don't use hyphens in project name yet), replace contents of

mytype.h

#ifndef LAUNCHER_H
#define LAUNCHER_H

#include <QObject>
#include <QProcess>

class Launcher : public QObject
{
    Q_OBJECT

public:
    explicit Launcher(QObject *parent = 0);
    ~Launcher();
    Q_INVOKABLE QString launch(const QString &program);

protected:
    QProcess *m_process;
};

#endif // LAUNCHER_H

mytype.cpp

#include "mytype.h"

Launcher::Launcher(QObject *parent) :
    QObject(parent),
    m_process(new QProcess(this))
{

}

QString Launcher::launch(const QString &program)
{
    m_process->start(program);
    m_process->waitForFinished(-1);
    QByteArray bytes = m_process->readAllStandardOutput();
    QString output = QString::fromLocal8Bit(bytes);
    return output;
}

Launcher::~Launcher() {

}

and change qmlRegisterType in the backend.cpp to

qmlRegisterType<Launcher>(uri, 1, 0, "Launcher");

Next, just clean all MyType remains from QML files and add

        Rectangle {

          Launcher {
             id: qprocess
          }

          Text {
            anchors.centerIn: parent
            text: qprocess.launch("which bash")
          }
        }

wherever you like and

import projectname 1.0

in the beginning.

Optional

I also use this wrapper:

function exec(command) {
    return qprocess.launch("sh -c \"" + command + " < /dev/null \"")
}

If you need root access, add pkexec.

1
  • 1
    I would just like to confirm that this solution worked excellently for me. Whatever commands you input, its output is displayed in the rectangle.
    – Anon
    Apr 19, 2014 at 14:53
2

You really don't need to know a lot about c++ to get access to terminal commands. Just put the following in any file ending with .cpp, for instance runPython.cpp.

#include <stdlib.h>

int main ()
{
    system("cd /home/user/path/to/script");
    system("python3 myScript.py");
    return 0;
}

All you have to find out now is how to get the c++ code running in QML but I'm sure that's very well documented.

Note that you can add any linux command you like by following the same syntax system("linux command");.

Hope this helps!

1

You shall use PlasmaCore.DataSource with the engine "executable", as in this example.

Mind that the call is asynchronous. Hence the command sends a signal when it finishes, and a different part of the code picks the signal and continues with the next step you want to perform.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .