Connect Qprocess signal to slot - qt

In the function below, how do I connect the process signal errorOccured to a slot? My goal is to qDebug the errorOccurred property when process.startDetached() runs.
void MainWindow::on_pushButton_clicked()
{
qDebug() << "Start Detached";
QProcess process;
connect(process, SIGNAL(errorOccurred()), this,
SLOT(onSdetacherror()));
process.setProgram("C:/windows/system32/cmd.exe");
process.setArguments({"/k"});
process.startDetached();
}
The proper connect syntax is eluding me ...

Related

QProcess does not emit finished signal

I try to read out the output of a command executed in QProcess. I don't get the connection working between QProcess's finished signal and a finished handler.
I tried several different ways of connecting to QProcess finished signal but no luck so far. I know that the process executes because it prints the output in the GUI's console and that the process finishes because it passes the waitForFinished method from sequential API.
Why does my code not hit onFinish or onFinishNoPams?
header:
class Test : public QObject
{
Q_OBJECT
public:
Test(QObject *parent = 0);
Q_INVOKABLE void read();
public slots:
void onFinish(int exitCode , QProcess::ExitStatus exitStatus);
void onFinishNoPams();
private:
QProcess *m_process;
};
cpp:
Test::Test(QObject *parent)
: QObject(parent)
{}
void Test::read(){
m_process=new QProcess(this);
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinishNoPams()));
connect(m_process, SIGNAL(finished(int,QProcess::ExitStatus)), this, SLOT(onFinish(int,QProcess::ExitStatus)));
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
[=](int exitCode, QProcess::ExitStatus exitStatus){
qDebug() << "not reached";
});
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this,&Test::onFinish);
QString program = "lsusb";
QStringList arguments;
m_process->execute(program,arguments);
m_process->waitForFinished();
qDebug() << "reached";
return;
}
void Test::onFinish(int exitCode , QProcess::ExitStatus exitStatus){
qDebug() << "not reached";
}
void Test::onFinishNoPams(){
qDebug() << "not reached";
QByteArray out=m_process->readAllStandardOutput();
}
qml:
import test 1.0
Window {
Test{
id:test
Component.onCompleted: test.read()
}
}
QProcess::execute() is a static method that starts the external process and waits for its completion in a blocking way. It has nothing to do with your m_process variable. What you want to use is QProcess::start().

QProcess ReadAllStandardError()

I need to connect a QProcess to an error handler, but I'm unsure how to pass the error string to the slot. What's below compiles, but doesn't work.
QString MainWindow::RunProcess(QString cstring)
{
QProcess *process = new QProcess(this);
connect(process,SIGNAL(readyReadStandardError()),this,SLOT( adberror(process::ReadAllStandardError() ) ))
process->start(cstring);
}
void MainWindow::adberror(QString errtxt)
{
qDebug() << "error handler";
qDebug() << errtxt;
}
I can induce a a process error, but adberror() never triggers.
When run, in the Application Output pane I see:
QObject::connect: No such slot MainWindow::adberror(process::ReadAllStandardError() )
QObject::connect: (receiver name: 'MainWindow')
edit: this is Qt 5.6. I did a new qmake/clean.
you have two options
1- wait before reading the output
QString MainWindow::RunProcess(QString cstring)
{
QProcess process;
process.start(cstring);
process.waitForFinished();
QString str = process.readAllStandardOutput();
}
2- make you process a member variable and remove your 1st argument from adberror. So,
in RunProcess
connect(process,SIGNAL(readyReadStandardError()),this,SLOT(adberror()))
then in adberror
QString str = process->readAllStandardOutput();
note that in your code you have a problem since your signal and slot args don't to match .. Also, ReadAllStandardError is not going to be ready anyways !
Edit: more code for the 2nd solution
mainwindow.h
class MainWindow
{
private://methods
void adberror();
private://attributes
QProcess* process;
};
mainwindow.cpp
QString MainWindow::RunProcess(QString cstring)
{
process = new QProcess(this);
connect(process,SIGNAL(readyReadStandardError()),this,SLOT(adberror()));
connect(process, SIGNAL(finished(int)), process, SLOT(deleteLater()));
process->start(cstring);
}
void MainWindow::adberror()
{
QString str = process->readAllStandardOutput();
qDebug() << str;
}
To process the readyReadStandardError() signal you should define the slot as:
private slots:
void adberror();
and use it:
connect(process,SIGNAL(readyReadStandardError()),this,SLOT( adberror() ));
i.e. with no arguments. Keep child process as a field of your MainWindow class to read data when it will be available.

Can't write to Qt5 textEdit box with ui->control->setText(message)

I am trying to put the data passed to a mainwindow.cpp function on the screen with the typical ui->control->setText(message) without success. The same line works if it is in a timer loop or a button function but not from display_that_data function
"MainWindow::display_that_data()" is called from myudp.cpp with the following lines
MainWindow show_tlm;
show_tlm.display_that_data(data_source, buf_copy);
mainwindow.cpp (updated to include emitting a signal for a SIGNAL/SLOT connection)
The SIGNAL/SLOT connection is set up in the constructor with the following line
connect (this, SIGNAL (showdata_signal()), this, SLOT(showdata_slot()));
void MainWindow::display_that_data(QByteArray data_source, QByteArray tlmBuf){
QString msg ;
msg = " in display_that_data";
qDebug() << msg ;
ui->tlm_vals->setText(msg);
//generate a signal which will trigger showdata_slot
emit showdata_signal();
msg = " in display_that_data after emit showdata_signal()";
qDebug() << msg ;
}
void MainWindow::showdata_slot() {
QString msg = "showdata_slot called";
qDebug() << msg ;
ui->tlm_vals->setText(msg);
}
Runtime debug messages show that code is making it to the showdata_slot but it is still not writing to the ui->tlm_vals
" in display_that_data"
"showdata_slot called"
" in display_that_data after emit showdata_signal()"
but.... neither one of the ui->tlm_vals->setText(msg) lines are putting text on the ui
"MainWindow::realtimeDataSlot()" is called by at timer timout signal as follows:
void MainWindow::setupRealtimeDataDemo(QCustomPlot *customPlot) {
// setup a timer that repeatedly calls MainWindow::realtimeDataSlot
connect(&dataTimer, SIGNAL(timeout()), this, SLOT(realtimeDataSlot()));
dataTimer.start(1000);
}
void MainWindow::realtimeDataSlot(){
QString temp = QString("%1").arg(epochTime, 10, 10, QChar('0'));
ui->tlm_vals->setText(temp);
}
And this works perfectly (of course I have to disable it to see if showdata_slot is writing to the ui)
I thought the problem was a needed SIGNAL and SLOT connection to trigger the write to the ui but generating a SIGNAL/SLOT connection (which debug shows as working) still does not write to the ui from the slot function.
For completeness mainwindow.h contains the following
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void setupRealtimeDataDemo(QCustomPlot *customPlot);
void display_that_data (QByteArray data_source, QByteArray tlmBuf);
private slots:
void realtimeDataSlot();
void showdata_slot();
private:
Ui::MainWindow *ui;
QTimer dataTimer;
What am I missing/doing wrong?
Somewhere deeply embedded in Qt there is a difference between gui mouse click generated event and code generated event and this somehow caues Qt behavior to vary with the same lines of code. I will repost a more more "root level" question on this topic.

Read output of multiple write in QProcess one by one

Can anyone help me read the output of qprocess after write and loop until all task is done?
I have this code
wifi->write("scan\n");
wifi->closeWriteChannel();
wifi->waitForBytesWritten(100);
wifi->waitForReadyRead(100);
wifi->waitForFinished(100);
qDebug() << "read output" << wifi->readAllStandardOutput();
wifi->write("scan\n");
wifi->closeWriteChannel();
wifi->waitForBytesWritten(100);
wifi->waitForReadyRead(100);
wifi->waitForFinished(100);
qDebug() << "read output" << wifi->readAllStandardOutput();
the expected output must be
"OK"
"scan results"
but the ouput is
"OK"
""
thanks.
Your multiple waits are not useful for anything. All you care about is when the process finishes, so have a single waitForFinished call with a much longer timeout (those scans don't happen in ~100ms, a few seconds is a good minimum).
You should not be using the blocking waitForXxx methods. They trip up everyone and are a source of unending grief. Forget that they exist. Use process's signals to react to events as they happen.
Qt 5 + C++11
This is the way forward. This is why you should insist on using a modern development environment, if you can. It's less typing and easier to understand.
void MyObject::startWifi() {
auto process = new QProcess(this);
process->start("program", QStringList() << "argument");
connect(process, &QProcess::started, [process]{
process->write("scan\n");
process->closeWriteChannel();
});
connect(process, &QProcess::finished, [process]{
qDebug() << process->readAllStandardOutput();
process->deleteLater();
});
}
Qt 4
class MyObject : public QObject {
Q_OBJECT
QProcess m_wifi;
Q_SLOT void onStarted() {
m_wifi.write("scan\n");
m_wifi.closeWriteChannel();
}
Q_SLOT void onFinished() {
qDebug() << m_wifi.readAllStandardOutput();
}
public:
MyObject(QObject * parent = 0) : QObject(parent) {
connect(&m_wifi, SIGNAL(started()), SLOT(onStarted()));
connect(&m_wifi, SIGNAL(finished(int,QProcess::ExitStatus)),
SLOT(onFinished()));
}
Q_SLOT void start() {
m_wifi.start("program", QStringList() << "argument");
}
};
Then invoke the start method/slot on an instance of this object. That's all.

Launch and write to terminal in Qt

I am coding in linux using Qt. I understand that with popen or QProcess I can launch terminal from my program, but how do I write into to it? I google around people are suggesting fork() and pipe().
My purpose is to do an ICMP ping with the terminal, and stop when ping successfully. I made it with popen, but I couldn't stop the ping process thus my program won't run.
You don't write anything to terminal because there's no terminal. You pass name of a program to run and its arguments as arguments of the QProcess::start method. If you only need to know if ping was successful or not it's enough to check the exit code of the process which you started earlier using QProcess::start; you don't have to read its output.
from ping(8) - Linux man page
If ping does not receive any reply
packets at all it will exit with code
1. If a packet count and deadline are both specified, and fewer than count
packets are received by the time the
deadline has arrived, it will also
exit with code 1. On other error it
exits with code 2. Otherwise it exits
with code 0. This makes it possible to
use the exit code to see if a host is
alive or not.
By default ping under Linux runs until you stop it. You can however use -c X option to send only X packets and -w X option to set timeout of the whole process to X seconds. This way you can limit the time ping will take to run.
Below is a working example of using QProcess to run ping program on Windows. For Linux you have to change ping options accordingly (for example -n to -c). In the example, ping is run up to X times, where X is the option you give to Ping class constructor. As soon as any of these executions returns with exit code 0 (meaning success) the result signal is emitted with value true. If no execution is successful the result signal is emitted with value false.
#include <QCoreApplication>
#include <QObject>
#include <QProcess>
#include <QTimer>
#include <QDebug>
class Ping : public QObject {
Q_OBJECT
public:
Ping(int count)
: QObject(), count_(count) {
arguments_ << "-n" << "1" << "example.com";
QObject::connect(&process_,
SIGNAL(finished(int, QProcess::ExitStatus)),
this,
SLOT(handlePingOutput(int, QProcess::ExitStatus)));
};
public slots:
void handlePingOutput(int exitCode, QProcess::ExitStatus exitStatus) {
qDebug() << exitCode;
qDebug() << exitStatus;
qDebug() << static_cast<QIODevice*>(QObject::sender())->readAll();
if (!exitCode) {
emit result(true);
} else {
if (--count_) {
QTimer::singleShot(1000, this, SLOT(ping()));
} else {
emit result(false);
}
}
}
void ping() {
process_.start("ping", arguments_);
}
signals:
void result(bool res);
private:
QProcess process_;
QStringList arguments_;
int count_;
};
class Test : public QObject {
Q_OBJECT
public:
Test() : QObject() {};
public slots:
void handle(bool result) {
if (result)
qDebug() << "Ping suceeded";
else
qDebug() << "Ping failed";
}
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Test test;
Ping ping(3);
QObject::connect(&ping,
SIGNAL(result(bool)),
&test,
SLOT(handle(bool)));
ping.ping();
app.exec();
}
#include "main.moc"

Resources