Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Application not shutting down properly when (x) button is clicked.
QtWS25 Last Chance

Application not shutting down properly when (x) button is clicked.

Scheduled Pinned Locked Moved Solved Qt for Python
11 Posts 3 Posters 1.7k 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.
  • T Offline
    T Offline
    tbreimer
    wrote on 2 Aug 2024, 13:59 last edited by
    #1

    I've created a window in Qt for Python by loading a ui file in the following way:

    import sys
    from PySide6.QtUiTools import QUiLoader
    from PySide6.QtWidgets import QApplication, QMainWindow
    from PySide6.QtCore import QFile
    
    class MainWindow(QMainWindow):
    
        def __init__(self, app):
            super().__init__()
            self.app = app
            loader = QUiLoader()
            file = QFile("mainWindow.ui")
            file.open(QFile.ReadOnly)
            self.ui = loader.load(file, self)
            file.close()
            self.ui.show()
    
        def closeEvent(self, event):
            print("Close event triggered")
            self.app.quit()
            event.accept()
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = MainWindow(app)
        app.aboutToQuit.connect(lambda: print("quit"))
        sys.exit(app.exec())
    

    I've overrided the closeEvent() method to try to get "Close event triggered" to print out. I've also connected the aboutToQuit signal to a lambda function which prints out "quit". However, when I press the (x) button, neither "quit" nor "Close event triggered" is printed, and the terminal process keeps running. So what am I doing wrong here? I'm on Ubuntu, and here is my ui file, if that helps:

    <?xml version="1.0" encoding="UTF-8"?>
    <ui version="4.0">
     <class>MainWindow</class>
     <widget class="QMainWindow" name="MainWindow">
      <property name="geometry">
       <rect>
        <x>0</x>
        <y>0</y>
        <width>953</width>
        <height>681</height>
       </rect>
      </property>
      <property name="windowTitle">
       <string>MainWindow</string>
      </property>
      <widget class="QWidget" name="centralWidget">
       <layout class="QHBoxLayout" name="horizontalLayout"/>
      </widget>
      <widget class="QMenuBar" name="menuBar">
       <property name="geometry">
        <rect>
         <x>0</x>
         <y>0</y>
         <width>953</width>
         <height>22</height>
        </rect>
       </property>
      </widget>
     </widget>
     <resources/>
     <connections/>
    </ui>
    
    J 1 Reply Last reply 2 Aug 2024, 14:55
    0
    • T tbreimer
      2 Aug 2024, 13:59

      I've created a window in Qt for Python by loading a ui file in the following way:

      import sys
      from PySide6.QtUiTools import QUiLoader
      from PySide6.QtWidgets import QApplication, QMainWindow
      from PySide6.QtCore import QFile
      
      class MainWindow(QMainWindow):
      
          def __init__(self, app):
              super().__init__()
              self.app = app
              loader = QUiLoader()
              file = QFile("mainWindow.ui")
              file.open(QFile.ReadOnly)
              self.ui = loader.load(file, self)
              file.close()
              self.ui.show()
      
          def closeEvent(self, event):
              print("Close event triggered")
              self.app.quit()
              event.accept()
      
      if __name__ == "__main__":
          app = QApplication(sys.argv)
          window = MainWindow(app)
          app.aboutToQuit.connect(lambda: print("quit"))
          sys.exit(app.exec())
      

      I've overrided the closeEvent() method to try to get "Close event triggered" to print out. I've also connected the aboutToQuit signal to a lambda function which prints out "quit". However, when I press the (x) button, neither "quit" nor "Close event triggered" is printed, and the terminal process keeps running. So what am I doing wrong here? I'm on Ubuntu, and here is my ui file, if that helps:

      <?xml version="1.0" encoding="UTF-8"?>
      <ui version="4.0">
       <class>MainWindow</class>
       <widget class="QMainWindow" name="MainWindow">
        <property name="geometry">
         <rect>
          <x>0</x>
          <y>0</y>
          <width>953</width>
          <height>681</height>
         </rect>
        </property>
        <property name="windowTitle">
         <string>MainWindow</string>
        </property>
        <widget class="QWidget" name="centralWidget">
         <layout class="QHBoxLayout" name="horizontalLayout"/>
        </widget>
        <widget class="QMenuBar" name="menuBar">
         <property name="geometry">
          <rect>
           <x>0</x>
           <y>0</y>
           <width>953</width>
           <height>22</height>
          </rect>
         </property>
        </widget>
       </widget>
       <resources/>
       <connections/>
      </ui>
      
      J Offline
      J Offline
      JonB
      wrote on 2 Aug 2024, 14:55 last edited by JonB 8 Feb 2024, 14:56
      #2

      @tbreimer said in Application not shutting down properly when (x) button is clicked.:

      and the terminal process keeps running.

      What "terminal" process"? You have created a QApplication and shown a QMainWindow, so this application is not running in a terminal.

      Start by removing your closeEvent() and self.app.quit(), does your application exit when the main window is closed? Not that it matters, but get rid of your MainWindow and using the .ui file, just verify it exits with a plain QMainWindow and nothing else.

      T 1 Reply Last reply 5 Aug 2024, 14:43
      0
      • S Offline
        S Offline
        SGaist
        Lifetime Qt Champion
        wrote on 2 Aug 2024, 18:14 last edited by
        #3

        Hi,

        Just did a quick test with:

        import sys
        from PySide6.QtWidgets import QApplication, QMainWindow
        
        class MainWindow(QMainWindow):
        
            def __init__(self):
                super().__init__()
        
            def closeEvent(self, event):
                print("Close event triggered")
                super().closeEvent(event)
        
        if __name__ == "__main__":
            app = QApplication(sys.argv)
            window = MainWindow()
            window.show()
            app.aboutToQuit.connect(lambda: print("quit"))
            sys.exit(app.exec())
        

        It's working properly on macOS 13.6.8 with PySide6 6.7.2

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        0
        • J JonB
          2 Aug 2024, 14:55

          @tbreimer said in Application not shutting down properly when (x) button is clicked.:

          and the terminal process keeps running.

          What "terminal" process"? You have created a QApplication and shown a QMainWindow, so this application is not running in a terminal.

          Start by removing your closeEvent() and self.app.quit(), does your application exit when the main window is closed? Not that it matters, but get rid of your MainWindow and using the .ui file, just verify it exits with a plain QMainWindow and nothing else.

          T Offline
          T Offline
          tbreimer
          wrote on 5 Aug 2024, 14:43 last edited by
          #4

          @JonB said in Application not shutting down properly when (x) button is clicked.:

          What "terminal" process"?

          By this I mean that if I run the command python3 ./main.py in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.

          Using a normal QMainWindow object does solve the issue, with the process ending once the window is closed. Here's a video demonstrating this, which is my desired behavior. This quitting behavior also works when loading a ui file and setting it as the central widget to a QMainWindow in the following way:

          import sys
          from PySide6.QtWidgets import QApplication, QMainWindow
          from PySide6.QtUiTools import QUiLoader
          from PySide6.QtCore import QFile
          
          if __name__ == "__main__":
              app = QApplication(sys.argv)
              window = QMainWindow()
              loader = QUiLoader()
              file = QFile("mainWindow.ui")
              file.open(QFile.ReadOnly)
              ui = loader.load(file)
              window.setCentralWidget(ui)
              window.show()
              app.aboutToQuit.connect(lambda: print("quit"))
              sys.exit(app.exec())
          

          So, the issue seems to related to my custom MainWindow class. However, I'm still confused as to why closeEvent() fails to run and "quit" fails to print in my original code.

          J S 2 Replies Last reply 5 Aug 2024, 15:21
          0
          • T tbreimer
            5 Aug 2024, 14:43

            @JonB said in Application not shutting down properly when (x) button is clicked.:

            What "terminal" process"?

            By this I mean that if I run the command python3 ./main.py in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.

            Using a normal QMainWindow object does solve the issue, with the process ending once the window is closed. Here's a video demonstrating this, which is my desired behavior. This quitting behavior also works when loading a ui file and setting it as the central widget to a QMainWindow in the following way:

            import sys
            from PySide6.QtWidgets import QApplication, QMainWindow
            from PySide6.QtUiTools import QUiLoader
            from PySide6.QtCore import QFile
            
            if __name__ == "__main__":
                app = QApplication(sys.argv)
                window = QMainWindow()
                loader = QUiLoader()
                file = QFile("mainWindow.ui")
                file.open(QFile.ReadOnly)
                ui = loader.load(file)
                window.setCentralWidget(ui)
                window.show()
                app.aboutToQuit.connect(lambda: print("quit"))
                sys.exit(app.exec())
            

            So, the issue seems to related to my custom MainWindow class. However, I'm still confused as to why closeEvent() fails to run and "quit" fails to print in my original code.

            J Offline
            J Offline
            JonB
            wrote on 5 Aug 2024, 15:21 last edited by
            #5

            @tbreimer
            @SGaist shows code which subclasses QMainWindow, overrides closeEvent() and works for him. Does his code work for you? I don't know if it's to do with loader.load(), does that do something about replacing your widget with the one loaded? Never used it.

            T 1 Reply Last reply 6 Aug 2024, 13:18
            0
            • T tbreimer
              5 Aug 2024, 14:43

              @JonB said in Application not shutting down properly when (x) button is clicked.:

              What "terminal" process"?

              By this I mean that if I run the command python3 ./main.py in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.

              Using a normal QMainWindow object does solve the issue, with the process ending once the window is closed. Here's a video demonstrating this, which is my desired behavior. This quitting behavior also works when loading a ui file and setting it as the central widget to a QMainWindow in the following way:

              import sys
              from PySide6.QtWidgets import QApplication, QMainWindow
              from PySide6.QtUiTools import QUiLoader
              from PySide6.QtCore import QFile
              
              if __name__ == "__main__":
                  app = QApplication(sys.argv)
                  window = QMainWindow()
                  loader = QUiLoader()
                  file = QFile("mainWindow.ui")
                  file.open(QFile.ReadOnly)
                  ui = loader.load(file)
                  window.setCentralWidget(ui)
                  window.show()
                  app.aboutToQuit.connect(lambda: print("quit"))
                  sys.exit(app.exec())
              

              So, the issue seems to related to my custom MainWindow class. However, I'm still confused as to why closeEvent() fails to run and "quit" fails to print in my original code.

              S Offline
              S Offline
              SGaist
              Lifetime Qt Champion
              wrote on 5 Aug 2024, 15:52 last edited by
              #6

              @tbreimer said in Application not shutting down properly when (x) button is clicked.:

              @JonB said in Application not shutting down properly when (x) button is clicked.:

              What "terminal" process"?

              By this I mean that if I run the command python3 ./main.py in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.

              You can't enter new commands because you have the Qt event loop running which is normal. You would have the same result starting any GUI enabled application from the command line. You would also have the same result if using for example tail -f /var/log/syslog as the tail process will continue to work in the foreground.

              Interested in AI ? www.idiap.ch
              Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

              T 1 Reply Last reply 6 Aug 2024, 13:07
              0
              • S SGaist
                5 Aug 2024, 15:52

                @tbreimer said in Application not shutting down properly when (x) button is clicked.:

                @JonB said in Application not shutting down properly when (x) button is clicked.:

                What "terminal" process"?

                By this I mean that if I run the command python3 ./main.py in the terminal to start the application, it is impossible to type any new commands in the terminal, even after the window is closed. I'm not sure how you would run the application without using a terminal window, unless you've built an executable from the project. I've also noticed by using the system monitor that the process that starts when the application is run does not end after the window is closed. Here's a video example to demonstrate what I mean.

                You can't enter new commands because you have the Qt event loop running which is normal. You would have the same result starting any GUI enabled application from the command line. You would also have the same result if using for example tail -f /var/log/syslog as the tail process will continue to work in the foreground.

                T Offline
                T Offline
                tbreimer
                wrote on 6 Aug 2024, 13:07 last edited by
                #7

                @SGaist said in Application not shutting down properly when (x) button is clicked.:

                You can't enter new commands because you have the Qt event loop running which is normal.

                I understand that, but compare this behavior to this. In the first one, the event loop keeps running indefinitely after the window is closed, and is only stopped with a manual control-z to suspend the process. In the second example, the event loops automatically ends after the window is closed and the process also ends.

                1 Reply Last reply
                0
                • J JonB
                  5 Aug 2024, 15:21

                  @tbreimer
                  @SGaist shows code which subclasses QMainWindow, overrides closeEvent() and works for him. Does his code work for you? I don't know if it's to do with loader.load(), does that do something about replacing your widget with the one loaded? Never used it.

                  T Offline
                  T Offline
                  tbreimer
                  wrote on 6 Aug 2024, 13:18 last edited by tbreimer 8 Jun 2024, 13:23
                  #8

                  @JonB said in Application not shutting down properly when (x) button is clicked.:

                  @SGaist shows code which subclasses QMainWindow, overrides closeEvent() and works for him. Does his code work for you?

                  It does! And I also figured out the problem, @JonB's hunch about it being related to the loader.load() was spot on. In my original code, I was using the QUILoader to load the ui file and set it's parent to MainWindow. Then, I was showing the QWidget retuned by the loader, like so:

                  self.ui = loader.load(file, self)
                  self.ui.show()
                  

                  What I needed to do is set self.ui as the central widget of MainWindow, and then call MainWindow.show(). This example works to subclass QMainWindow , load a ui file, override the closeEvent method, and properly shutdown when the window is closed.

                  import sys
                  from PySide6.QtWidgets import QApplication, QMainWindow
                  from PySide6.QtUiTools import QUiLoader
                  from PySide6.QtCore import QFile
                  
                  class MainWindow(QMainWindow):
                  
                      def __init__(self):
                          super().__init__()
                          loader = QUiLoader()
                          file = QFile("mainWindow.ui")
                          file.open(QFile.ReadOnly)
                          ui = loader.load(file)
                          self.setCentralWidget(ui)
                          self.show()
                  
                      def closeEvent(self, event):
                          print("Close event triggered")
                          super().closeEvent(event)
                  
                  if __name__ == "__main__":
                      app = QApplication(sys.argv)
                      window = MainWindow()
                      window.show()
                      sys.exit(app.exec())
                  

                  Thanks for the help everyone!

                  J 1 Reply Last reply 6 Aug 2024, 13:48
                  0
                  • T tbreimer has marked this topic as solved on 6 Aug 2024, 13:18
                  • T tbreimer
                    6 Aug 2024, 13:18

                    @JonB said in Application not shutting down properly when (x) button is clicked.:

                    @SGaist shows code which subclasses QMainWindow, overrides closeEvent() and works for him. Does his code work for you?

                    It does! And I also figured out the problem, @JonB's hunch about it being related to the loader.load() was spot on. In my original code, I was using the QUILoader to load the ui file and set it's parent to MainWindow. Then, I was showing the QWidget retuned by the loader, like so:

                    self.ui = loader.load(file, self)
                    self.ui.show()
                    

                    What I needed to do is set self.ui as the central widget of MainWindow, and then call MainWindow.show(). This example works to subclass QMainWindow , load a ui file, override the closeEvent method, and properly shutdown when the window is closed.

                    import sys
                    from PySide6.QtWidgets import QApplication, QMainWindow
                    from PySide6.QtUiTools import QUiLoader
                    from PySide6.QtCore import QFile
                    
                    class MainWindow(QMainWindow):
                    
                        def __init__(self):
                            super().__init__()
                            loader = QUiLoader()
                            file = QFile("mainWindow.ui")
                            file.open(QFile.ReadOnly)
                            ui = loader.load(file)
                            self.setCentralWidget(ui)
                            self.show()
                    
                        def closeEvent(self, event):
                            print("Close event triggered")
                            super().closeEvent(event)
                    
                    if __name__ == "__main__":
                        app = QApplication(sys.argv)
                        window = MainWindow()
                        window.show()
                        sys.exit(app.exec())
                    

                    Thanks for the help everyone!

                    J Offline
                    J Offline
                    JonB
                    wrote on 6 Aug 2024, 13:48 last edited by
                    #9

                    @tbreimer
                    Glad I could help. It's your choice, but why do you use this QUILoader/loading stuff at all? Like I said, I never have. So far as I can see, when you do so you lost all ability to address the widgets you design directly by Python variable, don't you have to QObject::findChild<>() to get at them? I always use Option A: Generating a Python class rather than Option B, much better editing experience as well as coding? And what everyone in C++ does. Have you looked at it or just settled for the loader approach?

                    1 Reply Last reply
                    0
                    • T Offline
                      T Offline
                      tbreimer
                      wrote on 6 Aug 2024, 14:03 last edited by
                      #10

                      @JonB I see what you mean, and yes I have to do QObject::findChild<>() to get every widget. I suppose when I was initially learning Qt for Python I just thought it would be easier to forgo the extra step of using the pyside6-uic tool every time I made changes to the ui file. But I agree in retrospect that Option A is better.

                      J 1 Reply Last reply 6 Aug 2024, 14:43
                      1
                      • T tbreimer
                        6 Aug 2024, 14:03

                        @JonB I see what you mean, and yes I have to do QObject::findChild<>() to get every widget. I suppose when I was initially learning Qt for Python I just thought it would be easier to forgo the extra step of using the pyside6-uic tool every time I made changes to the ui file. But I agree in retrospect that Option A is better.

                        J Offline
                        J Offline
                        JonB
                        wrote on 6 Aug 2024, 14:43 last edited by JonB 8 Jun 2024, 14:44
                        #11

                        @tbreimer
                        Yes, the extra step is irritating (I don't know, I think Creator can call it automatically (when .ui is changed) for you for Python? It does so for C++) but it's so worth it! Not only nicer code, but also design-time code completion when using the generated variables and the editor knows about their types.

                        1 Reply Last reply
                        0

                        1/11

                        2 Aug 2024, 13:59

                        • Login

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