Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. Application/process runs after exiting

Application/process runs after exiting

Scheduled Pinned Locked Moved Unsolved General and Desktop
8 Posts 3 Posters 3.3k Views
  • 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.
  • cpperC Offline
    cpperC Offline
    cpper
    wrote on last edited by cpper
    #1

    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
    0
    • Chris KawaC Offline
      Chris KawaC Offline
      Chris Kawa
      Lifetime Qt Champion
      wrote on last edited by Chris Kawa
      #2

      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
      5
      • cpperC Offline
        cpperC Offline
        cpper
        wrote on last edited by cpper
        #3

        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
        0
        • VRoninV Offline
          VRoninV Offline
          VRonin
          wrote on last edited by
          #4
          • 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
          1
          • cpperC Offline
            cpperC Offline
            cpper
            wrote on last edited by cpper
            #5

            @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
            0
            • cpperC Offline
              cpperC Offline
              cpper
              wrote on last edited by cpper
              #6

              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
              0
              • cpperC Offline
                cpperC Offline
                cpper
                wrote on last edited by
                #7

                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
                0
                • VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on last edited by
                  #8

                  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
                  2

                  • Login

                  • Login or register to search.
                  • First post
                    Last post
                  0
                  • Categories
                  • Recent
                  • Tags
                  • Popular
                  • Users
                  • Groups
                  • Search
                  • Get Qt Extensions
                  • Unsolved