QProcess does not emit finished signal - qt

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().

Related

Delays in UI display in QT Multithreading

I have a multi-threaded application. My application has 2 dialogs: Main Dialog (Dialog1) and Transaction Dialog (Dialog2). When the application runs, Dialog1 will start a QThread to download a big file. While downloading, Dialog2 will be displayed. Dialog2 will display the status of the download. Note that the download will still continue even if Dialog2 is displayed. When Dialog2 is displayed, a poller thread will be started. This thread will process the transaction when a card is detected.
Problem:
When the card is detected, Dialog2 should update the UI (I used signal and slot for this). However, updating the UI is delayed. or it takes several seconds to display the correct message to the UI. This only happens when download is ongoing.
Below is my code:
Dialog1:
void Dialog1::startDownlaod()
{
DownloadClass *downloadClass ;
Dialog2 *dialog2 = new Dialog2 (this);
cout << "[Dialog2] from main thread: " << QThread::currentThreadId() << endl;
downloadClass = new DownloadClass ();
pAppDownloadThread_ = nullptr;
pAppDownloadThread_ = new QThread();
downloadClass->moveToThread(pAppDownloadThread_);
connect(pAppDownloadThread_, SIGNAL(started()), downloadClass , SLOT(processDownloadRequest()));
connect(downloadClass , SIGNAL(finished()), pAppDownloadThread_, SLOT(quit()));
connect(downloadClass , SIGNAL(finished()), downloadClass , SLOT(deleteLater()));
connect(pAppDownloadThread_, SIGNAL(finished()), pAppDownloadThread_, SLOT(deleteLater()));
connect(downloadClass , SIGNAL(updateDownloadStatus()), dialog2, SLOT(updateDownloadStatus()));
pAppDownloadThread_->start();
dialog2->setWindowFlags(Qt::Window | Qt::FramelessWindowHint);
dialog2->exec();
}
Downloader class:
class DownloadClass : public QObject
{
Q_OBJECT
public slots:
void processDownloadRequest();
signals:
void finished();
void onUpdateDownloadStatus();
}
Dialog2:
// this is the slot that will update downlaod status
void Dialog2::updateDownloadStatus()
{
ui->labelStatus.setText("some text here");
}
// this is method to start the poller thread
void Dialog2::startPollingThread()
{
pollingThread_ = new QThread;
Poller::instance()->moveToThread(pollingThread_); // singleton
connect(pollingThread_, SIGNAL(started()), Poller::instance(), SLOT(poll()));
connect(Notifier::getInstance(), SIGNAL(displayMessage(QString)), this, SLOT(displayMessage(QString)));
connect(Poller::instance(), SIGNAL(finished()), pPollingThread_, SLOT(quit()));
connect(pPollingThread_, SIGNAL(finished()), Poller::instance(), SLOT(deleteLater()));
connect(pPollingThread_, SIGNAL(finished()), pPollingThread_, SLOT(deleteLater()));
cout << "[Dialog2] from main thread: " << QThread::currentThreadId() << endl;
pollingThread_->start();
}
Poller class:
class Poller : public QObject
{
Q_OBJECT
public slots:
void poll();
signals:
void finished();
void displayMessage(QString message);
}
// poll() method
void Poller::poll()
{
if(isCardDetected)
emit displayMessage("Detected"); // this will be sent to Dialog2 to display the message in the label
else
emit displayMessage("No card detected");
}
Here is the output when I print the threadID:
[Dialog2] from main thread: 0xb6fed000
[Dialog1] from main thread: 0xb6fed000
[Poller] from poller thread: 0xb0aff400
[DownloadClass] from downloader class: 0xb02ff400
Notice that threadID of Dialog1 and Dialog2 are the same.

How to communicate Qt applications two-way

I want to create two-way communicate beetwen my Qt Apps. I want to use QProcess to do this. I'm calling sucesfully child app from root app and sending test data without any erro, but I can't recive any data in child app. I'll be gratefull for any help. I'm using Qt 4.7.1. Below my test code:
Root app:
InterProcess::InterProcess(QObject *parent) : QProcess(parent)
{
process = new QProcess(this);
process->start(myChildApp);
process->waitForStarted();
process->setCurrentWriteChannel(QProcess::StandardOutput);
process->write("Test");
connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()) );
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()) );
QByteArray InterProcess::read()
{
QByteArray readBuffer = process->readAllStandardOutput();
return readBuffer;
}
void InterProcess::error( QProcess::ProcessError error )
{
qDebug() << "Error!";
qDebug() << error;
}
void InterProcess::readyReadStandardError()
{
qDebug() << "Ready to read error.";
qDebug() << process->readAllStandardError();
}
void InterProcess::readyReadStandardOutput()
{
qDebug() << "The output:";
QByteArray readBuffer = process->readAllStandardOutput();
qDebug() << readBuffer;
}
Child app:
InterProcess::InterProcess(QObject *parent) : QProcess(parent)
{
process = new QProcess();
process->setCurrentReadChannel(QProcess::StandardOutput);
connect( process, SIGNAL(readyRead()), this, SLOT(readyReadStandardOutput()));
connect( process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(error(QProcess::ProcessError)) );
connect( process, SIGNAL(readyReadStandardError()), this, SLOT(readyReadStandardError()) );
connect( process, SIGNAL(readyReadStandardOutput()), this, SLOT(readyReadStandardOutput()) );
process->waitForReadyRead(5000);
}
void InterProcess::readyReadStandardError()
{
qDebug() << "Ready to read error.";
qDebug() << process->readAllStandardError();
setText("REady error");
}
void InterProcess::readyReadStandardOutput()
{
setMessage("2");
qDebug() << "The output:";
QByteArray readBuffer = process->readAllStandardOutput();
qDebug() << readBuffer;
}
void InterProcess::error( QProcess::ProcessError error )
{
qDebug() << "Error!";
qDebug() << error;
setText(QString(error));
}
It's very hard to explain in one answer all mistakes, so just look at code and ask if you still got problems.
Here is example of using QProcess as IPC.
This is your main process, that creates additional process and connects to its signals
MyApplicaiton.h
#ifndef MYAPPLICATION_H
#define MYAPPLICATION_H
#include <QApplication>
class InterProcess;
class MyApplication : public QApplication {
Q_OBJECT
public:
MyApplication(int &argc, char **argv);
signals:
void mainApplicationSignal();
private slots:
void onInterProcessSignal();
private:
InterProcess *mProcess;
};
#endif // MYAPPLICATION_H
MyApplicaiton.cpp
#include "MyApplication.h"
#include "InterProcess.h"
MyApplication::MyApplication(int &argc, char **argv) : QApplication(argc, argv) {
mProcess = new InterProcess(this);
connect(mProcess, SIGNAL(interProcessSignal()),
this, SLOT(onInterProcessSignal()));
mProcess->start();
}
void MyApplication::onInterProcessSignal() {}
This is example implementation of your interProcess class:
InterProcess.h
class InterProcess : public QProcess {
Q_OBJECT
public:
explicit InterProcess(QObject *parent = nullptr);
signals:
void interProcessSignal();
private slots:
void onMainApplicationSignal();
};
InterProcess.cpp
#include "InterProcess.h"
#include "MyApplication.h"
InterProcess::InterProcess(QObject *parent) : QProcess(parent) {
if(parent) {
auto myApp = qobject_cast<MyApplication *>(parent);
if(myApp) {
connect(myApp, SIGNAL(mainApplicationSignal()),
this, SLOT(onMainApplicationSignal()));
}
}
}
void InterProcess::onMainApplicationSignal() {}
Locally, using UDP is very convenient and efficient
void Server::initSocket() {
udpSocket = new QUdpSocket(this);
udpSocket->bind(QHostAddress::LocalHost, 7755);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readPendingDatagrams()));}
void Server::readPendingDatagrams(){
while (udpSocket->hasPendingDatagrams()) {
QByteArray datagram;
datagram.resize(udpSocket->pendingDatagramSize());
QHostAddress sender;
quint16 senderPort;
udpSocket->readDatagram(datagram.data(), datagram.size(),
&sender, &senderPort);
processTheDatagram(datagram);
}}

QT QTcpServer::incomingConnection(qintptr handle) not firing?

I'm trying to create a multithreaded server using Qt for the first time. Normally one would use the socket pointer returned by the QTcpServer::nextPendingConnection() with the socket handle already baked in - but since I'm interfacing with the connecting client on a separate thread, I need to create the socket separately using the qintptr handle from QTcpServer::incomingConnection(qintptr handle). After a very dreary, error-packed debugging session I managed to track down the problem to the QTcpServer::incomingConnection() never being fired?
Has anyone had a similar problem - has something changed over recent versions Qt?
These are the ones I've tried:
QTcpServer::incomingConnection(qintptr handle)
QTcpServer::incomingConnection(qintptr socketDescriptor)
QTcpServer::incomingConnection(int handle)
EDIT:
Creating instance of server:
TestServer *myServer = new TestServer();
myServer->initializeServer(1234);
Which calls:
void TestServer::initializeServer(quint16 port)
{
mainServer = new QTcpServer(this);
mainServer->listen(QHostAddress::Any, port);
qDebug() << "Listening for connections on port: " << port;
}
Server is now listening. When a client connects incomingConnection(qintptr handle) is supposed to be called:
void TestServer::incomingConnection(qintptr socketDescriptor){
TestClient *client = new TestClient(this);
client->setSocket(socketDescriptor);
}
Which calls:
void TestClient::setSocket(quint16 socketDescr)
{
socket = new QTcpSocket(this);
socket->setSocketDescriptor(socketDescr);
connect(socket, SIGNAL(connected()),this,SLOT(connected()));
connect(socket, SIGNAL(disconnected()),this,SLOT(disconnected()));
connect(socket, SIGNAL(readyRead()),this,SLOT(readyRead()));
}
Called on connect() signal:
void TestClient::connected()
{
qDebug() << "Client connected..."; // This debug never appears in the console, since QTcpServer::incomingConnection isn't being fired.
}
You have some errors at your code:
At TestServer your QTcpServer probably aggregated, but you need to inherit it. At this case you try to override incomingConnection() method, but you haven't base class and you just create new incomingConnection(), not override.
You get qintptr descriptor variable from incomingConnection(), but set quint16 type at setSocket() method.
You probably mix client of server and client of your part, which just get incoming connection and handling socket data.
I write some little example below for your understanding tcp client-server communication.
Server part
Main part is server themselves:
#include <QTcpServer>
class TestServer: public QTcpServer
{
public:
TestServer(QObject *parent = 0);
void incomingConnection(qintptr handle) Q_DECL_OVERRIDE;
};
Just look: I don't aggragate QTcpServer, but inherited it. At this case you can override incomingConnection() method correctly.
At constructor we just start server for listening using listen() method:
TestServer::TestServer(QObject *parent):
QTcpServer(parent)
{
if (this->listen(QHostAddress::Any, 2323)) {
qDebug() << "Server start at port: " << this->serverPort();
} else {
qDebug() << "Start failure";
}
}
Then time for overriding incomingConnection():
void TestServer::incomingConnection(qintptr handle)
{
qDebug() << Q_FUNC_INFO << " new connection";
SocketThread *socket = new SocketThread(handle);
connect(socket, SIGNAL(finished()), socket, SLOT(deleteLater()));
socket->start();
}
I create SocketThread object which handle incoming data:
#include <QThread>
#include <QObject>
class QTcpSocket;
class SocketThread: public QThread
{
Q_OBJECT
public:
SocketThread(qintptr descriptor, QObject *parent = 0);
~SocketThread();
protected:
void run() Q_DECL_OVERRIDE;
private slots:
void onConnected();
void onReadyRead();
void onDisconnected();
private:
QTcpSocket *m_socket;
qintptr m_descriptor;
};
We inherits from QThread for making our server multithreading, so we have to override run() method:
SocketThread::SocketThread(qintptr descriptor, QObject *parent)
: QThread(parent), m_descriptor(descriptor)
{
}
void SocketThread::run()
{
qDebug() << Q_FUNC_INFO;
m_socket = new QTcpSocket;
m_socket->setSocketDescriptor(m_descriptor);
connect(m_socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()), Qt::DirectConnection);
connect(m_socket, SIGNAL(disconnected()), this, SLOT(onDisconnected()), Qt::DirectConnection);
exec();
}
This way we initialize our QTcpSocket, set socket descriptor, connect it with readyRead() and disconnected() signals and start event loop.
void SocketThread::onReadyRead()
{
QDataStream in(m_socket);
in.setVersion(QDataStream::Qt_5_5);
QString message;
in >> message;
qDebug() << message;
m_socket->disconnectFromHost();
}
void SocketThread::onDisconnected()
{
m_socket->close();
// Exit event loop
quit();
}
At onReadyRead() just read some QString from client, write it to console and disconnect from host. At onDisconnected() we close socket connection and exit event loop.
Client part
It is just example and bad-smells style, but i create connection to the server at MainWindow class on QPushButton::clicked signal:
void MainWindow::on_pushButton_clicked()
{
QTcpSocket *client = new QTcpSocket;
connect(client, SIGNAL(connected()), this, SLOT(connected()));
connect(client, SIGNAL(disconnected()), client, SLOT(deleteLater()));
client->connectToHost(QHostAddress::LocalHost, 2323);
client->waitForConnected();
if (client->state() != QAbstractSocket::ConnectedState ) {
qDebug() << Q_FUNC_INFO << " can't connect to host";
delete client;
return;
}
QByteArray block;
QDataStream out(&block, QIODevice::WriteOnly);
out.setVersion(QDataStream::Qt_5_5);
out << QString("Hello");
out.device()->seek(0);
client->write(block);
}
void MainWindow::connected()
{
qDebug() << Q_FUNC_INFO << " client connected";
}
I create new QTcpSocket, connect it to the signals and try to connect to the host(in my case it is localhost). Wait for connected and check socket status. If all is right I write to socket QString - just example.
It is one of possible ways to organized multithreading client-server architecture, i hope it will be helpfull for you and you find yours bugs.

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.

Qt Mainwindow menu signals

I've "Core" object that handles QMainWindow.
Core.h code
class Core : public QObject
{
Q_OBJECT
public:
explicit Core(QObject *parent = 0);
~Core();
void appInit();
int getAuth();
public slots:
void appExit();
private slots:
void appMenuTriggered(QAction *action);
private:
void preInit();
MainWindow *mwnd;
};
Core.cpp code
Core::Core(QObject *parent) : QObject(parent)
{
qDebug() << "Core::Constructor called";
preInit();
}
Core::~Core()
{
delete mwnd;
qDebug() << "Core::Destructor called";
}
int Core::getAuth()
{
LoginDialog *login = new LoginDialog();
int r = login->exec();
delete login;
return r;
}
void Core::appExit() // connected to qapplication aboutToQuit
{
qDebug() << "Core::appExit called";
}
void Core::preInit() // called after getAuth im main.cpp
{
qDebug() << "Core::preInit called";
}
void Core::appMenuTriggered( QAction *action )
{
qDebug() << "action triggered";
}
void Core::appInit()
{
mwnd = new MainWindow();
mwnd->show();
qDebug() << "Core::appInit called";
}
I'm trying to connect mainwindow menubar signal to core slot like this:
connect(mwnd->menuBar(), SIGNAL(triggered()), this, SLOT(appMenuTriggered()));
But it doesn't work. Im new to c++ and Qt. How to connect this?
Or maybe there is better way to handle mainwindow actions to other programm parts.
UPD
Problem solved. Forget to include QMenuBar
You have to give the full function spec in the SIGNAL and SLOT parameters (but without the argument names). Like this:
connect(mwnd->menuBar(),
SIGNAL(triggered(QAction*)),
this,
SLOT(appMenuTriggered(QAction*)));
If you debug such code in Qt Creator, the connect function will write diagnostic error messages to the Application Output pane when it doesn't find a signal or a slot. I suggest that you find these error messages before you fix your problem, so that you know where to look in future. It's very easy to get signals and slots wrong!

Resources