Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Unsolved Application/process runs after exiting

    General and Desktop
    3
    8
    2374
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • cpper
      cpper last edited by cpper

      In my program, I have a single button, which is checkable. When I first press it, it prints "test" every second; when I press it again, the loop which prints stops, and so on.

      This is the code:

      void MainWindow::on_pushButton_clicked(bool checked){
      
          if(checked){
             bloop=true;
             QTimer timer(this);
             QEventLoop loop;
             QObject::connect(&timer, &QTimer::timeout,&loop,&QEventLoop::quit);
      
              while(bloop){
                  qDebug()<<"test";
                  timer.start(1000);
                  loop.exec();
              }
          }
      
          else{
             bloop=false;
          }
      }
      

      bloop is a bool declared in MainWindow class.

      As you can see, the second press on the button makes bloop false, which exists the while(bloop) loop, started previously from the first click on the button. The application works how expected, but if I close the program(from the X icon) while the loop is started, the GUI closes, but I can still see "test" getting printed in the output, and also the process being alive. Also, "test" is printed without the 1000ms delay after closing the program.
      How could I prevent this ?

      1 Reply Last reply Reply Quote 0
      • Chris Kawa
        Chris Kawa Moderators last edited by Chris Kawa

        Wow. This is pretty convoluted way to just run a timer. I'd seriously rethink that and simplify. Anyway...

        By default Qt application exits when last window is closed. The implementation detail for this is that it is done by setting a "special flag" on a thread data that makes loops quit and prevents new ones from starting. This is done so that the usual a.exec() in the main() quits.

        A side effect is that when you close the window your local event loop quits. Since bloop was never set back to false the while loop keeps rolling and tries to start another loop. This time the loop.exec() fails because of the "special flag" set, so it quits immediately (or rather never starts). The while loop keeps on spinning like this indefinitely and, since the loop never starts inside, you see the stream of "test" on the output without delays. The timer is reset every time so it never timeouts anyway if the loop didn't started.

        The fix is to check the return value of loop.exec(). If it fails to start it returns non-zero value, so you can check it to know you should quit your while loop:

        ...
        if (loop.exec() != 0)
            break;
        ...
        
        1 Reply Last reply Reply Quote 5
        • cpper
          cpper last edited by cpper

          Thanks Chris, that did the trick.
          Do you know a better way of running a timer, and keeping everything in one function ?

          Just wondering, is there no way I could control the exit(X) event, and set bloop to false when exit(X) is pressed ?
          I've tried connecting a slot which makes bloop false to the QoreApplication::aboutToQuit() signal, but with no success.

          1 Reply Last reply Reply Quote 0
          • V
            VRonin last edited by

            • make QTimer timer; a member of MainWindow
            • in MainWindow constructor call:
            timer.setInterval(100);
            connect(&timer, &QTimer::timeout,[](){qDebug()<<"test";});
            
            • use on_pushButton_clicked() to start or stop the timer:
            void MainWindow::on_pushButton_clicked(bool checked){
            if(checked) timer.start();
            else timer.stop();
            }
            

            "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
            ~Napoleon Bonaparte

            On a crusade to banish setIndexWidget() from the holy land of Qt

            1 Reply Last reply Reply Quote 1
            • cpper
              cpper last edited by cpper

              @VRonin
              That's a shorther verison indeed. However, the program I provided above only contains the part which was causing the process to keep running, from a bigger project.

              This is the complete pushButton_clicked function:

              void MainWindow::on_pushButton_clicked(bool arg)
              {
                  if(arg){
              
                      flow=true;
                      keeploop=true;
                      ui->pushButton->setText("Stop");
              
                      fps=ui->spinBox->value();
                      pse=ui->spinBox_2->value();
              
                      QTimer timer(this);
                      QEventLoop loop;
                      QObject::connect(&timer, &QTimer::timeout,&loop,&QEventLoop::quit);
              
                      while(keeploop){
              
              
                              for(it=pics.begin();it<pics.end()&& flow;++it){
                              ui->label->setPixmap(*it);
              
                              timer.start(fps);
                              loop.exec();
                              }
              
                              if(!ui->checkBox->isChecked()){
                                  keeploop=false;
                                  ui->pushButton->setText("Start animation");
                                  ui->pushButton->setChecked(0);
                              }
              
                              else{
                                  timer.start(pse);
                                  loop.exec();
                              }
              
                      }
              
                  }
              
                  else{
                      flow=false;
                      keeploop=false;
                      ui->pushButton->setText("Start animation");
                  }
               }
              

              It displays pixmaps from vector pics, with "fps" delay between the pics, and "pse" delay if the checkbox(for looping) is enabled.
              I need to figure out where to put the if (loop.exec() != 0) break; because I have a nested loop.

              *Later edit: Something strange: In my complete program, I've replaced both lines of loop.exec(); with qDebug()<<loop.exec(); and after closing the program it prints "0" unlike in the first example I provided.

              1 Reply Last reply Reply Quote 0
              • cpper
                cpper last edited by cpper

                Here is a video of the program. If I click X while the loop is on, the process is still alive.

                1 Reply Last reply Reply Quote 0
                • cpper
                  cpper last edited by

                  I managed to solve the problem for the second program too.
                  Firstly, by overriding this function:

                   void MainWindow::closeEvent(QCloseEvent *event){
                       flow=false;
                       keeploop=false;
                       event->accept();
                   }
                  
                  

                  And secondly , by adding

                  if(!this->isVisible()){
                          QApplication::quit();
                      }
                  

                  at the end of the clicked function. Without this if, the infinite loops ends, but the program remains somehow alive,

                  1 Reply Last reply Reply Quote 0
                  • V
                    VRonin last edited by

                    You don't need an event loop at all, QTimer is already a loop. the idea is to use the slot associated with QTimer::timeoutto change images and the slot associated with the button to change the QTimer parameters + start/stop it.

                    I don't understand what the loop checkbox does however so I cannot put my code here

                    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                    ~Napoleon Bonaparte

                    On a crusade to banish setIndexWidget() from the holy land of Qt

                    1 Reply Last reply Reply Quote 2
                    • First post
                      Last post