Execute comandos do sistema a partir do QML App

16

Eu quero executar um comando do sistema dentro do meu aplicativo. É suposto executar um comando em um servidor remoto usando SSH. Mas isso não é realmente o ponto. O ponto é que eu não sei como executar qualquer tipo de comando do aplicativo. Eu perguntei na lista de e-mail e eles me indicaram para construir uma extensão QML usando C ++. Mas eu não sei o C ++ e parece que tenho que aprender muito apenas para executar um comando simples.

No Python (como no PHP) é fácil executar um comando do sistema. Existe alguma outra maneira de fazer isso no meu aplicativo Touch ou há alguém que possa me ajudar ainda mais? Ou talvez tenha uma solução melhor para o meu problema?

    
por Daniel Holm 30.04.2013 / 15:18

4 respostas

13

Isso não é algo que o QML suporta, a resposta típica é escrever um plugin em C ++ para lidar com esse tipo de coisa.

No entanto, a equipe do SDK está planejando várias extensões para fornecer aos desenvolvedores de aplicativos QML, e isso pode ser algo que eles implementam em um plug-in genérico que você pode usar.

    
por mhall119 30.04.2013 / 16:35
10

Atualização: Para 14.04, veja a resposta muito simplificada por int_ua.

Texto original:

No link , há uma visão geral básica de como adicionar a extensão ao QML. Eu decidi dar uma chance usando o ubuntu-sdk, o que é um pouco diferente. Vou documentar abaixo.

Para este projeto eu selecionei Ubuntu Touch / UI Simples com Backend C ++ no QtCreator. Isso cria um projeto com duas partes separadas, o backend e o touchui frontend escritos em QML. Para o backend, vamos adicionar dois arquivos para a 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;
}

Esta classe simplesmente usa QProcess para executar um programa, aguarda que ele termine, leia seu stdout e o retorne como uma string.

Em seguida, precisamos modificar o backend / backend.cpp para incluir a classe. Isso requer duas linhas. Anexar uma inclusão:

#include "launcher.h"

e em BackendPlugin :: registerTypes adicione uma linha:

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

Já deve haver uma linha para MyType, que é o exemplo incluído. Depois disso, poderemos construir o backend. A única coisa que resta é usá-lo no arquivo main.qml. Para isso eu adicionei uma linha:

Launcher { id: myLauncher }

e ao manipulador onClick do Button, defina:

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

Neste ponto, tudo o que resta é iniciá-lo e testá-lo. Aqui é onde eu me deparei com um problema, já que o QtCreator não parece configurar tudo corretamente por padrão. Como solução, no terminal, navegue até o diretório do projeto QtCreator e:

mkdir -p Ubuntu/Example

Em seguida, copie o arquivo libUbuntuExample.so de ProjectBuildDir / backend para Ubuntu / Example e o arquivo qmldir de ProjectName / backend / qmldir. Então você pode correr:

qmlscene -I . ProjectName/touchui/main.qml

Tenho certeza de que provavelmente existe uma maneira simples de montar tudo isso, para que o Build / Run funcione.

    
por Jason Conti 29.06.2013 / 01:05
6

Ubuntu 14.04

O conceito do tipo QProcess Launcher agora está funcionando sem problemas em Trusty com ubuntu-sdk-team PPA. Apenas crie QML Extension Library + Tabbed UI project ( não use hifens no nome do projeto ainda ), substitua o conteúdo 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() {

}

e altere qmlRegisterType no backend.cpp para

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

Em seguida, limpe todos os MyType restantes dos arquivos QML e adicione

        Rectangle {

          Launcher {
             id: qprocess
          }

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

onde você quiser e

import projectname 1.0

no começo.

Opcional

Eu também uso este wrapper:

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

Se você precisar de acesso root, adicione pkexec .

    
por int_ua 12.04.2014 / 06:30
2

Você realmente não precisa saber muito sobre o c ++ para ter acesso aos comandos do terminal. Basta colocar o seguinte em qualquer arquivo que termine com .cpp, por exemplo runPython.cpp.

#include <stdlib.h>

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

Tudo que você precisa descobrir agora é como obter o código c ++ em execução no QML, mas tenho certeza de que está muito bem documentado.

Note que você pode adicionar qualquer comando linux de que goste, seguindo a mesma sintaxe system("linux command"); .

Espero que isso ajude!

    
por user93692 16.08.2013 / 00:53