I got strange problem. QProcess just not working!
And error is unknown.
I got global var in header
QProcess *importModule;
An I got this function ( I tried both start and startDetached methods btw )
void App::openImport(){
importModule = new QProcess();
importModule->setWorkingDirectory(":\\Resources");
importModule->startDetached("importdb_module.exe");
QMessageBox::information(0,"",importModule->errorString());
}
It jsut outputs that error is unknown. Also it wont start other exes like
void App::openImport(){
importModule = new QProcess();
importModule->setWorkingDirectory("C:\\Program Files\\TortoiseHg");
importModule->startDetached("hg.exe");
QMessageBox::information(0,"",importModule->errorString());
}
What I've done wrong?
And is there other ways to run some .exe from my programm?
Or maybe .bat files(which runs exes)? (Tried with QProcess too, not working)
startDetached() is a static method and doesn't operate on importModule at all.
It starts a process and then stops caring. Thus the error()/errorState() in importModule has nothing to do with the startDetached() call. What you want is start().
However, as QProcess is asynchronous, nothing will have happened yet immediately after start() returns. You must connect to the started(), error() and finished() signals to learn about the result.
connect(importModule, SIGNAL(started()), this, SLOT(importModuleStarted()));
connect(importModule, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(importModuleFinished(int, QProcess::ExitStatus)));
CONNECT(importModule, SIGNAL(error(QProcess::ProcessError)), this, SLOT(importModuleError(QProcess::ProcessError)));
importModule->start(QStringLiteral("importdb_module"), QStringList());
Alternatively you can use the blocking wait functions:
importModule->start(QStringLiteral("importdb_module"), QStringList());
importModule->waitForStarted(); // waits until starting is completed
importModule->waitForFinished(); // waits until the process is finished
However, I strongly advise against using them in the main thread, as they block the UI then.
Related
I am trying to run a script in parallel to my Qt program and am having trouble starting it as a separate process. Check out my attempts below and let me know what you see wrong.
The first attempt was just a system call:
system("python3 startprocess.py");
This works but it also stops the program while running it.
I then followed this guy https://forum.qt.io/topic/92205/writing-commands-to-linux-bash with no success. No errors, just no start of my script.
I am trying this after I saw the documentation and have the below code.
QProcess process;
process.start("python3 startprocess.py");
process.waitForStarted();
I am just wanting to start this script and have it run at the same time as my C++ code. Perhaps I am using the QProcess wrong?
UPDATE:
It was a lot easier to use QThreading and the original system call.
I think the issue is that the QProcess doesn't have the file path and fails to find and start it! I suggest first to use the full file path! Also check the QProcess::setWorkingDirectory and QProcess::setProcessEnvironment that are useful to handle this case!
Update
In order to prevent the QProcess to be killed while running and without freezing the GUI, you need to define it as a pointer, then connect the QProcess::finished event; in the slot, you can check the exit code and delete the sender using QObject::deleteLater method. Check both the Qt example and the QProcess::finished.
Update 2
Try this code:
auto process = new QProcess(this);
connect(process, QOverload<int,QProcess::ExitStatus>::of(&QProcess::finished),
[this](int exitCode, QProcess::ExitStatus exitStatus)
{
if (exitStatus == QProcess::ExitStatus::CrashExit
|| exitCode != 0) {
// Process error!
} else {
// Process OK!
}
});
process->setWorkingDirectory("startprocess.py folder location");
process->start("python3 startprocess.py");
if (!process->waitForStarted(-1)) {
// Failed to start process
delete process;
}
I'm trying to use QProcess inside a thread to do some operations (read I2C connections).The update method is calling every 100 msec:
void TempsReader::update()
{
if (_currProcess == nullptr) {
_currProcess = new QProcess();
connect(_currProcess, &QProcess::errorOccurred, this, &TempsReader::onProcessError);
connect(_currProcess, SIGNAL(finished(int,QProcess::ExitStatus)),
this, SLOT(onProcessFinished()));
}
_currProcess->start("sh");
if (_currProcess->waitForStarted()) {
_currProcess->write("i2cdetect -y 1");
_currProcess->closeWriteChannel();
_currProcess->waitForFinished();
}
}
After some time, the process gives "FailedToStart" error and never starts again.
void TempsReader::onProcessError(QProcess::ProcessError error)
{
qDebug() << error;
_currProcess->close();
}
void TempsReader::onProcessFinished()
{
QString devs = _currProcess->readAll();
_currProcess->waitForFinished();
// doing some stuff with devs
_currProcess->close();
}
How can I fix this issue? Am I using QProcess in a wrong way? and how can I start the process again when it drops in error slot. Thanks in advance.
Update: QProcess::errorString() gives this: "Resource error (fork failure): Too many open files"
UPDATE: Finally I've found the issue and it was not related to QProcess itself. It was relating to I2C connection.
My guess is that you get the failure because all your update() calls share the same QProcess object.
What happens here is that when you call update(), you start the process. And 100ms later, you call it again without ensuring that the previous update() has finished to wait the end of the process.
The consequence is that you try to start an already started process and thus it fails.
For me, the easiest solution is to create one QProcess object for each update() call.
Something like:
void TempsReader::update()
{
QProcess * current_process = new QProcess;
connect(current_process, &QProcess::errorOccured, this, &TempReader::onProcessError);
connect(current_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &TempReader::onProcessFinished());
current_process->start("sh"); // Your command
current_process->waitForStarted();
current_process->write("i2cdetect -y 1");
current_process->waitForFinished();
current_process->deleteLater();
}
Or without pointers:
void TempsReader::update()
{
QProcess current_process;
connect(¤t_process, &QProcess::errorOccured, this, &TempReader::onProcessError);
connect(¤t_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &TempReader::onProcessFinished());
current_process.start("sh"); // Your command
current_process.waitForStarted();
current_process.write("i2cdetect -y 1");
current_process.waitForFinished();
}
As you did not show the calling part of the code (the thread creation, the 100ms loop, ...), this may not be the solution you need.
In this case, please let me know if it does not solve your issue so that I'll remove this answer.
Finally I've found the issue and it was not related to QProcess itself. It was relating to I2C connection. I was using this command in update: wiringPiI2CSetup(addr); and it opens a new device each time.
I'm creating a thread like this:
main.cpp
QThread acceptorThread;
acceptorObject acceptorobject;
acceptorobject.setupConnections(acceptorThread, simulation);
acceptorobject.moveToThread(&acceptorThread);
acceptorObject.cpp
void acceptorObject::setupConnections(QThread& thread, Simulation * simulation)
{
QObject::connect(&thread, SIGNAL(started()), this, SLOT(acceptNewClients()));
}
acceptNewClients() method works in infinite loop. At this point if I close my program I would get an error:
QThread destroyed while thread is still running
I looked through similar problems at stack and one guy said that I need to break the loop before finishing the thread in order to get rid of this bug. He also suggested to use a flag in infinite loop and emit a signal in destructor that will change the flag and eventually break the loop. It KINDA worked when I did something like this:
QObject::connect(&thread, SIGNAL(started()), this, SLOT(acceptNewClients()));
QObject::connect(this, SIGNAL(finishThread(bool)), this, SLOT(acceptNewClients(bool)));
And then emited finishThread(true) signal from destructor so I directly changed the flag. Of course I changed slot signature as well so it won't run in new thread anymore.
destructor code:
emit finishThread(true);
this->thread()->quit();
if(!this->thread()->wait(3000))
{
this->thread()->terminate();
this->thread()->wait();
}
How can I make this work?
What I've tried so far:
Adding a new slot that will change the flag. Result: when I close program the window dissapears but the proccess is still running. I think that destructor destroys the object before its emited signal is proccessed .
Making bool argument in acceptNewClients() slot a default one. Result: it overloads the funtion so one is run in different thread and the second one tries to change the flag which obviously doesn't work because they are completely different functions.
Solution:
connect(this, SIGNAL(finishThread()), &thread, SLOT(quit()));
connect(this, SIGNAL(finishThread()), this, SLOT(deleteLater()));
It was pointless to change slot function signature in this case.
In deconstructor I simply emit finishThread() signal, nothing more.
One way is instead of doing a while(true) in acceptNewClients you instead do
void acceptorObject::acceptNewClients(){
// do accept new client
QMetaObject::invokeMethod(this, "acceptNewClients", Qt::QueuedConnection);
}
In essence making the loop external.
The other option is to make everything use signals, QTcpServer (which I think you are using) has a newConnection signal you can connect to. Instead of using waitForNewConnection.
I'm using QtConcurrent to do some heavy background image processing and I want to display the image while parts of it are being updated progressively.
Each line of the image is computed separately and is passed a functor.
To compute the full image I then have a sequence of item that I pass to QtConcurrent mapped and each line emits a signal when it is done computing
Here is the instantiation of the class Worker:
//living in the main(gui) thread !
Worker::Worker(VideoEngine* engine):_engine(engine){
_watcher = new QFutureWatcher<bool>;
_watcher->setPendingResultsLimit(200);
connect(_watcher, SIGNAL(resultReadyAt(int)), this, SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
Here is the slot to report progress:
void Worker::onProgressUpdate(int i){
if(i < (int)_rows.size() && i%10==0){
cout << " index = " << i << " y = "<< _rows[i] << endl;
_engine->checkAndDisplayProgress(_rows[i],i);
}
}
Now the usage:
void Worker::_computeTreeForFrame(.../*unrelevant args*/){
....
....
_watcher->setFuture(
QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
}
}
All the signals are emitted but the slot onProgressUpdate gets called only when Qtconcurrent::mapped is done with all the items in the sequence.
When executing it has a huge delay while the sequence is processing and then all slots are executed sequentially afterwards.
I have tried all types of signal/slots connection and none of them changed this behaviour.
Any clue ?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Shf suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
The call was made until now in the main(gui) thread.
I changed the call to :
_computeFrameWatcher->setFuture(QtConcurrent::run(_worker,&Worker::computeTreeForFrame));
Since _computeTreeForFrame is now executed in another thread, I changed the call to QtConcurrent::mapped to:
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
This results in exactly the same behaviour as before.
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after Marek R suggestion
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ok so I made so tests and here is what I observed:
QtConcurrent::map :
Doesn't emit the signal resultReadyAt(int)
QtConcurrent::mapped
Emits resultReadyAt(int) only when finished
It doesn't matter if the call to the map function is done in a separate thread the same behaviour is encountered.
I also gave a try to the signal progressValueChanged(int) as the Qt progressDialog example suggests.
The signal progressValueChanged(int) gets emitted only for 2 lines in the image (the first and last).
This is really weird as in the Qt progress dialog example it is emitted smoothly.
I changed a bit the Qt example to launch the map function in another thread than the main thread and it still works well in that case.
The issue must arise from somewhere else.
Maybe the GUI event loop is doing something I don't expect ? I have no clue what.
I will now try QtConcurrent::mappedReduced and report with the results :-)
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT after giving a try to QtConcurrent::mappedReduced
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
It doesn't work and calls the "reduce" function ONLY when the "map" function is done. In other words it does the same than the previous signal/slots mechanism.
I'm running low in possibilities now
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
EDIT I'm back to a solution as close as the Qt progress dialog example
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Something must be wrong if I can't get the same behaviour than the Qt example.
Here's the code now:
//created in the main thread! (gui)
Worker::Worker(VideoEngine* engine):_engine(engine),_watcher(0){
_watcher = new QFutureWatcher<void>;
_watcher->setPendingResultsLimit(200);
connect(_watcher,SIGNAL(progressValueChanged(int)), _engine,
SLOT(onProgressUpdate(int)));
connect(_watcher, SIGNAL(finished()), engine, SLOT(engineLoop()));
}
//executed on the main thread
void Worker::computeTreeForFrame(...){
...
_watcher->setFuture(QtConcurrent::map(_sequence,boost::bind(metaEnginePerRow,_1,output)));
...
}
The call to computeTreeForFrame...
...
_worker->computeTreeForFrame();
...
This call is done in a slot .
It emits the signals for the line 0 and for the last line as told before but doesn't emits anything else.
Shouldn't this do EXACTLY what the Qt example does?
From task description it looks like you should use mappedReduced. Problem is that I don't see a good way to get partial results. One way to overcome this problem is to emit signal form reduce function.
It is possible that this thread may help.
It seems, that QtConcurrent::mapped does not put VideoEngine::metaEnginePerRow in another thread, judging by the documentation. If image is processed in the same thread as GUI, then your slots indeed will be executed after processing, no matter what type of connection you select, just as you've described.
The solution is to either run Worker::_computeTreeForFrame (as i understood, your main processing function) in another thread via QtConcurrent::run or to put your Worker object in another thread probably via QObject::moveToThread(). Then, the connection type you should use is Qt::QueuedConnection (or if you will put Worker in another thread before connection, you can connect even with Qt::AutoConnectionor Qt::UniqueConnection, caller and receiver will be in a different threads, so qt will automaticly chose QueuedConnection`)
EDIT:
I'm not sure, but your _watcher = new QFutureWatcher<bool>; is still created in the main thread and if you call
_watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output)));
_watcher->waitForFinished();
would _watcher set GUI thread to wait, in what it was created or thread, where this command is executed. If _watcher->setFuture(QtConcurrent::mapped(_sequence,
boost::bind(&VideoEngine::metaEnginePerRow,_1,output))); if the end of a function, is _watcher->waitForFinished(); needed at all? Qt will destroy thread right after it's execution and you set your processing function to run, why wait?
And _computeFrameWatcher should be of QFuture<void*> type.
EDIT2:
Ok, before i give up, i suggest you to test QObject::moveToThread:
before you call _worker->computeTreeForFrame(); , put it in another thread:
QThread *workerThread=new QThread();
_worker->moveToThread();
_worker->computeTreeForFrame();
/* connect _worker's finished signal with workerThread::quit and deleteLater slots */
and all connections within _worker should be DirectConnection and all connections between _worker and main (GUI) thread should be connected with QueuedConnection. Also it's probably good to create new thread in _worker constructor and move it to another thread immediately, this way you can destroy thread in _worker's destructor and don't worry about thread problem's in GUI thread
I'm doing a ping to an IP address, and I want to show into a QMessageBox that a ping operation is going on. After that, if a response is received or one second timeout happens, I want to close the QMessageBox.
Code:
int status;
QByteArray command;
QMessageBox myBox(QMessageBox::Information, QString("Info"), QString("Checking connection"), QMessageBox::NoButton, this);
command.append("ping -w 1 172.22.1.1");
status=system(command);
myBox.setStandardButtons(0);
myBox.exec();
if (0==status){ // Response received
// Some stuff here...
myeBox.setVisible(false);
}
else { // Timeout
// Some other stuff here...
myBox.setVisible(false);
}
My guess is that I may need to use threads for this task, but since I am a Qt newbie maybe the problem is anywhere else.
EDIT:
As #atamanroman suggested I've tried to use QProcess, using signal void QProcess::finished ( int exitCode, QProcess::ExitStatus exitStatus ) [signal] as told in Qt reference:
private:
QProcess *process;
//...
QMessageBox myBox(QMessageBox::Information, QString("Info"), QString("Checking connection"), QMessageBox::NoButton, this);
QObject::connect(&process, SIGNAL(finished(int, QProcess::ExitStatus)), &myBox, SLOT(close()));
command.append("ping -w 1 172.22.1.1");
process.start(comdand);
myBox.setStandardButtons(0);
myBox.exec();
And it's not working. myBox is never closed. What's wrong?
You should use QProcess (start ping.exe and parse output) or QTcpSocket (do the ping yourself) instead of system() because they are part of Qt and can signal you when the ping has finished. Connect to that signal in order to hide your QMessageBox.
In your edit:
First:
QProcess *process; // This is a pointer, you don't need to add "&" in connect
// You should have called "process = new QProcess" before...
QMessageBox myBox; // This is an object, you need to add the "&" to connect;
We take out the first &
QObject::connect(process, SIGNAL(finished(int, QProcess::ExitStatus)), &myBox, SLOT(close()));
second:
Using Linux ping will never stop, then you will never have the finished signal. You can provide ping some parameters like count or time to wait. Or start a timer to stop the process.
third:
You need to match the parameters between signals and slots to avoid warnings, etc.
I sugest you to create a local SLOT "processfinished(int, QProcess::ExitStatus)" and then you call to myBox.Close(), but "myBox" must be from class to have reference to this after end the method where you call it.