I have to get the output of a QProcess while it is running. Therefore I have written the following Code:
CommandExecutor_C::CommandExecutor_C():
mProcessStatus(AI_UNKNOWN),
mOnTdiActiveCallback(),
mTdiProcess(new QProcess)
{
connect(mTdiProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(CheckOutput()));
connect(mTdiProcess, SIGNAL(readyReadStandardError()), this, SLOT(CheckOutput()));
}
void CommandExecutor_C::ExecuteCommand(QString &aCommand)
{
mTdiProcess->start(aCommand, QProcess::Unbuffered | QProcess::ReadWrite);
LOGINFO(FB_TDI,"Launch command: " + aCommand.toStdString());
}
void CommandExecutor_C::CheckOutput()
{
QString StdOut = QString(mTdiProcess->readAllStandardOutput());
QString StdErr = QString(mTdiProcess->readAllStandardError());
mProcessStatus = CheckTdiAutomationInterface(StdOut.toStdString(), StdErr.toStdString());
if(mProcessStatus != AI_UNKNOWN)
{
OnTdiActive(mProcessStatus);
}
}
This works fine if QProcess gets finished but in my case the Process starts an automation interface which should run in background permanently. Therefore I have used "readyReadStandardOutput" and connect it to the slot CheckOutput(). CheckOutput() is getting called just if the process has been finished. Otherwise I am waiting endless.
I have googled a lot about the problem but nothing worked. I am very sure that the output is getting buffered and does just return if the Process has finished. Therefore I have started the Process in Unbuffered-Mode. I have also tried to forward the channels of mTdiProcess. Here the Code:
void CommandExecutor_C::ExecuteCommand(QString &aCommand)
{
mTdiProcess->setProcessChannelMode(QProcess::ForwardedChannels);
mTdiProcess->start(aCommand, QProcess::Unbuffered | QProcess::ReadWrite);
LOGINFO(FB_TDI,"Launch command: " + aCommand.toStdString());
}
But nothing worked. I hope you can help me.
I am using Qt 5.4.2 if that's important.
I usually check the output in regular intervals like this:
bool returnBool = false;
while (returnBool == false)
{
/*! Wait one second if the process finishes. Then read all output to
* stdout and stderr and redo. */
returnBool = process.waitForFinished(1000);
QString outputStdOut = process.readAllStandardOutput();
QString outputStdErr = process.readAllStandardError();
}
Related
I need some help with this:
I want to start a script ("test.sh") from inside my code and read the output. The script is giving an output string in an interval of 3 seconds for 5 times. So the output string is generated 5 times with a pause of 3 seconds in between. I want to display the output strings in a QTextBrowser. The string should be added every 3 seconds (as it comes from the script). Therefore I connected the readyReadStandardOutput() signal from QProcess to a slot but this slot is never entered. The connect function returns true. So no problem there, I guess.
There is some code:
void DialogWindow::startScript()
{
QProcess* prcs = new QProcess(this);
connect(prcs, SIGNAL(readyReadStandardOutput()), this, SLOT(slot_readyReadStandardOutput()));
QString program = "./test.sh";
prcs->setProgram(program);
prcs->open();
if(prcs->isOpen())
prcs->execute("test.sh"); //this line is executed
prcs->waitForStarted(6000);
qDebug() << prcs->state(); // --> "QProcess::NotRunning"
qDebug() << prcs->error(); // --> "QProcess::FailedToStart"
qDebug() << prcs->errorString(); // --> "0x000000c1"
qDebug() << prcs->workingDirectory(); // --> ""
}
void DialogWindow::slot_readyReadStandardOutput()
{
QTextBrowser* m_pTextBrowser = new QTextBrowser();
prcs->readAllStandardOutput();
prcs->readAllStandardError();
QString output = prcs->readAllStandardOutput();
if(output.contains("warning"))
m_pTextBrowser->setTextColor(QColor(Qt::yellow));
if(output.contains("error"))
{
m_pTextBrowser->setTextColor(QColor(Qt::red));
//emit errorOccured();
}
m_pTextBrowser->append(prcs->readAllStandardOutput());
m_pTextBrowser->setTextColor(QColor(Qt::black));
}
What am I missing????
My script is located in my project folder and I copied it to the debug folder. The script is running properly and returns the output text as expected when double clicking it or using the command "./test.sh" in the shell.
UPDATE: I could figure out which error string I get (0x000000c1) and I looked it up here. It means:
ERROR_BAD_EXE_FORMAT / %1 is not a valid Win32 application
What does that mean? The script is running as described above... Why can I not start it with QProcess?
I want to check if the process is running with process id (pid).
My project is developed using QT and can be executed on both Windows and Linux.
So my code need to be able to run on both OS.
I have searched full through stackoverflow but I couldn't find expected result.
I already tried to execute cmd command -
tasklist, kill. But I still can't get result.
I think there is a way to use QProcess to get access of specified process with pid.
Here are my code I used.
#ifdef Q_OS_WIN32
QVariant variant(this->pid);
QString cmd = "tasklist /nh /fi \"pid eq " + variant.toString() + "\"";
QProcess process;
process.start(cmd);
process.waitForReadyRead();
QString result = process.readAll();
process.terminate();
if (result.indexOf(variant.toString()) >= 0)
{
return true;
}
else {
return false;
}
#else
QVariant variant(this->pid);
QString cmd = "kill -0 " + variant.toString();
QProcess process;
process.start(cmd);
process.waitForReadyRead();
QString result = process.readAll();
process.terminate();
if (result.indexOf("No") >= 0)
{
return false;
}
else {
return true;
}
#endif
I want to get help.
I am having some problem regarding QProcess using Qt. I have connected the following function with the onClick event of a push button. Basically, I want to execute another file when this button is clicked, and get its output on my Qt program. This file calculator executes, displays some output, and then waits for an input from the user.
void runPushButtonClicked() {
QProcess myprocess;
myprocess.start("./calculator")
myprocess.waitForFinished();
QString outputData= myprocess.readStandardOutput();
qDebug() << outputData;
}
In a scenario, when the calculator is such a file that only outputs some results and terminates eventually, this works perfect. But, in case when the calculator waits for some further input from the user after outputting some results, I get nothing in my outputData. In fact, waitForFinished() would time out, but even when I remove waitForFinished(), the outputData would still be empty.
I have already tried some of the solutions available here on SO, but have been unable to handle this case. Any guidance will be much appreciated.
I would suggest, that you setup a signal handler, that gets called when the subprocess produces output. E.g. you have to connect to readyReadStandardOutput.
Then you can identify, when subprocess demands input and send the input you want. This will be done in readSubProcess().
main.cpp
#include <QtCore>
#include "Foo.h"
int main(int argc, char **argv) {
QCoreApplication app(argc, argv);
Foo foo;
qDebug() << "Starting main loop";
app.exec();
}
In the following, the subprocess is started and the input checked. When the calculator program finishes, the main also exits.
Foo.h
#include <QtCore>
class Foo : public QObject {
Q_OBJECT
QProcess myprocess;
QString output;
public:
Foo() : QObject() {
myprocess.start("./calculator");
// probably nothing here yet
qDebug() << "Output right after start:"
<< myprocess.readAllStandardOutput();
// get informed when data is ready
connect(&myprocess, SIGNAL(readyReadStandardOutput()),
this, SLOT(readSubProcess()));
};
private slots:
// here we check what was received (called everytime new data is readable)
void readSubProcess(void) {
output.append(myprocess.readAllStandardOutput());
qDebug() << "complete output: " << output;
// check if input is expected
if (output.endsWith("type\n")) {
qDebug() << "ready to receive input";
// write something to subprocess, if the user has provided input,
// you need to (read it and) forward it here.
myprocess.write("hallo back!\n");
// reset outputbuffer
output = "";
}
// subprocess indicates it finished
if (output.endsWith("Bye!\n")) {
// wait for subprocess and exit
myprocess.waitForFinished();
QCoreApplication::exit();
}
};
};
For the subprocess calculator a simple script is used. You can see the where output is generated and where input is expected.
#/bin/bash
echo "Sub: Im calculator!"
# some processing here with occasionally feedback
sleep 3
echo "Sub: hallo"
sleep 1
echo "Sub: type"
# here the script blocks until some input with '\n' at the end comes via stdin
read BAR
# just echo what we got from input
echo "Sub: you typed: ${BAR}"
sleep 1
echo "Sub: Bye!"
If you do not need to do anything else in your main process (e.g. show a GUI, manage other threads/processes....), the easiest would be to just in a sleep in a loop after subprocess creation and then something like readSubprocess.
void CSerialController::sl_executeCommand(const QString s_command,QString&s_result){
QMutexLocker locker(mpo_mutex);
KT_Error t_error = ERROR_NONE;
QByteArray o_serialOutput;
QString s_serialAnswer = "";
char c_serialLetter = ' ';
// Port is already open
mpo_serial->clearBuffer(); // Flush and ReadAll
t_error = mpo_serial->sendStr(s_command); //
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
while ((t_error == ERROR_NONE) && (c_serialLetter != '\n')) // Reads Serial till newline is found
{
t_error = mpo_serial->getChar(c_serialLetter); // -> checks BytesAvailable -> if no bytes available -> waitForReadyRead(1) <- This is in a Loop while given time is over(Timeouttime)
o_serialOutput.append(c_serialLetter);
}
}
NO_SUCCESS(t_error)
{
Q_EMIT sg_throwError(t_error);
}
SUCCESS(t_error)
{
s_serialAnswer = o_serialOutput;
s_serialAnswer.remove("\r\n");
}
s_result = s_serialAnswer; }
Im working with C++ and Qt 5.5 and i cant get the serial connection to work correctly. Im using signals to connect a QPushButton with a slot in the CSerialController class which calls this function in the same class. I tried this function with a endless while-loop and it works correctly all the time. Its just not working when i use the buttons. First time i use a button it works correctly but the second time i press a button which calls this slot, the serialport only sometimes returns a value. (Writing works just not reading) I even tried changing the Thread of this class but that didnt help aswell. If you want i can post the sendStr and getChar functions aswell but like i said they work without a problem(allready used in a lot of projects)
UPDATE: I tried using the Windows API for the serial connection = problem is gone. Seems like a problem with QSerialPort usage on an old CPU (I7-870)
Under Qt 4.7.1, OS X 10.6.8
(have to use this -- later versions
of Qt and/or OS X introduce severe
incompatibilities for my users)
The following works. Sometimes. Then sometimes not.
When it doesn't work, it returns "Unknown Error"
hst is good in all cases, qDebug returns same correct
data for hst every time.
The idea is, use ->get to pull a CGI URL; the CGI
returns some data, which I can ignore in this case.
Then I'm done.
hst is a well formed URL,
http://yadda.com/cgi-bin/whatever.py
QString hst;
QNetworkReply *qnr;
QNetworkAccessManager *qqnap = NULL;
qqnap = new(std::nothrow) QNetworkAccessManager(tmw);
if (qqnap != NULL)
{
hst = loaduphst(); // get qstring to send
qnr = qqnap->get(QNetworkRequest(QUrl(hst))); // report in and fetch update info
if (qnr->waitForReadyRead(3000) == FALSE)
{
qDebug() << "waitForReadyRead() returned FALSE -- error or timeout:" << qnr->errorString();
}
}
else
{
qDebug() << "qqnap is NULL";
}
yadda.com is up; the target script is dead simple
and works fine from browser or cmd line every time.
This is running within the context of
MainWindow::closeEvent(QCloseEvent *ce)
before I emit ce->accept() GUI is still up,
etc.
Hints? Tips? Abuse? Thanks!
waitForReadyRead is not implemented in QNetworkReply. The default implementation does nothing:
bool QIODevice::waitForReadyRead(int msecs)
{
Q_UNUSED(msecs);
return false;
}
Use the readyRead signal to find out when there is data available to be read.
More-or-less synchronous use of async networking is very problematic in the context of the main GUI loop. Signals that don't appear (finished OR readyRead), URLs that sometimes send and sometimes don't... and of course, as the kind person above pointed out, unimplemented functions. Zebras!
What we can do, though, is fire up an event loop and a timer on our own, and this will in a more-or-less friendly way act synchronous.
Perhaps some poor soul will need to poke a website CGI as I do; here's the code. It works. At least under Qt 4.7.1 it does!
So anyway, here it is:
QNetworkReply *qnr;
QNetworkAccessManager *qqnap;
QNetworkRequest qnwr;
QEventLoop w;
QTimer arf;
if ((qqnap = new(std::nothrow) QNetworkAccessManager(this)))
{
qnwr.setUrl(myUrl()); // Build web goodness
qnwr.setRawHeader("User-Agent", myUserAgent());
arf.setSingleShot(true);
if (connect(&arf, SIGNAL(timeout()), // timer firing blows...
&w, SLOT(quit()) // ...out event loop
) == FALSE)
{ return(BAD_CONNECT_TOUT); }
if (connect(qqnap, SIGNAL(finished(QNetworkReply*)), // notify we finished...
this, SLOT(qqnapReplyQ(QNetworkReply*)) // ...cuz I need to know
) == FALSE)
{ return(BAD_CONNECT_FINISHED_NOTIFY); }
if (connect(qqnap, SIGNAL(finished(QNetworkReply*)), // finishing blows out...
&w, SLOT(quit()) // ...event loop
) == FALSE)
{ return(BAD_CONNECT_FINISHED_ELOOP); }
if ((qnr = qqnap->get(qnwr))) // Go if qnr is good
{
arf.start(6000); // timeout in ms // Watchdog timer on
w.exec(); // handle all that
if (arf.isActive()) { arf.stop(); } // kill timer if needed
}
else { return(BAD_WWWGET); } // FAIL
}
else
{
return(BAD_NWAM); // FAIL
}
return(ZEN_NETWORKING);