Qt 5和QProcess使用signal / slot readyRead重定向stdout

这个问题困扰我,因为它应该工作,但遗憾的是它没有。 我试图实现的是读取某个过程的标准输出并使另一个过程处理它,即将其打印出来。

生成输出的过程如下所示:

#include  #include  #include  int main() { for (int i = 0; i < 100; i++) { printf("yes %d\n",i); fflush(stdout); sleep(1); } return 0; } 

该过程在另一个应用程序中启动,如下所示:

 #include  ... QProcess * process = new QProcess; SomeClass * someClass = new SomeClass(process); connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyRead())); process->start("../Test/Test",QStringList()); if (!process->waitForStarted(4000)) { qDebug() << "Process did not start."; } ... void SomeClass::onReadyRead() { qDebug() << "Reading:" <readAllStdOutput(); } 

我的预期输出是:

 Reading: yes 0 Reading: yes 1 ... Reading: yes 99 

但是我根本没有输出。 当我使用QCoreApplication时,我得到所有输出,但不是通过信号/插槽,而是直接在控制台中。

我不明白,因为它适用于使用Qt 4.8的另一个应用程序。

我的问题是,是否有人遇到同样的问题或有谁知道我如何能得到预期的行为?

您提供的答案中的问题在于误解了阅读的工作原理。 它只返回你在那里得到的任何数据,无论是否有行结尾。 通过生成一个线程并在线之间hibernate,您可以有效地以行大小的块发送进程间数据,因为当您等待足够长时间时管道会被刷新。

所以,你的答案,在工作时,并不是真的应该怎么做。 您需要使用readLine()将传入的数据切割成行。 以下是具有以下品质的示例:

  1. 只有一个可执行文件:)
  2. 仅使用Qt apis。 这减少了运行时内存消耗。
  3. 两个过程都干净地终止。
  4. 代码量尽可能小。
 // https://github.com/KubaO/stackoverflown/tree/master/questions/process-17856897 #include  QTextStream out{stdout}; class Slave : public QObject { QBasicTimer m_timer; int m_iter = 0; void timerEvent(QTimerEvent * ev) override { if (ev->timerId() == m_timer.timerId()) { out << "iteration " << m_iter++ << endl; if (m_iter > 35) qApp->quit(); } } public: Slave(QObject *parent = nullptr) : QObject(parent) { m_timer.start(100, this); } }; class Master : public QObject { Q_OBJECT QProcess m_proc{this}; Q_SLOT void read() { while (m_proc.canReadLine()) { out << "read: " << m_proc.readLine(); out.flush(); // endl implicitly flushes, so we must do the same } } Q_SLOT void started() { out << "started" << endl; } Q_SLOT void finished() { out << "finished" << endl; qApp->quit(); } public: Master(QObject *parent = nullptr) : QObject(parent) { connect(&m_proc, SIGNAL(readyRead()), SLOT(read())); connect(&m_proc, SIGNAL(started()), SLOT(started())); connect(&m_proc, SIGNAL(finished(int)), SLOT(finished())); m_proc.start(qApp->applicationFilePath(), {"dummy"}); } }; int main(int argc, char *argv[]) { QCoreApplication app{argc, argv}; if (app.arguments().length() > 1) new Slave{&app}; // called with an argument, this is the slave process else new Master{&app}; // no arguments, this is the master return app.exec(); } #include "main.moc" 

根据您发布的代码,您将使用以下代码连接到类槽: –

 connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyReadStdOutput())); 

但是类中的函数声明如下: –

 void SomeClass::onReadyRead(); 

如果您希望调用onReadyRead,那么您应该在SLOT中调用它,而不是onReadyReadStdOutput。 因此,请将您的连接更改为: –

  connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyRead())); 

好吧,我解决了我的问题。

如果使用startDetached()启动进程,它将不会从readyRead()readyReadStandardOutput()readyReadStandardError()接收信号。

所以刚用start()启动就解决了这个问题。

但是我注意到,如果我开始并执行while循环并在main()中打印,它将立即读取所有内容,即使它以\ n结尾。 所以我在一个线程中启动了while循环,这个问题也解决了。 一切都按预期打印。

 #include  class Thread : public QThread { Q_OBJECT public: explicit Thread(QObject *parent = 0) : QThread(parent) {} protected: void run() { for (int i = 0; i < 100; i++) { std::cout << "yes" << i << std::endl; msleep(200); } exit(0); } }; int main(int argc, char ** argv) { QCoreApplication app(argc,argv); Thread * t = new Thread(); t->start(); return app.exec(); } 

TestP main.cpp

 #include  #include  class Controller : public QObject { Q_OBJECT private: QProcess * process; public: Controller(QObject *parent = 0) : QObject(parent), process(new QProcess) {} void init(const QString &program) { connect(process,SIGNAL(readyRead()),this,SLOT(readStdOut())); connect(process,SIGNAL(started()),this,SLOT(onStarted())); connect(process,SIGNAL(finished(int)),this,SLOT(onFinished(int))); process->start(program); } private slots: void readStdOut() { std::cout << "YES " << QString(process->readAllStandardOutput()).toUtf8().constData() << std::endl; } void onStarted(){ std::cout << "Process started" << std::endl; } void onFinished(int) { std::cout << "Process finished: " << signal << std::endl; } }; int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); Controller c; c.init("../Test/Test"); return a.exec(); }