I am working with a QProcess and have connected QProcess's signal readyReadStandardOutput().
That process normally spits out data to the console regularly, but the readyReadStandardOutput() seems to batch results and only emit every half a minute or so (with all accumulated data).
I want to access the "live feed" of the QProcess so I thought maybe QProcess's superclass QIODevice has some other signals.
Other solutions instead of using bytesWritten are also welcome
Now I'm trying to connect bytesWritten, but it doesn't let me.
Code:
void MainWindow::on_Program_clicked() {
program= new QProcess(this);
QString file = "../folder/program/program.exe";
QString directory = "../folder/program/";
//qint64 pid;
program->setWorkingDirectory(directory);
program->start(file, {""});
program->waitForStarted();
connect(program, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
//ERROR: "QObject::connect: No such signal QProcess::bytesWritten() in ..\---\mainwindow.cpp:45
connect(program, SIGNAL(bytesWritten()), this, SLOT(myBytesWritten()));
}
void MainWindow::myBytesWritten() {
QProcess *program = dynamic_cast<QProcess *>(sender());
QByteArray outData = program->readAll();
qDebug() << "DEBUG: " + outData;
}
//Works, but only emits a signal every so often, and not every time a new line is written to the console as when I launch the exe normally
void MainWindow::readOutput(){
QProcess *program = dynamic_cast<QProcess *>(sender());
QByteArray outData = program->readAll();
qDebug() << "DEBUG: " + outData;
}
If you want to use the old, deprecated way of connecting signals to slots, you need to also include the parameter list:
connect(program, SIGNAL(bytesWritten(int)), this, SLOT(myBytesWritten()));
Or you can just use the modern, compile-time Qt5 way:
connect(program, &QProcess::bytesWritten, this, &MainWindow::myBytesWritten);
Also note that bytesWritten fires when a write command from YOUR end has succeeded. You don't seem to be sending any input so this will never fire.
Related
I'm trying to write an app for testing ST board via serial port and I'm currently facing the following issue. (The code below is just a simplification of a problem.)
Widget::Widget(QWidget *parent)
: QWidget(parent)
, m_button(new QPushButton(this))
, m_timer(new QTimer(this))
{
m_timer->setSingleShot(true);
connect(m_button, &QPushButton::released, this, &Widget::RunTest);
connect(m_timer, &QTimer::timeout, this, &Widget::OnTimeout);
}
void Widget::RunTest()
{
qDebug() << "Start test";
m_timer->start(1000);
while (m_timeout != true);
qDebug() << "Start end";
}
void Widget::OnTimeout()
{
qDebug() << "Timeout";
m_timeout = true;
}
I want to have a seprate class for gathering and running tests. The tests are triggered by clicking on a button. Some tests will have to send data via serial port and wait for the reply. I would like to be able to implement a timeout feature (if board doesn't reply then finish test with failure). However I the app is waiting for the m_timeout flag indefinitely. So my question is: Is there any signal/slot mechanism similar to interrupt preemption? If no how sush problems are solved in Qt? Shall I create seprate QTimer object and run it in separate thread?
I tried to create simple server like in link 1.
Youtube tutorial to create multithreaded server
void Test_Server::incomingConnection(int socketDescriptor_)
{
qDebug() << socketDescriptor_ << "connecting...";
Test_Thread *thread_ = new Test_Thread(number_,socketDescriptor_,this);
connect(thread_,SIGNAL(finished()),thread_,SLOT(deleteLater()));
thread_->start();
number_++;
}
////
void Test_Thread::run()
{
qDebug() << this->Socket_Descriptor_ << "starting thread";
socket = new QTcpSocket();
if(!socket->setSocketDescriptor(Socket_Descriptor_))
{
qDebug() << "ERROR";
}
connect(socket,SIGNAL(readyRead()),this,SLOT(Ready_read_()),Qt::DirectConnection);
connect(socket,SIGNAL(disconnected()),this,SLOT(disconnected_()),Qt::DirectConnection);
qDebug() << this->Socket_Descriptor_ << "Client connected";
QByteArray name = QByteArray::number(number_);
server_->Socket_map_.insert(name,this);
server_->show_all_connected_sockets_();
exec();
}
My goal is to connect two clients to server(i use telnet), write from Client 1 to server something, and server should pass data to Client 2.
To do that I've made QMap to storage pointers to MyThreads. When data is received from Client 1, I'm calling method:
void Test_Server::write_to_client_(int number, QByteArray data)
{
QByteArray name = QByteArray::number(number);
Test_Thread *pointer;
pointer = client_socket_(name);
connect(this,SIGNAL(send_data_(QByteArray)),pointer,SLOT(write_data_(QByteArray)));
emit send_data_(data);
disconnect(this,SIGNAL(send_data_(QByteArray)),pointer,SLOT(write_data_(QByteArray)));
qDebug() << "void Test_Server::write_to_client_(int number, QByteArray data): data sent";
}
////
void Test_Thread::write_data_(QByteArray data) const
{
socket->write(data);
socket->waitForBytesWritten();
}
Generally passing information works, I write in Client 1 some data, and Client 2 shows it, however I'm geting:
TQObject: Cannot create children for a parent that is in a different
thread.
Parent Test_Thread is QNativeSocketEngine(Pointer 1), parent's thread is >(Pointer 2), current thread is (Pointer 3);
QsocketNotifier: Socket notifiers cannot be enabled or disabled from another thread.
My question is: how to correctly pass data from client 1, to server, and then to client 2? I've done reasearch and problem lies in proper use of Signals and Slots but I cannot find out how to do it in proper way.
Test_Thread::write_data is not running on the same thread where the socket was created, that is Test_Thread::run(). In the QThread class, only what runs on the run method runs on a separate thread.
I finally solved issue. To do that i followed similar issue solution described here: PROBLEM & SOLUTION
I've resigned to use class MyThread, instead created class Worker and moved it to thread like here below:
void Test_Server::incomingConnection(int socketDescriptor_)
{
qDebug() << "void Test_Server::incomingConnection current thread: " << QThread::currentThread();
qDebug() << socketDescriptor_ << "connecting...";
Socket_map_.insert(number_,QByteArray::number(socketDescriptor_));
QThread *thread_= new QThread;
qDebug() << "void Test_Server::incomingConnection new thread_: " << thread_->thread();
Test_Worker *worker = new Test_Worker(socketDescriptor_);
worker->moveToThread(thread_);
connect(thread_,SIGNAL(started()),worker,SLOT(create_socket_()));
connect(this,SIGNAL(pass_socket_descriptor_(int)),worker,SLOT(set_socket_descriptor_(int)));
connect(worker,SIGNAL(finished()),thread_,SLOT(quit()));
connect(worker,SIGNAL(finished()),worker,SLOT(deleteLater()));
connect(thread_,SIGNAL(finished()),thread_,SLOT(deleteLater()));
connect(worker,SIGNAL(pass_data_to_server_(QByteArray,QByteArray)),this,SLOT(data_from_socket_(QByteArray,QByteArray)));
connect(this,SIGNAL(pass_data_to_client_(QByteArray,QByteArray)),worker,SLOT(show_data_received_from_server_(QByteArray,QByteArray)));
number_++;
thread_->start();
}
HINT: When i created socket via test_server signal create_socket_(int)
and socket create_socket(int), program didn't work correctly. To fix
that connect signal from starting thread to socket - create_socket_
Program now succesfuly without errors receive data from client 1 and pass it to client 2.
I have a QProcess where i would like to output the response in a label. First off, here is what i have tried:
QProcess *proc = new QProcess();
proc->setProcessChannelMode(QProcess::MergedChannels);
proc->start(cmdLineRequest.toUtf8().constData()); // cmdLineRequest is omitted
if (!proc->waitForFinished()) {
qDebug() << "Make failed:" << proc->errorString();
ui->topBarcode->setText(QString(proc->errorString()));
} else {
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
proc->readAll() is a QByteArray and setText accepts a QString. From what i've read, i should be able to cast the QByteArray to a QString, howver it does not work. I have also tried to convert proc->readAll() with the QString class
->setText(QString::fromUtf8(proc->readAll())) // not working
->setText(QString::fromLatin1(proc->readAll())) // not working
->setText(QString::fromLocal8Bit(proc->readAll())) // not working
... etc ...
It seems weird, since i'm adding pictures to labels in nearly the same matter using setPixmap(QPixmap::fromImage(image))
Any help appreciated, thank you.
Update:
If i add a QMessageBox before the end of the method that the above block of code belongs to, i can see the text added to the label. However when i close the QMessageBox, the text dissapears. Am i giving an address position to the label with proc->readAll() or how come this behaviour? Thank you.
The problem here is that you're calling proc->readAll twice; the first for the qDebug output and then again for the string which you set on the label.
{
qDebug() << "Make output:" << proc->readAll();
ui->topBarcode->setText(QString(proc->readAll()) + "asdf");
}
I expect that as QProcess is a QIODevice, it's returning a buffered byte array. When you read it, it removes that from the buffer.
Therefore, create a temporary string and read the buffer once, before calling qDebug and setting the string to the label: -
{
QString output = proc->readAll();
qDebug() << "Make output:" << output;
ui->topBarcode->setText(output + "asdf");
}
You should listen to readyReadStandardOutput() signal and call readAll() when you receive signal.
or you can call
bool waitForReadyRead(int msecs = 30000)
before calling readAll().
I am just trying to create a file with QProcess by the following source code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage Dialog;
Dialog.setupUi(ProcessMessage);
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
ProcessMessage->show();
processmethodONE();
}
void processmethodONE()
{
QString ProcessCommand = "w8 " + blablubli";
Prozess.setWorkingDirectory(Path); //QProcess "Prozess" is globaly defined
Prozess.setStandardOutputFile(Path); //in my class
Prozess.start(ProcessCommand);
QProcess::ExitStatus Status = Prozess.exitStatus();
if (Status == 0)
{
std::cout << "File created!" << std::endl;
}
}
This process creates out of another file which is located in the QString "Path" a new file, let me call it "PROFILE" (PRO for Problem :). The Profile also is created, but is never completed, I guess not even 50% of the file are completed.
Just when using
while(!Prozess.waitForFinished())
{
qApp->processEvents();
std::cerr << "Process Create PROFile running " << std::endl;
}
the file is written completely.
Furthermore I tried to use the QProcess finished(int) Signal to start another method and deleted the while loop (which freezes the whole GUI). I declared it in the constructor with:
connect(&Prozess, SIGNAL(finished(int)), this, (SLOT(processmethodTWO())));
But I guess this could not work because the first process isn't finished completely. Where is the problem?
There is no warranty that right after Prozess.start(ProcessCommand); process will be finished, so calling "Prozess.exitStatus();" right after it will give you "false positive". You certainly will have to wait until process is finished. You may either do it with with while loop, that you suggested or with QEventLoop
// ...
Prozess.setStandardOutputFile(Path); //in my class
QEventLoop loop;
connect(&Prozess, SIGNAL(error(QProcess::ProcessError)), &loop, SLOT(quit()));
connect(&Prozess, SIGNAL(finished(int, QProcess::ExitStatus)), &loop, SLOT(quit()));
Prozess.start();
loop.exec();
// Now your process status should be valid:
QProcess::ExitStatus Status = Prozess.exitStatus();
I have the following code:
void Processmethod()
{
QDialog *ProcessMessage = new QDialog;
Ui::DialogProcessMessage Dialog;
Dialog.setupUi(ProcessMessage);
ProcessMessage->setModal(true);
ProcessMessage->setAttribute(Qt::WA_DeleteOnClose);
ProcessMessage->show();
qApp->processEvents();
processmethodONE();
processmethodTWO();
processmethodTHREE();
}
void processmethodONE()
{
QString ProcessCommand = "w8 " + blablubli";
Prozess.setWorkingDirectory(Path); //QProcess "Prozess" is globaly defined
Prozess.setStandardOutputFile(Path); //in my class
QThread* thread = new QThread;
Prozess.moveToThread(thread);
Prozess.start(ProcessCommand);
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
QProcess::ExitStatus Status = Prozess.exitStatus();
if (Status == 0)
{
std::cout << "File created!" << std::endl;
}
}
In this source code I try to open a popup dialog before some processes are starting. problem is that the dialog is not clickable, but on the dialog I want to create a button to abort the running method. As you can see I tried using QThread to run the process(es) in another thread, but still I can't click the dialog. Furthermore if I open my application (GUI) with the "application/x-executable"-file the dialogs content is missing when activating the above shown method. How can I fix these problems? Where am I wrong? greetings
void processmethodONE()
{
QThread* thread = new QThread;
Prozess.moveToThread(thread);
Prozess.start(ProcessComand);
Here you moved the QProcess to another thread. But then you call start() on it. That's already not thread-safe.
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
This blocks and makes using a thread useless. Also, it's not thread-safe.
You should instead not use threads but:
remove the waitForFinished() call
Connect the finished() and error() signals of the QProcess to slots which then start the next step, i.e. processMethodTWO.
I would also advise against reusing QProcess objects and just create a new one for each step.
While I still don't fully understand your recently updated code example, I feel this might be your issue:
while(!Prozess.waitForFinished(2000))
{
std::cerr << "Process running " << std::endl;
}
Wherever you are really calling this in your original code is blocking while waiting for Prozess to finish.
Use a brand new QProcess instance for each one, and connect their finished() signals to a SLOT that will get called when they have finished. Don't manually poll them and block. This will allow you to completely get rid of QThreads altogether.