4

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

Streight
  • 811
  • 4
  • 15
  • 28
  • 1
    I have a few questions... 1) How are you calling `Processmethod()`? 2) Why do you feel you need to create a QThread and move the QProcess into it? And also, why are you then not starting the new QThread? 3) Are you using this global QProcess for all your `processmethodX()`? – jdi Mar 25 '12 at 18:10
  • it doesnt fit with the question, but I'd suggest you to write variables names in _lowerCamelCase_. It's much fastly readable. However I agree with jdi, need more info to answer. – jalone Mar 25 '12 at 18:28
  • There's usually no need to run QProcess in a thread, as its API is not blocking, unless you use the waitForStarted/Finished methods. – Frank Osterfeld Mar 25 '12 at 18:43
  • @FrankOsterfeld: I am betting that once the OP gives us the answers to my questions, it will be clear that there is extra cruft here (you being correct in not needing QProcess in a thread) – jdi Mar 25 '12 at 19:10
  • 1)I call Processmethod() when a pushButton is clicked. 2)I thought to run the process in another thread would leave the dialog clickable/available. You are right I did not start the QThread - my fault - do I have to create a connection method and connect the thread to a method in which I define the process? 3.I have one QProcess for each process - would it be better to use just the same again? I am sorry for my mistake, but I had problems understanding the QThread methods probably because my English isn't good enough. @Frank: As you can see now I use waitForFinished - edited my question. – Streight Mar 25 '12 at 19:20
  • Yes, you should be using separate QProcess instances, so that is fine. QThread would allow your dialog to keep running, and so would QProcess, but only if you don't go and block your main thread by waiting for them to finish. Pick one or the other: QThread, or QProcess, and use their signals to tell your main thread when they are done. See both the answers we have given – jdi Mar 25 '12 at 19:38
  • The problem is, that I want the main thread (GUI main window) to freeze whereas the processes are running, just the popup dialog should be clickable. So, does anyone know how to achieve this? – Streight Mar 25 '12 at 21:39

2 Answers2

6
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:

  1. remove the waitForFinished() call
  2. 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.

Frank Osterfeld
  • 24,815
  • 5
  • 58
  • 70
  • Ok I first try this. I already have for each process one different QProcess object - that's what I wanted to tell with my first comment. – Streight Mar 25 '12 at 19:31
  • I tried now to connect the finish() signal of the first process "Prozess" with the second method "processmethodTWO()" with connect(Prozess, SIGNAL(finished()),processmethodTWO(),(SLOT(start()))); , but I get the error "invalid use of void expression". -> probably a noob fail :). – Streight Mar 25 '12 at 19:47
  • Using `finished()` signal instead of blocking `waitForFinished()` really did help. QML side buffered up all the emitted signals which caused the UI to be unresponsive until QProcess is finally done. Thanks a lot for basic but life saving post, still valid after a decade :) – Nazım Gediz Aydındoğmuş Jan 18 '21 at 13:09
3

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.

jdi
  • 90,542
  • 19
  • 167
  • 203
  • I have one global for each process, that means `one QProcess Prozess for processmethodONE();` , `one QProcess Prozess2 for processmethodTWO();`... The `waitForFinished()` method I need because the processes need some time and the previous process always needs to be finished before the next starts. – Streight Mar 25 '12 at 19:27
  • If this is the case, then you have to do a different approach. Your example suggested that all the processes were able to run at the same time. If you need them to run in order, then you could chain the `finished()` signal of one to the `start()` slot of the next, and so on. – jdi Mar 25 '12 at 19:32
  • Or, you could simply create one custom QThread that does all of your commands using synchronous lower level c++ system calls, since QProcess is no longer a benefit. And then just use the QThread finished() signal to announce that the whole thing is done. – jdi Mar 25 '12 at 19:37
  • I tried now to connect the finish() signal of the first process "Prozess" with the second method "processmethodTWO()" with `connect(Prozess, SIGNAL(finished()),processmethodTWO(),(SLOT(start())));` , but I get the error "invalid use of void expression". -> probably a noob fail :). – Streight Mar 25 '12 at 19:45
  • yea noob fail :-) Do `SLOT(Procezz2.start())` not `processmethodTWO()`. What you are doing is trying to call it. To be honest I am not even sure if this syntax is right. Im a python guy – jdi Mar 25 '12 at 19:47
  • i retried it with `connect(Prozess, SIGNAL(finished()), this,(SLOT(processmethodTWO.start())));` , but now I get the error `Error: no matching function for call to 'GUI :: connect (qprocess &, const char *, const GUI *, const char *) "` and `Candidates are: / usr/include/qt4/QtCore/qobject.h: 198:17: note: static bool QObject :: connect (const QObject *, const char *, const QObject *, const char *, Qt :: Connection Type)............` – Streight Mar 25 '12 at 19:57
  • LOL. Im a python guy sorry. Its probably: `connect(Prozess, SIGNAL(finished()), Prozess2, SLOT(start()))` – jdi Mar 25 '12 at 19:59
  • Doesn't work. Furthermore Prozess2 is only fully defined localy in processmethodTWO() (see processmethodONE() in my question), so calling the Prozess2.start directly wouldn't work. If it should work I would have to call the method processmethodTWO(). – Streight Mar 25 '12 at 20:08
  • Basically, my answer has outlined what you need to do. This is all just organizational issues of your code. My suggestion itself is solid. I can't rewrite your entire code for you. – jdi Mar 25 '12 at 20:40
  • Yeah right, also thx for the answer, but "Frank Osterfeld" gave the same answer first so I will have to accept his answer. however, thx:). – Streight Mar 26 '12 at 14:10
  • Lol. Well actually I posted the first answer and he posted one a bit after. But whatever! Good luck! – jdi Mar 26 '12 at 15:58