how to use QProcess to wrap telenet.exe on Windows? - c++

I'm trying to code a wrapper class using QProcess to drive the CLI applications (e.g. telnet.exe, ftp.exe) on Windows but so far with no luck. Do you know if this is even possible?
Below is the code I used to try with telnet.exe on Windows 7. I was expecting this code will print out the "welcome message" after telnet connected to the server but there is nothing print out (from standard output or error output).
#include <QCoreApplication>
#include <QProcess>
#include <iostream>
class ProcessWrapper :public QObject
{
Q_OBJECT
public:
ProcessWrapper();
~ProcessWrapper();
void start();
public slots:
void readStandardError();
void readStandardOutput();
private:
QProcess *process;
};
ProcessWrapper::ProcessWrapper()
{
process = new QProcess(this);
connect(process, SIGNAL(readyReadStandardError()), this, SLOT(readStandardError()));
connect(process, SIGNAL(readyReadStandardOutput()), this, SLOT(readStandardOutput()));
}
void ProcessWrapper::start()
{
if(process) {
process->start("telnet.exe",QStringList() << "135.251.142.36");
process->waitForStarted();
}
}
ProcessWrapper::~ProcessWrapper()
{
if(process) delete process;
}
void ProcessWrapper::readStandardOutput()
{
if(process) {
QByteArray s = process->readAllStandardOutput();
QString str(s);
std::cout << str.toStdString();
}
}
void ProcessWrapper::readStandardError()
{
if(process) {
QByteArray s = process->readAllStandardError();
QString str(s);
std::cout << str.toStdString();
}
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ProcessWrapper p;
p.start();
return a.exec();
}
#include "main.moc"

The function main() exit immediately after you called ProcessWrapper::start().

Related

Sending data to QSerialPort from another thread

I'm trying to send some data over serial port using QSerialPort class. Sending data from the same parent class every time works well. But when I'm trying to send data using another thread QSerialPort it doesn't. I used serial port monitor to watch the data and it showed nothing.
Code is looks like this:
#include <QSerialPort>
#include <QObject>
#include <QDebug>
#include <QCoreApplication>
#include <thread>
#include <mutex>
#include <list>
#include <memory>
class Message {
public:
bool isSent;
bool isProcessed;
int data;
Message(int d) :
data(d),
isSent(false),
isProcessed(false) {
}
};
class SerialClass : public QObject {
Q_OBJECT
public:
SerialClass(unsigned short portNumber, unsigned int baudrate, QObject *parent = 0) :
_portNumber(portNumber),
_baudrate(baudrate),
_serialPort(new QSerialPort(this)),
_messages(),
_writeThread(nullptr),
QObject(parent) {
_serialPort->setPortName(QString("COM%1").arg(_portNumber));
_serialPort->setBaudRate(baudrate);
_serialPort->setDataBits(QSerialPort::DataBits::Data8);
_serialPort->setParity(QSerialPort::Parity::NoParity);
_serialPort->setStopBits(QSerialPort::StopBits::OneStop);
}
void start() {
if (!_serialPort->open(QIODevice::ReadWrite)) {
qDebug() << "Couldn't open serial port";
return;
}
auto *m = &_messages;
auto *p = &_enableProcessing;
auto *port = _serialPort.get();
auto *mutex = &_mutex;
_serialPort->write(QString("Hello\r\n").toLocal8Bit());
_writeThread = std::make_unique<std::thread>([m, p, port, mutex]() {
qDebug() << "Work thread started";
while (*p) {
std::this_thread::sleep_for(std::chrono::milliseconds(15));
auto inactiveMessage = std::find_if(m->begin(), m->end(), [](Message &item) {
return !item.isSent;
});
if (inactiveMessage != m->end()) {
mutex->lock();
qDebug() << "Written" << port->write(QString("data %1\r\n").arg(inactiveMessage->data).toLocal8Bit());
inactiveMessage->isSent = true;
mutex->unlock();
}
}
qDebug() << "Work thread stopped";
});
}
void wait() {
if (!_writeThread) {
return;
}
_writeThread->join();
}
void addMessage(Message& msg) {
_mutex.lock();
_messages.push_back(msg);
_mutex.unlock();
}
private:
unsigned short _portNumber;
unsigned int _baudrate;
std::unique_ptr<QSerialPort> _serialPort;
std::unique_ptr<std::thread> _writeThread;
std::list<Message> _messages;
bool _enableProcessing;
std::mutex _mutex;
};
int main(int argc, char ** argv) {
QCoreApplication application(argc, argv);
SerialClass serialProcessor(2, 9600, &application);
serialProcessor.addMessage(Message(228));
serialProcessor.addMessage(Message(929));
serialProcessor.addMessage(Message(221424));
serialProcessor.start();
return application.exec();
}
#include "main.moc"
Does it means what the QSerialPort class can not transmit data from another thread? (not QSerialPort thread)
It is recommended not to mix STL and Qt solutions in the same project
QSerialPort can work in any thread
You can see an example of correct using of QThread here: https://stackoverflow.com/a/35673612/4149835

QStateMachine not executing correctly when using QCoreApplication

I am trying to implement a simple state machine within a console application. The signals that are supposed to trigger the state transitions are being emitted, however, the state machine is not reacting to those signals.
This state machine works perfectly when running within a QApplication (i.e. a GUI application), however I am wanting to develop a console application. I suspect there is an issue in the way I have implemented the event loop, as the QStateMachine is not emitting the started() signal.
What is the correct way to execute the application in order for the state machine to function correctly?
main.cpp:
#include <QCoreApplication>
#include "test.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
QMetaObject::invokeMethod( &test, "Run", Qt::QueuedConnection );
return a.exec();
}
test.h:
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QStateMachine>
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = 0) : QObject(parent) {}
public slots:
void Run();
signals:
void stateChanged();
void debugSignal();
private:
void buildStateMachine();
QStateMachine machine;
private slots:
void runS1();
void runS2();
void runS3();
void debugSlot();
};
#endif // TEST_H
test.cpp:
#include "test.h"
#include <QDebug>
void Test::Run()
{
buildStateMachine();
QTextStream qin(stdin);
while (true)
{
QString line = qin.readLine();
qDebug() << "line: " << line;
if (line == "A")
{
qDebug() << "emit stateChanged signal";
emit stateChanged();
}
else if (line == "B")
{
qDebug() << "emit debugSignal";
emit debugSignal();
}
}
}
void Test::buildStateMachine()
{
connect(&machine, SIGNAL(started()), this, SLOT(debugSlot())); // doesn't seem to get triggered... (why is machine not starting?)
connect(this, SIGNAL(debugSignal()), this, SLOT(debugSlot())); // works as expected
QState *s1 = new QState(&machine);
QState *s2 = new QState(&machine);
QState *s3 = new QState(&machine);
s1->addTransition(this, SIGNAL(stateChanged()), s2);
s2->addTransition(this, SIGNAL(stateChanged()), s3);
s3->addTransition(this, SIGNAL(stateChanged()), s1);
connect(s1, SIGNAL(entered()), this, SLOT(runS1())); // these are never triggered
connect(s2, SIGNAL(entered()), this, SLOT(runS2()));
connect(s3, SIGNAL(entered()), this, SLOT(runS3()));
s1->assignProperty(&machine, "state", 1);
s2->assignProperty(&machine, "state", 2);
s3->assignProperty(&machine, "state", 3);
machine.setInitialState(s1);
machine.start();
}
void Test::runS1()
{
qDebug() << "entered state S1";
}
void Test::runS2()
{
qDebug() << "entered state S2";
}
void Test::runS3()
{
qDebug() << "entered state S3";
}
void Test::debugSlot()
{
qDebug() << "slot was triggered!";
}
Solved my problem. The issue was caused by the infinite while loop. The slot can only be called once the Run function ends, which obviously never occurs.
Here is a working solution. The change to the Qt 5 style signals and slots syntax is optional. If main.cpp is kept as-is from the version shown in the question above, the application will not quit correctly.
main.cpp:
#include <QCoreApplication>
#include <QTimer>
#include "test.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
Test test;
QObject::connect(&test, &Test::finished, &a, &QCoreApplication::quit, Qt::QueuedConnection);
QTimer::singleShot(0, &test, &Test::Run);
return a.exec();
}
test.h:
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include <QStateMachine>
class Test : public QObject
{
Q_OBJECT
public:
explicit Test(QObject *parent = 0);
signals:
void next_state();
void finished();
private:
void buildStateMachine();
QStateMachine machine;
public slots:
void Run();
void runS1();
void runS2();
void runS3();
void debugSlot();
};
#endif // TEST_H
test.cpp:
#include "test.h"
#include <iostream>
#include <QTextStream>
Test::Test(QObject * parent) : QObject(parent)
{
buildStateMachine();
}
void Test::Run()
{
QTextStream qin(stdin);
std::cout << "line: ";
QString line = qin.readLine();
if (line == "A")
{
std::cout << "emit stateChanged signal" << std::endl;
emit next_state();
}
else if (line == "q")
{
emit finished();
}
else
{
Run();
}
}
void Test::buildStateMachine()
{
QState *s1 = new QState(&machine);
QState *s2 = new QState(&machine);
QState *s3 = new QState(&machine);
s1->addTransition(this, SIGNAL(next_state()), s2);
s2->addTransition(this, SIGNAL(next_state()), s3);
s3->addTransition(this, SIGNAL(next_state()), s1);
connect(s1, &QState::entered, this, &Test::runS1);
connect(s2, &QState::entered, this, &Test::runS2);
connect(s3, &QState::entered, this, &Test::runS3);
machine.setInitialState(s1);
machine.start();
}
void Test::runS1()
{
std::cout << "entered state S1" << std::endl;
Run();
}
void Test::runS2()
{
std::cout << "entered state S2" << std::endl;
Run();
}
void Test::runS3()
{
std::cout << "entered state S3" << std::endl;
Run();
}
void Test::debugSlot()
{
std::cout << "debug slot was triggered!" << std::endl;
Run();
}

How to fix the runtime crash - QObject::setParent: Cannot set parent, new parent is in a different thread?

I have written a QT - webkit application. this application fires a callback when my pSeudo driver gets the character 'l'. However, the application crashes during a firecallback - it says - QObject::setParent: Cannot set parent, new parent is in a different thread. I don't know to fix this, I tried doing moveToThread, but it doesn't help. Please help me here.
#include <QtGui/QApplication>
#include <QApplication>
#include <QDebug>
#include <QWebFrame>
#include <QWebPage>
#include <QWebView>
#include <QThread>
#include <unistd.h>
#include <fcntl.h>
class DemoThread;
class MyJavaScriptOperations : public QObject {
Q_OBJECT
public:
QWebView *view;
DemoThread *m_pDemoThread;
MyJavaScriptOperations();
void firecb();
bool slot_installed;
signals:
void alert_script_signal();
public slots:
void JS_ADDED();
void loadFinished(bool);
private:
};
class DemoThread : public QThread {
public:
DemoThread( MyJavaScriptOperations *pJavascriptOp);
protected:
void run();
private :
MyJavaScriptOperations *m_pJavascriptOp;
};
DemoThread::DemoThread(MyJavaScriptOperations *pJavascriptOp):m_pJavascriptOp(pJavascriptOp)
{
}
void DemoThread:: run()
{
int filedesc = open("/dev/pSeudoDrv", O_RDONLY);
if(filedesc < 0)
{
qDebug()<<"Couldn't open Driver.";
}
unsigned char buff;
while(1)
{
read(filedesc,&buff, 1);
qDebug()<<"The code received is "<< buff;
if ( (m_pJavascriptOp->slot_installed == true) && (buff == 166))
{
m_pJavascriptOp->firecb();
}
qDebug()<<"Running Thread.";
sleep(6);
}
}
void MyJavaScriptOperations::JS_ADDED()
{
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->addToJavaScriptWindowObject("myoperations", this);
}
void MyJavaScriptOperations::loadFinished(bool oper)
{
qDebug()<<__PRETTY_FUNCTION__<< oper;
slot_installed = true;
// firecb();
}
void MyJavaScriptOperations::firecb()
{
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->evaluateJavaScript("JavaScript_function()");
}
MyJavaScriptOperations::MyJavaScriptOperations()
{
qDebug()<<__PRETTY_FUNCTION__;
view = new QWebView();
view->resize(400, 500);
connect(view->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(JS_ADDED()));
connect(view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
view->load(QUrl("./index.html"));
view->show();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyJavaScriptOperations *jvs = new MyJavaScriptOperations;
DemoThread *thread = new DemoThread(jvs);
jvs->moveToThread(thread);
thread->start();
return a.exec();
}
#include "main.moc"
This is the crash-error I get -
./QT_DEMO
MyJavaScriptOperations::MyJavaScriptOperations()
loaded the Generic plugin
The code received is 156
Running Thread.
The code received is 166
void MyJavaScriptOperations::firecb()
QObject::setParent: Cannot set parent, new parent is in a different thread
There are few articles on internet how to make multithreaded applications in Qt. Best explanation can be found here:
http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
You could read also other articles:
https://www.qt.io/blog/2010/06/17/youre-doing-it-wrong
http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/
Well, I got a solution for my problem. Please tell me, am I complicating the solution.
I am using signal and slot. The thread will emit the signal and the slot of other class will emit the callback to the Qtwebkit - the javascript function. IS it right?
Because, I have suggestion using event loop - exec().
#include <QtGui/QApplication>
#include <QApplication>
#include <QDebug>
#include <QWebFrame>
#include <QWebPage>
#include <QWebView>
#include <QThread>
/** for reading my driver **/
#include <unistd.h>
#include <fcntl.h>
class DemoThread;
class MyJavaScriptOperations : public QObject
{
Q_OBJECT
public:
QWebView *view;
DemoThread *m_pDemoThread;
MyJavaScriptOperations();
void firecb();
bool slot_installed;
signals:
void alert_script_signal();
public slots:
void JsAdded();
void alertReceived();
void loadFinished(bool);
private:
};
class DemoThread : public QThread
{
Q_OBJECT
private:
MyJavaScriptOperations *m_pJavascriptOp;
public:
DemoThread( MyJavaScriptOperations *pJavascriptOp);
protected:
void run();
signals:
void alertSendSignal();
};
DemoThread::DemoThread(MyJavaScriptOperations *pJavascriptOp):m_pJavascriptOp(pJavascriptOp)
{
connect(this, SIGNAL(alertSendSignal()), m_pJavascriptOp, SLOT(alertReceived()));
}
void DemoThread:: run()
{
int filedesc = open("/dev/pSeudoDrv", O_RDONLY);
if(filedesc < 0)
{
qDebug()<<"Couldn't open Driver.";
}
unsigned char buff;
while(1)
{
if( 1 != read(filedesc,&buff, 1))
{
qDebug()<<"Read Invalid Data";
}
qDebug()<<"The code received is "<< buff;
/** In my laptop, the 166 means the character 'l' **/
if ( (m_pJavascriptOp->slot_installed == true) && (buff == 166))
{
emit alertSendSignal();
}
qDebug()<<"Running Thread.";
}
}
void MyJavaScriptOperations::JsAdded()
{
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->addToJavaScriptWindowObject("myoperations", this);
}
void MyJavaScriptOperations::loadFinished(bool oper)
{
qDebug()<<__PRETTY_FUNCTION__<< oper;
slot_installed = true;
}
void MyJavaScriptOperations::alertReceived()
{
qDebug()<<"Sending Firecallback now";
firecb();
}
void MyJavaScriptOperations::firecb()
{
qDebug()<<__PRETTY_FUNCTION__;
view->page()->mainFrame()->evaluateJavaScript("JavaScript_function()");
}
MyJavaScriptOperations::MyJavaScriptOperations()
{
qDebug()<<__PRETTY_FUNCTION__;
view = new QWebView();
view->resize(400, 500);
connect(view->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()), this, SLOT(JsAdded()));
connect(view, SIGNAL(loadFinished(bool)), this, SLOT(loadFinished(bool)));
view->load(QUrl("./index.html"));
view->show();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyJavaScriptOperations *jvs = new MyJavaScriptOperations;
DemoThread *thread = new DemoThread(jvs);
thread->start();
return a.exec();
}
#include "main.moc"

Why does this Qt signal never get emitted?

I am trying to get data out of a web page, but the signal finished() never gets emitted!!! I know I must be doing something wrong, but can't figure out what it is.
# webservice.h
class WebService:public QObject
{
Q_OBJECT
public:
explicit WebService(QObject *parent=0);
void getRequest(const QString &urlString);
signals:
void networkError(QNetworkReply::NetworkError ne);
void finished(QNetworkReply*);
public slots:
void parseNetworkResponse(QNetworkReply* finished);
private:
QNetworkAccessManager *netMgr;
public:
QByteArray data;
};
#webservice.cpp
WebService::WebService(QObject *parent):QObject(parent)
{
netMgr = new QNetworkAccessManager;
connect(netMgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(parseNetworkResponse(QNetworkReply*)));
}
void WebService::getRequest(const QString &urlString)
{
QUrl url(urlString);
QNetworkRequest req;
emit finished(netMgr->get(req));
}
void WebService::parseNetworkResponse(QNetworkReply *finished)
{
if (finished->error() != QNetworkReply::NoError)
{
emit networkError(finished->error());
return;
}
data = finished->readAll();
qDebug() << data;
}
data never gets assigned a value as expected.
You aren't passing the url to the QNetworkRequest you create. Try:
QNetworkRequest req(url);
inside WebService::getRequest().
As requested, here's the source modified to allow it compile and work inside QtCreator as a single main.cpp file in a console application project:
#include <QCoreApplication>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QByteArray>
#include <QString>
#include <QDebug>
//# webservice.h
class WebService:public QObject
{
Q_OBJECT
public:
explicit WebService(QObject *parent=0);
void getRequest(const QString &urlString);
signals:
void networkError(QNetworkReply::NetworkError ne);
void finished(QNetworkReply*);
public slots:
void parseNetworkResponse(QNetworkReply* finished);
private:
QNetworkAccessManager *netMgr;
public:
QByteArray data;
};
//#webservice.cpp
WebService::WebService(QObject *parent):QObject(parent)
{
netMgr = new QNetworkAccessManager;
connect(netMgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(parseNetworkResponse(QNetworkReply*)));
}
void WebService::getRequest(const QString &urlString)
{
QUrl url(urlString);
QNetworkRequest req(url);
emit finished(netMgr->get(req));
}
void WebService::parseNetworkResponse(QNetworkReply *finished)
{
if (finished->error() != QNetworkReply::NoError)
{
qDebug() << "QNetworkReply error: " << finished->error();
emit networkError(finished->error());
return;
}
data = finished->readAll();
qDebug() << data;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WebService web;
web.getRequest("http://www.google.com");
return a.exec();
}
#include "main.moc"
The minor modifications that were made:
added necessary headers
added a main() that called WebService::getRequest() with an appropriate URL
added #include "main.moc" to the end of the main.cpp file so qmake would "moc-ify" it properly as a single, self-contained .cpp file
made the fix mentioned above in the answer to the question
added a qDebug() output in the error case
One final thing that needed to be done was to add QT += network in the .pro file for the project so the Qt networking modules get added to the link step and to the header search path.
Update 15 Oct 2013
From your comments, it looks like you want the QNetworkAccessManager::get() call to be synchronous. I've added another version of your example program that will block in WebService::getRequest() until the request's finished signal is received. Note that this example doesn't perform much in the way of error handling, and would probably perform very badly if the netwrok request fails to complete in a timely manner. Dealing apprpriately with errors and timeouts would be necessary for anything but example or study code.
The basic idea in this example is that the signals emitted in the asynchronous Qt networking model are driven by the framework's event loop. So when a request is made, a new 'nested' event loop is created and the WebService::getRequest() function execs that loop (and stays there) until the handler of the finished signal tells the event loop to exit.
#include <QCoreApplication>
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QNetworkAccessManager>
#include <QUrl>
#include <QEventLoop>
#include <QByteArray>
#include <QString>
#include <QDebug>
//# webservice.h
class WebService:public QObject
{
Q_OBJECT
public:
explicit WebService(QObject *parent=0);
void getRequest(const QString &urlString);
signals:
void networkError(QNetworkReply::NetworkError ne);
//void finished(QNetworkReply*);
public slots:
void parseNetworkResponse(QNetworkReply* finished);
private:
QNetworkAccessManager *netMgr;
QEventLoop request_event_loop;
public:
QByteArray data;
};
//#webservice.cpp
WebService::WebService(QObject *parent):QObject(parent)
{
netMgr = new QNetworkAccessManager;
connect(netMgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(parseNetworkResponse(QNetworkReply*)));
}
void WebService::getRequest(const QString &urlString)
{
QUrl url(urlString);
QNetworkRequest req(url);
netMgr->get(req);
request_event_loop.exec(); // wait here until the WebService::parseNetworkResponse() slot runs
// emit finished(netMgr->get(req));
}
void WebService::parseNetworkResponse(QNetworkReply *finished)
{
qDebug() << "enter parseNetworkResponse()";
if (finished->error() != QNetworkReply::NoError)
{
qDebug() << "QNetworkReply error: " << finished->error();
emit networkError(finished->error());
}
else {
data = finished->readAll();
qDebug() << data;
}
qDebug() << "request_event_loop.exit()";
request_event_loop.exit();
qDebug() << "exit parseNetworkResponse()";
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
WebService web;
qDebug() << "main() getRequest()";
web.getRequest("http://www.stackoverflow.com");
qDebug() << "main() getRequest() completed";
return a.exec();
}
#include "main.moc"

Qt 5 and QProcess redirect stdout with signal/slot readyRead

This problem is bothering me because it should work, but sadly it does not.
What i try to achieve is to read the standard output of a certain process and make another process handle it i.e. print it out.
The process that produces output looks like this:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
int main() {
for (int i = 0; i < 100; i++) {
printf("yes %d\n",i);
fflush(stdout);
sleep(1);
}
return 0;
}
The process is started in another application like this:
#include <QProcess>
...
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:" << process->readAllStdOutput();
}
My expected output would be:
Reading: yes 0
Reading: yes 1
...
Reading: yes 99
However i get no output at all.
And when i use QCoreApplication i get all the output but not through the signal/slot but directly in the console.
I dont understand because it works in another application that uses Qt 4.8.
My question is, is anyone experiencing the same problem or does anyone know how i can get the expected behaviour?
Your problem in the answer you provide lies in misunderstanding how the reading works. It simply returns whatever data you've got there, whether there are line endings or not. By spawning a thread and sleeping between lines, you're effectively sending the inter-process data in line-sized chunks since the pipe is flushed when you wait long enough.
So, your answer, while working, is not really how one should do it. You need to use readLine() to chop the incoming data into lines. Below is an example with following qualities:
There's just one executable :)
Only Qt apis are used. This reduces the runtime memory consumption.
Both processes cleanly terminate.
The amount of code is as minimal as practicable.
// https://github.com/KubaO/stackoverflown/tree/master/questions/process-17856897
#include <QtCore>
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"
Based on the code you've posted, you're connecting to the class slot with this: -
connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyReadStdOutput()));
But the function in the class is declared like this: -
void SomeClass::onReadyRead();
If you're expecting onReadyRead to be called, then you should be calling it in the SLOT, rather than onReadyReadStdOutput. So change your connection to: -
connect(process,SIGNAL(readyRead()),someClass,SLOT(onReadyRead()));
Well i solved my problem.
If the process is started with startDetached() it will not receive the signals from readyRead(), readyReadStandardOutput() and readyReadStandardError().
So just starting it with start() solved the problem.
However i noticed that if i start and do the while loop and prints in main() it will read everything at once even if it ends with \n. So i started the while loop in a thread and that problem was also solved. Everything prints as expected.
#include <QThread>
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 <QProcess>
#include <iostream>
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();
}