Russian Qt Forum

Qt => Общие вопросы => Тема начата: Gordey1978 от Июль 01, 2010, 20:41



Название: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 20:41
Всем привет.
Помогите пожалуйста наладить перехват stdout консольного приложения.

Использую QT 4.6.3 и Microsoft Visual Studio 2008.

Задача: из Qt GUI запустить консольное приложение, перехватить его стандартный поток ввода/вывода и вывести перехваченные данные в элемент QTextEdit.

Консольное приложение в цикле валит в поток вывода строки
Value: 1
Value: 2
Value: 3
и т.д.

#include <iostream>

int main(int argc, char* argv[])
{
   for(int i =0; i != 1000000; ++i)
      std::cout << "Value: " << i << std::endl;

   return 0;
}

В Qt GUI при нажатии на кнопку создается отдельный поток.

process = new QProcess;
process->setProcessChannelMode(QProcess::MergedChannels);
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(output()));
process->start("test_console.exe");
exec();

При создании потока запускаем процесс с консольным приложением. При получении сигнала readyReadStandardOutput() отправляем считанные данные родительскому приложению.

void ServerThread::output()
{
    QByteArray bytes = process->readAllStandardOutput();
    emit updateOutput(bytes);
}

В Qt GUI получаем посылку с данными и выводим ее в QTextEdit.

void MainWindow::setOutput(const QString &msg)
{
   ui->textEdit->insertPlainText(msg);
}

Проблема в том, что при перехвате потока ввода/вывода и  выводе данных в QTextEdit происходит залипание Qt GUI. То есть я практически ничего не могу сделать с родительским окном.
Как можно решить данную проблему? Как избавиться от залипания QT окна? При решении проблемы изменять код консольного приложения нельзя , нужно решить задачу другими способами.

Файлы проектов выложил на
Скачать test.rar с WebFile.RU (http://webfile.ru/4590573)


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: kuzulis от Июль 01, 2010, 20:52
А вы проверьте, действительно ли QProcess работает в другом потоке?

---

что-то у меня скачался архив в котором только main.cpp


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 20:55
А вы проверьте, действительно ли QProcess работает в другом потоке?

А как проще проверить?


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: BRE от Июль 01, 2010, 20:55
Попробуй:
Код
C++ (Qt)
class ServerThread : public QThread
{
   Q_OBJECT
 
public:
  ServerThread();
 

Код
C++ (Qt)
ServerThread::ServerThread() : QThread( 0 ), process(0)
{
moveToThread( this );
}
 


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: BRE от Июль 01, 2010, 20:56
А как проще проверить?
Посмотреть, что выводит QThread::currentThreadId()


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: kuzulis от Июль 01, 2010, 20:59
Шо ви выкладываете хрень какую-то в аттач? То в *.zip ошибка в архиве, то в *.rar один только main.cpp!?? У меня одного так?


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:01
Шо ви выкладываете хрень какую-то в аттач? То в *.zip ошибка в архиве, то в *.rar один только main.cpp!?? У меня одного так?

Чета архивы портятся при добавлении. Сам обратно заказиваю, а они уже битые. Как выложить то?


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: kuzulis от Июль 01, 2010, 21:01
Ничо не должно бится.. Мож архиватор палёный? :)


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:03
Попробуй:
Код
C++ (Qt)
class ServerThread : public QThread
{
   Q_OBJECT
 
public:
  ServerThread();
 

Код
C++ (Qt)
ServerThread::ServerThread() : QThread( 0 ), process(0)
{
moveToThread( this );
}
 


Не помогло. Залипание не ушло :(


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:04
Ничо не должно бится.. Мож архиватор палёный? :)

Да вроде проверенные :-) Сейчас еще попробую...


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: kuzulis от Июль 01, 2010, 21:06
Цитировать
Не помогло. Залипание не ушло Грустный
Проверьте ID-ы потоков: основного и процессного


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:10
А как проще проверить?
Посмотреть, что выводит QThread::currentThreadId()

На разных.
h1   0x00000e40    void *
h2   0x00000d60    void *

void ServerThread::run()
{
   Qt::HANDLE h2 = QThread::currentThreadId();
}

void MainWindow::on_pushButton_clicked()
{
   Qt::HANDLE h1 = QThread::currentThreadId();
}




Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:16
Вот еще попытка выложить проекты


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: kuzulis от Июль 01, 2010, 21:21
Все-равно косяки с архивами.. Как вариант - перед аттачем архивов - уберите расширение *.txt . может поможет.


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:23
Так как ничего не вышло с архивами дополнительно закачал файлы на webfile.ru

Скачать test.rar с WebFile.RU (http://webfile.ru/4590573)


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 01, 2010, 21:38
Залипание можно убрать если после вывода строки поставить задержку Sleep(1).

Старый вариант:
int main(int argc, char* argv[])
{
   for(int i =0; i != 1000000; ++i)
      std::cout << "Value: " << i << std::endl;

   return 0;
}

Новый вариант:
int main(int argc, char* argv[])
{
   for(int i =0; i != 1000000; ++i)
   {
      std::cout << "Value: " << i << std::endl;
      Sleep(1);
   }

   return 0;
}

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


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: BRE от Июль 01, 2010, 22:20
Ну тогда дай время главному потоку разгребать все сообщения о пришедших сигналах и на вставку текста:
Код
C++ (Qt)
void ServerThread::output()
{
   msleep( 200 );
   QByteArray bytes = process->readAllStandardOutput();
   emit updateOutput(bytes);
}
 
Также можно складывать пришедшие данные в промежуточный буфер и когда соберется определенное количество данных отправлять их одним эмитом.

Думаю, стоит обратить внимание на класс QPlainTextEdit, он по-быстрее QTextEdit.


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 02, 2010, 05:56
Ну тогда дай время главному потоку разгребать все сообщения о пришедших сигналах и на вставку текста:
Код
C++ (Qt)
void ServerThread::output()
{
   msleep( 200 );
   QByteArray bytes = process->readAllStandardOutput();
   emit updateOutput(bytes);
}
 
Также можно складывать пришедшие данные в промежуточный буфер и когда соберется определенное количество данных отправлять их одним эмитом.

Думаю, стоит обратить внимание на класс QPlainTextEdit, он по-быстрее QTextEdit.
С msleep( 200 ) попробовал... не помогло :-(


Все попробовал. Ничего не помогло :-(


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Гурман от Июль 02, 2010, 14:35
я бы дал идею не просто создать процесс-перехватчик запуском одного QProcess, а запустить второй QThread, в нем запускать QProcess, получать там данные дочернего приложения, и через BlockingQueuedConnection передавать в QTextEdit основной нити - так интерфейс гарантированно блокироваться не будет

у меня в приложении похожим образом работает "консоль" - основные действия выполняются фоновым QThread, из которого через блокирующее соединение вычислитель плюется сообщениями, и эти сообщения валятся в QTextEdit в основном треде

только вот QTextEdit при этом все сильно тормозит, он на добавлении строк медлееееееннннннныыыыыыййййй..... :( поэтому при полностью асинхронной работе дочернего приложения вполне возможна потеря части сообщений


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 02, 2010, 15:29
я бы дал идею не просто создать процесс-перехватчик запуском одного QProcess, а запустить второй QThread, в нем запускать QProcess, получать там данные дочернего приложения, и через BlockingQueuedConnection передавать в QTextEdit основной нити - так интерфейс гарантированно блокироваться не будет

у меня в приложении похожим образом работает "консоль" - основные действия выполняются фоновым QThread, из которого через блокирующее соединение вычислитель плюется сообщениями, и эти сообщения валятся в QTextEdit в основном треде

только вот QTextEdit при этом все сильно тормозит, он на добавлении строк медлееееееннннннныыыыыыййййй..... :( поэтому при полностью асинхронной работе дочернего приложения вполне возможна потеря части сообщений


А код отвечающий за перехват и работу через BlockingQueuedConnection не можешь выложить?


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Гурман от Июль 02, 2010, 19:22
код, отвечающий за перехват - это не мой код, это ваш код...


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 04, 2010, 08:11
Неужто здесь на форуме нет гуру способных помочь?


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: niXman от Июль 04, 2010, 21:42
у меня подобная задача работает превосходно.
установи монитор событий на дескрипторе, например, epoll() (http://linux.die.net/man/4/epoll) или select() (http://linux.die.net/man/2/select)


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: niXman от Июль 04, 2010, 22:14
только буферизацию на дескрипторе не забудь отключить ;)


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 05, 2010, 05:40
у меня подобная задача работает превосходно.
установи монитор событий на дескрипторе, например, epoll() (http://linux.die.net/man/4/epoll) или select() (http://linux.die.net/man/2/select)

Если это реализовывать на чистых С++ + WinAPI, то и у меня все работает отлично. А вот с QT не очень получается :-(


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: niXman от Июль 05, 2010, 06:19
Цитировать
А вот с QT не очень получается :-(
а должно? ;)


Название: Re: Помогите пожалуйста наладить перехват stdout консольного приложения.
Отправлено: Gordey1978 от Июль 05, 2010, 16:47
Цитировать
А вот с QT не очень получается :-(
а должно? ;)

Думаю, что способ есть :-)