Ejecute comandos del sistema desde la aplicación QML

16

Quiero ejecutar un comando del sistema desde mi aplicación. Se supone que debe ejecutar un comando en un servidor remoto utilizando SSH. Pero ese no es realmente el punto. El punto es que no sé cómo ejecutar ningún tipo de comando desde la aplicación. Pregunté en la lista de correo y me recomendaron construir una extensión QML usando C ++. Pero no conozco C ++ y parece que tengo que aprender mucho solo para ejecutar un comando simple.

En Python (como en PHP) es fácil ejecutar un comando del sistema. ¿Hay alguna otra forma de hacerlo en mi aplicación Touch, o hay alguien que pueda ayudarme aún más? ¿O tal vez tiene una mejor solución a mi problema?

Daniel Holm
fuente
1
¿Puedes eliminar todo el contenido que no tenga que ver con el núcleo de tu pregunta, como el "Servidor de Minecraft", Cómo estás aprendiendo esto "Solo por diversión", etc. La razón por la que pregunto es porque estos detalles están al lado del problema y son bastante molestos, respetuosamente.
Akiva

Respuestas:

13

Esto no es algo que QML admita, la respuesta típica es escribir un complemento C ++ para manejar ese tipo de cosas.

Sin embargo, el equipo del SDK está planeando varias extensiones para proporcionar a los desarrolladores de aplicaciones QML, y esto puede ser algo que implementen en un complemento genérico que puede usar.

mhall119
fuente
2
Eso sería muy apreciado! En cambio, he comenzado a buscar una forma de llamar a un script de Python, pero solo puedo encontrar un script de Python que ejecute QML, y no al revés.
Daniel Holm
Lo que finalmente hice fue hacer algunos cambios en mi webui para la misma función que la nueva aplicación, y extraer la información que necesito de eso usando XML. Con buena pinta.
Daniel Holm
1
Probé el concepto QProcess Launcher en 14.04 y funciona bien: askubuntu.com/a/446736/20275
int_ua
@ mhall119 Corríjame si estoy equivocado, pero en realidad no puede hacer esto con QML en el teléfono debido a AppArmor. Te impedirá hacer esto.
Akiva
10

Actualización: para 14.04 ver la respuesta simplificada de int_ua.

Texto original:

En http://talk.maemo.org/showthread.php?t=87580 hay una descripción básica de cómo agregar la extensión a QML. Decidí intentarlo usando ubuntu-sdk, que es ligeramente diferente. Lo documentaré a continuación.

Para este proyecto, seleccioné Ubuntu Touch / Simple UI con C ++ Backend en QtCreator. Esto crea un proyecto con dos partes separadas, el backend y la interfaz táctil escrita en QML. Al backend vamos a agregar dos archivos para la clase 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;
}

Esta clase simplemente usa QProcess para ejecutar un programa, espera a que termine, lee su stdout y lo devuelve como una cadena.

A continuación, debemos modificar backend / backend.cpp para incluir la clase. Esto requiere dos líneas. Añadir un incluir:

#include "launcher.h"

y en BackendPlugin :: registerTypes agregue una línea:

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

Ya debería haber una línea para MyType, que es el ejemplo incluido. Después de esto, deberíamos poder construir el backend. Lo único que queda es usarlo en el archivo main.qml. Para esto agregué una línea:

Launcher { id: myLauncher }

y para el controlador onClick del botón, establezca:

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

En este punto, todo lo que queda es iniciarlo y probarlo. Aquí es donde me encontré con un problema, ya que QtCreator no parece configurar todo correctamente de forma predeterminada. Mientras soluciono, en la terminal navegue a su directorio de proyecto QtCreator y:

mkdir -p Ubuntu/Example

Luego copie el archivo libUbuntuExample.so de ProjectBuildDir / backend a Ubuntu / Example, y el archivo qmldir de ProjectName / backend / qmldir. Entonces puedes ejecutar:

qmlscene -I . ProjectName/touchui/main.qml

Estoy seguro de que probablemente haya una forma simple de arreglar todo esto, así que Build / Run simplemente funciona.

Jason Conti
fuente
Ahora solo funciona en 14.04: askubuntu.com/a/446736/20275
int_ua
6

Ubuntu 14.04

El concepto de tipo QProcess Launcher ahora funciona sin problemas en Trusty con ubuntu-sdk-teamPPA. Simplemente cree un QML Extension Library + Tabbed UIproyecto ( no use guiones en el nombre del proyecto todavía ), reemplace el contenido 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() {

}

y cambiar qmlRegisterTypeen el backend.cppa

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

A continuación, simplemente limpie todos los MyTyperestos de los archivos QML y agregue

        Rectangle {

          Launcher {
             id: qprocess
          }

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

donde quieras y

import projectname 1.0

al principio.

Opcional

También uso este contenedor:

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

Si necesita acceso de root, agregue pkexec.

int_ua
fuente
1
Solo me gustaría confirmar que esta solución funcionó excelentemente para mí. Independientemente de los comandos que ingrese, su salida se mostrará en el rectángulo.
Akiva
2

Realmente no necesita saber mucho sobre c ++ para acceder a los comandos de la terminal. Simplemente coloque lo siguiente en cualquier archivo que termine con .cpp, por ejemplo runPython.cpp.

#include <stdlib.h>

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

Todo lo que tiene que descubrir ahora es cómo ejecutar el código c ++ en QML, pero estoy seguro de que está muy bien documentado.

Tenga en cuenta que puede agregar cualquier comando de Linux que desee siguiendo la misma sintaxis system("linux command");.

¡Espero que esto ayude!

usuario93692
fuente