crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

 
Ответить в данную темуНачать новую тему
> связь между терминалом и gui программой
ht1515
  опции профиля:
сообщение 31.1.2014, 18:00
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 29
Регистрация: 14.4.2012
Пользователь №: 3324

Спасибо сказали: 0 раз(а)




Репутация:   0  


Всем привет!
Есть консольная программа - терминал. Там вводятся команды, выполняются и результат сразу же печатается в программе( н-р командная строка в винде ).
Я хочу ее связать с gui программой написанной на куте. Никакой сессии, общей памяти консольная программа не дает. Она подразумевает наличие оператора ПК, который тыкать будет команды.
Можно ли каким-нибудь хитрым способом передавать консольной проге команды, чтобы она их выполняла и потом получать ответ?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Sokoloff
  опции профиля:
сообщение 31.1.2014, 19:40
Сообщение #2


Участник
**

Группа: Участник
Сообщений: 237
Регистрация: 1.4.2009
Из: Москва
Пользователь №: 654

Спасибо сказали: 50 раз(а)




Репутация:   11  


Цитата(ht1515 @ 31.1.2014, 19:00) *
Всем привет!
Есть консольная программа - терминал. Там вводятся команды, выполняются и результат сразу же печатается в программе( н-р командная строка в винде ).
Я хочу ее связать с gui программой написанной на куте. Никакой сессии, общей памяти консольная программа не дает. Она подразумевает наличие оператора ПК, который тыкать будет команды.
Можно ли каким-нибудь хитрым способом передавать консольной проге команды, чтобы она их выполняла и потом получать ответ?


Никакого хитрого способа не надо, используй QProcess. Вот реальный пример из моей программы https://github.com/flacon/flacon/blob/maste...litter.cpp#L127 Смотри метод Splitter::doRun()
У меня, правда, немного другая ситуация, я запускаю программу, передаю в нее данные, закрываю STDIN, а потом читаю из STDOUT-а, но очень близко к твоему случаю, тебе не надо дергать closeWriteChannel.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ht1515
  опции профиля:
сообщение 31.1.2014, 20:46
Сообщение #3


Студент
*

Группа: Участник
Сообщений: 29
Регистрация: 14.4.2012
Пользователь №: 3324

Спасибо сказали: 0 раз(а)




Репутация:   0  



ммм... спасибо. Посмотрю.

Я прокомментирую ,вы поправьте если что.

Цитата
QStringList args;
args << "split";
args << "-w";
args << "-O" << "always";
args << "-n" << "%04d";
args << "-t" << mFilePrefix +"%n";
args << "-d" << mWorkDir;
args << disk()->audioFileName();
//qDebug() << args;


формирование входных параметров консольной программы. Необходимы при запуске программы.


Цитата
QString shntool = settings->value(Settings::Prog_Shntool).toString();

Видимо путь до программы.

Цитата
mProcess = new QProcess();
mProcess->setReadChannel(QProcess::StandardError);

создание объекта процесса и установка ??? канала на чтение ошибок?

Цитата
mProcess->start(shntool, args);
mProcess->waitForStarted();


Запуск процесса( консольной программы) и ожидание ее готовности к работе.

Цитата
sendCueData();

Отправка каких-то данных. Пока не углубляюсь куда и каких данных.
В этой функции mProcess->write(" INDEX 01 00:00:00\n"); --- Видимо что-то пишется в консоль программы(cin, stdin)

Цитата
mProcess->closeWriteChannel();

закрыли процесс записи в консольку. Это имитация нажатия кнопки enter?

Цитата
parseOut();

Производим чтение результата выполнения команды. По сути чтение с консоли и парсинг.

Цитата
mProcess->waitForFinished(-1);

блокировка потока пока процесс консольной программы не будет завершет.

Цитата
QProcess *proc = mProcess;
mProcess = 0;
delete proc;

garbage collector

Цитата
if (OutFormat::currentFormat()->createCue())
{
CueCreator cue(disk());
cue.setHasPregapFile(mPreGapExists);
if (!cue.write())
error(disk()->track(0), cue.errorString());
}

Какая-то работа с файлом.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Sokoloff
  опции профиля:
сообщение 1.2.2014, 0:11
Сообщение #4


Участник
**

Группа: Участник
Сообщений: 237
Регистрация: 1.4.2009
Из: Москва
Пользователь №: 654

Спасибо сказали: 50 раз(а)




Репутация:   11  


Все что я не комментирую правильно.

Цитата(ht1515 @ 31.1.2014, 21:46) *
Цитата
mProcess = new QProcess();
mProcess->setReadChannel(QProcess::StandardError);

создание объекта процесса и установка ??? канала на чтение ошибок?

У консольной программы есть 3 потока:
STDIN - входные данные, обычно он связан с клавиатурой, но может быть и чем то другим. Например "dir | sort" sort получает на вход выхлоп ls.
STDOUT - выходной, сюда печатаются обычные выходные данные.
STDERR - выходной, сюда выводятся сообщения об ошибках.
Деление между последними условное, так принято. И, если STDOUT все используют по назначению, то в STDERR выводят не только ошибки, а все что не должно путаться с STDOUT-ом. В моем случае на STDERR выводятся проценты выполнения работы. Именно они меня и интересуют, поэтому я говорю QProcess-у что его readXXX функции будут читать STDERR.

Цитата(ht1515 @ 31.1.2014, 21:46) *
Цитата
mProcess->closeWriteChannel();

закрыли процесс записи в консольку. Это имитация нажатия кнопки enter?

Нет это имитация окончания входного файла. Например если запустить программу "sort < file.txt", то sort будет читать данные из файла file.txt до тех пор пока он не кончится. А после уже отсортирует и выведет их, так вот closeWriteChannel это имитация окончания файла. Или в случае "dir | sort" окончание работы первой программы. Вот это тебе делать и не надо, не закрывай канал. А enter передается обычным переводом строки("\n").

Да, еще. Консольная программа может получать команды разными методами. Стандартный подход через STDIN, и тогда мой подход сработает. Но программа может сама обрабатывать нажатия клавиатуры, и тогда придется извращаться.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
ht1515
  опции профиля:
сообщение 1.2.2014, 15:48
Сообщение #5


Студент
*

Группа: Участник
Сообщений: 29
Регистрация: 14.4.2012
Пользователь №: 3324

Спасибо сказали: 0 раз(а)




Репутация:   0  


Вчера вечером почитал
http://doc.crossplatform.ru/qt/4.7.x/qproc...waitForFinished

Нашел такой пример, gzip заменил на gdb.
Цитата
QProcess gdb;
gdb.start("gdb", QStringList() << "-c");
if (!gdb.waitForStarted())
return false;

QByteArray result = gdb.readAll(); // Это чтобы вычерпать "шапку", которую печатает gdb при запуске

gdb.write("print");
gdb.closeWriteChannel();

if (!gdb.waitForFinished())
return false;

QByteArray result = gdb.readAll(); // должен прочитать результата команды в gdb


Чуть-чуть изменил код.
Но все равно result выдает все. И шапку и результат выполнения команды и даже (gdb)>
Я вроде понял о чем вы, но не могу собрать пока велосипед, чтобы он поехал как надо.
Что не так сделал я? вроде логично рассуждаю)




небольшая правка
Цитата
gdb.start("gdb");

а не
Цитата
gdb.start("gdb", QStringList() << "-c");

просто в редакторе форума код правил
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Sokoloff
  опции профиля:
сообщение 1.2.2014, 20:54
Сообщение #6


Участник
**

Группа: Участник
Сообщений: 237
Регистрация: 1.4.2009
Из: Москва
Пользователь №: 654

Спасибо сказали: 50 раз(а)




Репутация:   11  


Цитата(ht1515 @ 1.2.2014, 15:48) *
Но все равно result выдает все. И шапку и результат выполнения команды

А никто не обещал, что waitForStarted ждет пока программа будет готова принимать данные от пользователя, да еще и проскипает вводное сообщение. Для этого нужен искин. waitForStarted ждет пока ОС прочитает экзешник, выделит всякие PID-ы и.т.п, т.е. чисто на низком уровне. А дальше сам читаешь и парсишь.

Цитата(ht1515 @ 1.2.2014, 15:48) *
и даже (gdb)>

А чем "(gdb)>" отличается от другого текста? Обычная строка, только без перевода каретки.

Я накидал простой пример класса работы с gdb

#ifndef GDB_H
#define GDB_H

#include <QObject>
class QProcess;

class Gdb : public QObject
{
    Q_OBJECT
public:
    explicit Gdb(QObject *parent = 0);

    bool run();
signals:

public slots:

private slots:
    void procOutDataReady();
    void procErrDataReady();

private:
    QProcess *mProc;
    QByteArray mStdOutBuf;
    QByteArray mStdErrBuf;
    bool mSkip;
};

#endif // GDB_H



#include "gdb.h"
#include <QProcess>
#include <QDebug>
#include <QInputDialog>
#include <QMessageBox>

/************************************************

************************************************/
Gdb::Gdb(QObject *parent) :
    QObject(parent),
    mProc(new QProcess(this))
{
}

/************************************************

************************************************/
bool Gdb::run()
{
    mProc->start("gdb");
    mSkip = true;
    if (!mProc->waitForStarted())
        return false;

    connect(mProc, SIGNAL(readyReadStandardOutput()),
            this, SLOT(procOutDataReady()));

    connect(mProc, SIGNAL(readyReadStandardError()),
            this, SLOT(procErrDataReady()));

}


/************************************************

************************************************/
void Gdb::procOutDataReady()
{
    mStdOutBuf += mProc->readAllStandardOutput();
    if (mStdOutBuf.endsWith("(gdb) "))
    {
        if (!mStdErrBuf.isEmpty())
        {
            QMessageBox::warning(0, tr("Warning"), QString::fromLocal8Bit(mStdErrBuf));
            mStdErrBuf.clear();
        }

        bool ok;
        QString command = QInputDialog::getText(0, tr("Command"),
                                                QString::fromLocal8Bit(mStdOutBuf),
                                                QLineEdit::Normal, "", &ok);
        mStdOutBuf.clear();

        if (!ok)
        {
            mProc->write("quit\n");
            mProc->waitForFinished(5000);
        }
        else
        {
            command += '\n';
            mProc->write(command.toLocal8Bit());
        }

    }
}

/************************************************

************************************************/
void Gdb::procErrDataReady()
{
    mStdErrBuf += mProc->readAllStandardError();
}


Не совершай стандартной ошибки новичков, никто не гарантирует, что в момент вызова procOutDataReady, процесс успел выплюнуть весь текст, вполне возможна ситуация, процесс напечатал пол слова, и в этот момент Qt решило эти данные обработать. Т.е. readAllStandardOutput вернет на все данные, а все которые готовы на этот момент. Поэтому надо накапливать в буфере.

Я обрабатываю и STOUT и STDERR, причем немного по другому чем в моей программе. Возможно через события тебе будет удобнее.

Обрати внимание, QString хранит в юникоде, процесс выдает в локальной кодировке, обязательно преобразовывать через fromLocal8Bit и toLocal8Bit

При вводе команды, надо добавлять "\n".

Желательно завершать программу корректно, я посылаю "quit" в gdb и даю ему 5 сек. на завершение.

Я не скипаю приглашение, если надо, то можно добавить условие, и при первом вызове procOutDataReady не выводить текст.

Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 25.11.2024, 21:08