Exécutez les commandes système à partir de l'application QML

16

Je veux exécuter une commande système depuis mon application. Il est supposé exécuter une commande sur un serveur distant en utilisant SSH. Mais ce n'est pas vraiment le point. Le fait est que je ne sais pas comment exécuter n'importe quel type de commande à partir de l'application. J'ai demandé dans la liste de diffusion et ils m'ont référé pour construire une extension QML en utilisant C ++. Mais je ne connais pas le C ++ et il semble que je doive apprendre tellement que pour exécuter une simple commande.

En Python (comme en PHP), il est facile d'exécuter une commande système. Y a-t-il une autre façon de le faire dans mon application Touch, ou y a-t-il quelqu'un qui pourrait m'aider encore plus? Ou peut-être avoir une meilleure solution à mon problème?

Daniel Holm
la source
1
Pouvez-vous supprimer tout le contenu qui n'a rien à voir avec le cœur de votre question, comme le "serveur Minecraft", comment vous apprenez ce "juste pour le plaisir", etc.? La raison pour laquelle je demande, c'est parce que ces détails sont à côté du problème et assez distrayants, respectueusement.
Akiva

Réponses:

13

Ce n'est pas quelque chose que QML prend en charge, la réponse typique est d'écrire un plugin C ++ pour gérer ce genre de chose.

Cependant, l'équipe du SDK prévoit différentes extensions à fournir aux développeurs d'applications QML, et cela peut être quelque chose qu'ils implémentent dans un plugin générique que vous pouvez utiliser.

mhall119
la source
2
Ce serait très apprécié! J'ai plutôt commencé à chercher un moyen d'appeler un script Python, mais je ne peux trouver qu'un script Python qui exécute QML, et non l'inverse.
Daniel Holm
Ce que j'ai finalement fait, c'est que j'ai apporté quelques modifications à mon webui pour la même fonction que la nouvelle application, et que je récupère les informations dont j'ai besoin en utilisant XML. Génial.
Daniel Holm
1
J'ai essayé le concept QProcess Launcher en 14.04 et cela fonctionne très bien: askubuntu.com/a/446736/20275
int_ua
@ mhall119 Veuillez me corriger si je me trompe, mais vous ne pouvez pas réellement le faire avec QML sur le téléphone à cause d'AppArmor. Cela vous empêchera de le faire.
Akiva
10

Mise à jour: pour 14.04 voir la réponse très simplifiée par int_ua.

Texte original:

Sur http://talk.maemo.org/showthread.php?t=87580, vous trouverez un aperçu de base sur la façon d'ajouter l'extension à QML. J'ai décidé de lui donner une photo en utilisant ubuntu-sdk à la place, ce qui est légèrement différent. Je documenterai ci-dessous.

Pour ce projet, j'ai sélectionné Ubuntu Touch / Simple UI avec C ++ Backend dans QtCreator. Cela crée un projet avec deux parties distinctes, le backend et le touchui frontend écrit en QML. Au backend, nous allons ajouter deux fichiers pour la classe Launcher.

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

Cette classe utilise simplement QProcess pour exécuter un programme, attend qu'il se termine, lit sa sortie standard et la renvoie sous forme de chaîne.

Ensuite, nous devons modifier backend / backend.cpp pour inclure la classe. Cela nécessite deux lignes. Ajoutez une inclusion:

#include "launcher.h"

et dans BackendPlugin :: registerTypes ajoutez une ligne:

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

Il devrait déjà y avoir une ligne pour MyType, qui est l'exemple inclus. Après cela, nous devrions pouvoir construire le backend. Il ne reste plus qu'à l'utiliser dans le fichier main.qml. Pour cela j'ai ajouté une ligne:

Launcher { id: myLauncher }

et au gestionnaire onClick du bouton, définissez:

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

À ce stade, il ne reste plus qu'à le démarrer et à le tester. Voici où j'ai rencontré un problème, car QtCreator ne semble pas tout configurer correctement par défaut. Pendant que je contourne, dans le terminal, accédez à votre répertoire de projet QtCreator et:

mkdir -p Ubuntu/Example

Copiez ensuite le fichier libUbuntuExample.so de ProjectBuildDir / backend vers Ubuntu / Example et le fichier qmldir de ProjectName / backend / qmldir. Ensuite, vous pouvez exécuter:

qmlscene -I . ProjectName/touchui/main.qml

Je suis sûr qu'il existe probablement un moyen simple de tout régler afin que Build / Run fonctionne.

Jason Conti
la source
Cela fonctionne maintenant seulement en 14.04: askubuntu.com/a/446736/20275
int_ua
6

Ubuntu 14.04

Le concept de type QProcess Launcher fonctionne désormais sans problème dans Trusty avec ubuntu-sdk-teamPPA. Créez simplement un QML Extension Library + Tabbed UIprojet ( n'utilisez pas encore de tirets dans le nom du projet ), remplacez le contenu de

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

}

et le changement qmlRegisterTypedans l' backend.cppà

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

Ensuite, nettoyez tous les MyTyperestes des fichiers QML et ajoutez

        Rectangle {

          Launcher {
             id: qprocess
          }

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

où vous voulez et

import projectname 1.0

au début.

Optionnel

J'utilise également ce wrapper:

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

Si vous avez besoin d'un accès root, ajoutez pkexec.

int_ua
la source
1
Je voudrais simplement confirmer que cette solution a parfaitement fonctionné pour moi. Quelles que soient les commandes que vous saisissez, sa sortie est affichée dans le rectangle.
Akiva
2

Vous n'avez vraiment pas besoin d'en savoir beaucoup sur c ++ pour avoir accès aux commandes du terminal. Mettez simplement ce qui suit dans n'importe quel fichier se terminant par .cpp, par exemple runPython.cpp.

#include <stdlib.h>

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

Tout ce que vous avez à découvrir maintenant est de savoir comment obtenir le code c ++ en QML, mais je suis sûr que c'est très bien documenté.

Notez que vous pouvez ajouter n'importe quelle commande linux que vous aimez en suivant la même syntaxe system("linux command");.

J'espère que cela t'aides!

user93692
la source