Führen Sie Systembefehle aus der QML-App aus

16

Ich möchte einen Systembefehl in meiner Anwendung ausführen. Es wird angenommen, dass Sie einen Befehl mit SSH auf einem Remote-Server ausführen. Aber darum geht es nicht wirklich. Der Punkt ist, dass ich nicht weiß, wie man irgendeinen Befehl von der App aus ausführt. Ich habe in der Mailingliste nachgefragt und sie haben mich angewiesen, eine QML-Erweiterung mit C ++ zu erstellen. Aber ich kenne C ++ nicht und es scheint, dass ich so viel lernen muss, nur um einen einfachen Befehl auszuführen.

In Python (wie in PHP) ist es einfach, einen Systembefehl auszuführen. Gibt es eine andere Möglichkeit, dies in meiner Touch-App zu tun, oder gibt es jemanden, der mir noch weiterhelfen könnte? Oder vielleicht eine bessere Lösung für mein Problem?

Daniel Holm
quelle
1
Können Sie alle Inhalte entfernen, die nicht mit dem Kern Ihrer Frage zu tun haben, wie z. B. den "Minecraft-Server". Wie lernen Sie diesen "Nur zum Spaß" usw.? Der Grund, den ich frage, ist, dass diese Details neben dem Problem liegen und respektvoll und ziemlich ablenkend sind.
Akiva

Antworten:

13

Dies wird von QML nicht unterstützt. Die typische Antwort besteht darin, ein C ++ - Plugin zu schreiben, um mit solchen Dingen umzugehen.

Das SDK-Team plant jedoch verschiedene Erweiterungen, die QML-App-Entwicklern zur Verfügung gestellt werden sollen. Diese werden möglicherweise in einem generischen Plug-in implementiert, das Sie verwenden können.

mhall119
quelle
2
Das wäre sehr dankbar! Stattdessen habe ich nach einer Möglichkeit gesucht, ein Python-Skript aufzurufen, aber ich kann nur ein Python-Skript finden, das QML ausführt, und nicht umgekehrt.
Daniel Holm
Was ich schließlich getan habe, war, dass ich einige Änderungen an meinem Webui für die gleiche Funktion wie die neue App vorgenommen und die benötigten Informationen mithilfe von XML abgerufen habe. Ziemlich ordentlich.
Daniel Holm
1
Ich habe das QProcess Launcher-Konzept in 14.04 ausprobiert und es funktioniert einwandfrei
int_ua
@ mhall119 Bitte korrigiere mich, wenn ich falsch liege, aber du kannst dies mit QML auf dem Telefon wegen AppArmor nicht tun. Es wird Sie daran hindern, dies zu tun.
Akiva
10

Update: Für 14.04 siehe die stark vereinfachte Antwort von int_ua.

Original Text:

Unter http://talk.maemo.org/showthread.php?t=87580 finden Sie eine grundlegende Übersicht über das Hinzufügen der Erweiterung zu QML. Ich habe beschlossen, es mit dem Ubuntu-SDK zu versuchen, was etwas anders ist. Ich werde unten dokumentieren.

Für dieses Projekt habe ich Ubuntu Touch / Simple UI mit C ++ Backend in QtCreator ausgewählt. Dadurch wird ein Projekt mit zwei separaten Teilen erstellt, dem Backend und dem Touchui-Frontend, die in QML geschrieben sind. Im Backend werden wir zwei Dateien für die Launcher-Klasse hinzufügen.

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;
}

Diese Klasse verwendet einfach QProcess, um ein Programm auszuführen, wartet, bis es beendet ist, liest die Standardausgabe und gibt sie als Zeichenfolge zurück.

Als nächstes müssen wir backend / backend.cpp ändern, um die Klasse einzuschließen. Dies erfordert zwei Zeilen. Füge ein Include hinzu:

#include "launcher.h"

und in BackendPlugin :: registerTypes füge eine Zeile hinzu:

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

Für MyType sollte bereits eine Zeile vorhanden sein. Dies ist das mitgelieferte Beispiel. Danach sollten wir das Backend erstellen können. Sie müssen es nur noch in der Datei main.qml verwenden. Dazu habe ich eine Zeile hinzugefügt:

Launcher { id: myLauncher }

und setzen Sie im onClick-Handler des Buttons:

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

An diesem Punkt muss es nur noch gestartet und getestet werden. Hier ist ein Problem aufgetreten, da QtCreator anscheinend nicht alle Einstellungen standardmäßig korrekt vornimmt. Navigieren Sie zur Umgehung des Problems im Terminal zu Ihrem QtCreator-Projektverzeichnis und:

mkdir -p Ubuntu/Example

Kopieren Sie dann die Datei libUbuntuExample.so von ProjectBuildDir / backend nach Ubuntu / Example und die Datei qmldir von ProjectName / backend / qmldir. Dann kannst du laufen:

qmlscene -I . ProjectName/touchui/main.qml

Ich bin mir sicher, dass es wahrscheinlich einen einfachen Weg gibt, dies alles zu manipulieren, damit Build / Run einfach funktioniert.

Jason Conti
quelle
Es funktioniert jetzt nur noch in 14.04: askubuntu.com/a/446736/20275
int_ua
6

Ubuntu 14.04

Das Konzept des QProcess Launcher-Typs funktioniert jetzt problemlos in Trusty mit ubuntu-sdk-teamPPA. Erstellen Sie einfach ein QML Extension Library + Tabbed UIProjekt (verwenden Sie noch keine Bindestriche im Projektnamen ) und ersetzen Sie den Inhalt von

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() {

}

und ändere qmlRegisterTypedas backend.cppin

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

Bereinigen Sie als Nächstes einfach alle MyTypeReste der QML-Dateien und fügen Sie sie hinzu

        Rectangle {

          Launcher {
             id: qprocess
          }

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

wo immer du willst und

import projectname 1.0

am Anfang.

Optional

Ich benutze auch diesen Wrapper:

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

Wenn Sie Root-Zugriff benötigen, fügen Sie hinzu pkexec.

int_ua
quelle
1
Ich möchte nur bestätigen, dass diese Lösung für mich hervorragend funktioniert hat. Unabhängig davon, welche Befehle Sie eingeben, wird die Ausgabe im Rechteck angezeigt.
Akiva
2

Sie müssen wirklich nicht viel über C ++ wissen, um auf Terminalbefehle zugreifen zu können. Fügen Sie einfach Folgendes in jede Datei ein, die mit .cpp endet, zum Beispiel runPython.cpp.

#include <stdlib.h>

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

Alles, was Sie jetzt herausfinden müssen, ist, wie Sie den C ++ - Code in QML zum Laufen bringen, aber ich bin sicher, dass dies sehr gut dokumentiert ist.

Beachten Sie, dass Sie jeden beliebigen Linux-Befehl hinzufügen können, indem Sie der gleichen Syntax folgen system("linux command");.

Hoffe das hilft!

user93692
quelle