Версия для печати темы
Форум на CrossPlatform.RU _ Qt Общие вопросы _ связь между терминалом и gui программой
Автор: ht1515 31.1.2014, 18:00
Всем привет!
Есть консольная программа - терминал. Там вводятся команды, выполняются и результат сразу же печатается в программе( н-р командная строка в винде ).
Я хочу ее связать с gui программой написанной на куте. Никакой сессии, общей памяти консольная программа не дает. Она подразумевает наличие оператора ПК, который тыкать будет команды.
Можно ли каким-нибудь хитрым способом передавать консольной проге команды, чтобы она их выполняла и потом получать ответ?
Автор: Sokoloff 31.1.2014, 19:40
Цитата(ht1515 @ 31.1.2014, 19:00)
Всем привет!
Есть консольная программа - терминал. Там вводятся команды, выполняются и результат сразу же печатается в программе( н-р командная строка в винде ).
Я хочу ее связать с gui программой написанной на куте. Никакой сессии, общей памяти консольная программа не дает. Она подразумевает наличие оператора ПК, который тыкать будет команды.
Можно ли каким-нибудь хитрым способом передавать консольной проге команды, чтобы она их выполняла и потом получать ответ?
Никакого хитрого способа не надо, используй QProcess. Вот реальный пример из моей программы https://github.com/flacon/flacon/blob/master/converter/splitter.cpp#L127 Смотри метод Splitter::doRun()
У меня, правда, немного другая ситуация, я запускаю программу, передаю в нее данные,
закрываю STDIN, а потом читаю из STDOUT-а, но очень близко к твоему случаю, тебе не надо дергать closeWriteChannel.
Автор: ht1515 31.1.2014, 20:46
ммм... спасибо. Посмотрю.
Я прокомментирую ,вы поправьте если что.
Цитата
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
Все что я не комментирую правильно.
Цитата(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
Вчера вечером почитал
http://doc.crossplatform.ru/qt/4.7.x/qprocess.html#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
Цитата(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 не выводить текст.
Форум Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)