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. Widget deletion process on app close?

Widget deletion process on app close?

Scheduled Pinned Locked Moved Unsolved Qt for Python
13 Posts 5 Posters 1.5k 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.
  • S Offline
    S Offline
    swpease
    wrote on last edited by
    #4

    @Denni-0 Where is/are appropriate places to do that? If I put it in an overridden closeEvent(), it doesn't work, which makes sense to me. Maybe check for QCloseEvent in an overridden event()?

    1 Reply Last reply
    0
    • jsulmJ jsulm

      @swpease said in Widget deletion process on app close?:

      I can still access my own member variables in my inherited class

      What inherited class? How is its life-time? Can you show your code?

      "When is the object actually deleted?" - that depends. If it does not have parent you are responsible for it's deletion. If it has a parent it is deleted when parent is deleted. Take a loop at https://doc.qt.io/qt-5/objecttrees.html

      S Offline
      S Offline
      swpease
      wrote on last edited by
      #5

      @jsulm Here is a pared down, working equivalent:

      import json
      
      from PySide2.QtCore import Qt
      from PySide2.QtWidgets import QApplication, QMainWindow
      
      
      class MainWindow(QMainWindow):
          def __init__(self, data, data_src='data.json'):
              super().__init__()
      
              self.setAttribute(Qt.WA_DeleteOnClose)
              self.data_modified = False
              self.data_src = data_src
              self.data = data
      
              QApplication.instance().lastWindowClosed.connect(self.save_dict)
      
          def save_dict(self):
              print(self.data)  # {'foo': 'bar'}
              print(self)  # <__main__.MainWindow(0x7fdf6ac551d0) at 0x109de7200>
      
      
      if __name__ == '__main__':
      
          import sys
      
          app = QApplication(sys.argv)
      
          data_src = 'data.json'
          with open(data_src) as f:
              data: dict = json.load(f)
      
          mainWin = MainWindow(data, data_src=data_src)
          mainWin.show()
          x = app.exec_()
      
          print(mainWin.data)  # {'foo': 'bar'}
          print(mainWin)  # RuntimeError: Internal C++ object (MainWindow) already deleted.
      
          sys.exit(x)
      

      where data.json is just {"foo": "bar"}

      In the actual program, there could be multiple instances of MainWindow, mimicking the sdi example, if that matters.

      1 Reply Last reply
      0
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #6

        Hi,

        Just a silly idea but if the saving takes that long, you can use a QSplashScreen to tell the user there's something going on. That would make it explicit that your app is not frozen.

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

        S 1 Reply Last reply
        2
        • SGaistS SGaist

          Hi,

          Just a silly idea but if the saving takes that long, you can use a QSplashScreen to tell the user there's something going on. That would make it explicit that your app is not frozen.

          S Offline
          S Offline
          swpease
          wrote on last edited by
          #7

          @SGaist Thanks for the suggestion. It goes in line with the hide() suggestion. I was under the impression that it wouldn't work because I had initially tried using QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)), which didn't work. Now I'm getting confused. I have:

          def closeEvent(self, event):
              if self.maybe_save():
                  self.write_settings()
                  # All work sometimes if `self.text_edit.document().isModified()` is True.
          
                  # Doesn't work (ever?) if `self.text_edit.document().isModified()` is False.
                  # QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
                  # QApplication.instance().processEvents()
          
                  # Both work always(?) if `self.text_edit.document().isModified()` is False.
                  # self.hide()
                  # QApplication.instance().processEvents()
          
                  # splash = QSplashScreen(QPixmap(':/images/new.png'))
                  # splash.show()
                  # QApplication.instance().processEvents()
          
                  if self.dict_modified:
                      with open(self.data_src, 'w') as f:
                          json.dump(self.data, f)
                  event.accept()
              else:
                  event.ignore()
          

          with:

          def maybe_save(self):
              if self.text_edit.document().isModified():
                  ret = QMessageBox.warning(self, "x",
                          "The document has been modified.\nDo you want to save your changes?",
                          QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
          
                  if ret == QMessageBox.Save:
                      return self.save()
                  elif ret == QMessageBox.Cancel:
                      return False
          
              return True
          

          Why would the call sometimes work?

          JonBJ 1 Reply Last reply
          0
          • S swpease

            @SGaist Thanks for the suggestion. It goes in line with the hide() suggestion. I was under the impression that it wouldn't work because I had initially tried using QApplication.setOverrideCursor(QCursor(Qt.WaitCursor)), which didn't work. Now I'm getting confused. I have:

            def closeEvent(self, event):
                if self.maybe_save():
                    self.write_settings()
                    # All work sometimes if `self.text_edit.document().isModified()` is True.
            
                    # Doesn't work (ever?) if `self.text_edit.document().isModified()` is False.
                    # QApplication.setOverrideCursor(QCursor(Qt.WaitCursor))
                    # QApplication.instance().processEvents()
            
                    # Both work always(?) if `self.text_edit.document().isModified()` is False.
                    # self.hide()
                    # QApplication.instance().processEvents()
            
                    # splash = QSplashScreen(QPixmap(':/images/new.png'))
                    # splash.show()
                    # QApplication.instance().processEvents()
            
                    if self.dict_modified:
                        with open(self.data_src, 'w') as f:
                            json.dump(self.data, f)
                    event.accept()
                else:
                    event.ignore()
            

            with:

            def maybe_save(self):
                if self.text_edit.document().isModified():
                    ret = QMessageBox.warning(self, "x",
                            "The document has been modified.\nDo you want to save your changes?",
                            QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
            
                    if ret == QMessageBox.Save:
                        return self.save()
                    elif ret == QMessageBox.Cancel:
                        return False
            
                return True
            

            Why would the call sometimes work?

            JonBJ Offline
            JonBJ Offline
            JonB
            wrote on last edited by JonB
            #8

            @swpease said in Widget deletion process on app close?:

            Why would the call sometimes work?

            Please define what you mean by "(sometimes) work"? Crashes? Hangs? Does not save? Saves but does not close? ....

            def closeEvent(self, event):
                if self.maybe_save():
            
            ...
            
            def maybe_save(self):
                    if ret == QMessageBox.Save:
                        return self.save()
            

            So what does your save() method return?

            Using a Python debugger to step through your code, or even just print() statements, is a really useful skill.

            1 Reply Last reply
            0
            • S Offline
              S Offline
              swpease
              wrote on last edited by
              #9

              hide() only works sometimes for me in the following:

              import json
              import time
              
              from PySide2.QtCore import Qt
              from PySide2.QtWidgets import QApplication, QMainWindow, QMessageBox
              
              
              class MainWindow(QMainWindow):
                  def __init__(self, data, data_src='data.json'):
                      super().__init__()
              
                      self.setAttribute(Qt.WA_DeleteOnClose)
                      self.data_modified = False
                      self.data_src = data_src
                      self.data = data
              
                  def closeEvent(self, event):
                      if self.maybe_save():
              
                          # MainWindow doesn't always hide
                          self.hide()
                          QApplication.instance().processEvents()
              
                          time.sleep(10)
                          # with open(self.data_src, 'w') as f:
                          #     json.dump(self.data, f)
              
                          event.accept()
                      else:
                          event.ignore()
              
                  def maybe_save(self):
                      if True:
                          ret = QMessageBox.warning(self, "x",
                                  "The document has been modified.\nDo you want to save your changes?",
                                  QMessageBox.Save | QMessageBox.Discard | QMessageBox.Cancel)
              
                          if ret == QMessageBox.Save:
                              return True
                          elif ret == QMessageBox.Cancel:
                              return False
              
                      return True
              
              
              if __name__ == '__main__':
              
                  import sys
              
                  app = QApplication(sys.argv)
              
                  data_src = 'data.json'  # Mine is 21 MB; takes a couple of seconds to `dump`
                  with open(data_src) as f:
                      data: dict = json.load(f)
              
                  mainWin = MainWindow(data, data_src=data_src)
                  mainWin.show()
                  sys.exit(app.exec_())
              
              1 Reply Last reply
              0
              • SGaistS Offline
                SGaistS Offline
                SGaist
                Lifetime Qt Champion
                wrote on last edited by
                #10

                You are trying to hide your window while you are already in the process do to it. That's not a good idea. Even more a bad idea is to block the thread with sleeping.

                Don't try to hide your widget in the close event, just show the splash screen, do your saving, and then everything will close nicely with the user knowing that things are going on.

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

                S 1 Reply Last reply
                2
                • SGaistS SGaist

                  You are trying to hide your window while you are already in the process do to it. That's not a good idea. Even more a bad idea is to block the thread with sleeping.

                  Don't try to hide your widget in the close event, just show the splash screen, do your saving, and then everything will close nicely with the user knowing that things are going on.

                  S Offline
                  S Offline
                  swpease
                  wrote on last edited by swpease
                  #11

                  @SGaist You mentioned blocking as a bad thing. Do you have a simple elaboration that could help me understand? From what I can determine, the QMessageBox is the source of the problem. I still have inconsistent behavior using a splash screen (it displays only sometimes), but only if the QMessageBox warning modal (blocking, right?) gets used.

                  Could this be an OS/version sort of issue?

                  Also, I'm not actually calling sleep in my code, I just plugged it in in case someone wanted to try running the code without needing to find a big JSON object to input. I was under the impression that it would behave the same as a lengthy file write.

                  JonBJ 1 Reply Last reply
                  0
                  • S swpease

                    @SGaist You mentioned blocking as a bad thing. Do you have a simple elaboration that could help me understand? From what I can determine, the QMessageBox is the source of the problem. I still have inconsistent behavior using a splash screen (it displays only sometimes), but only if the QMessageBox warning modal (blocking, right?) gets used.

                    Could this be an OS/version sort of issue?

                    Also, I'm not actually calling sleep in my code, I just plugged it in in case someone wanted to try running the code without needing to find a big JSON object to input. I was under the impression that it would behave the same as a lengthy file write.

                    JonBJ Offline
                    JonBJ Offline
                    JonB
                    wrote on last edited by JonB
                    #12

                    @swpease
                    I don't see how QMesssageBox is relevant to your issue. You are just using that to ask a question. Your issue lies in the time taken to do the save when the user tells you to do so.

                    I agree with @SGaist. If you dump your idea of hiding the window while the save proceeds and just went for a QProgressDialog or maybe a QSplashScreen, or even just a Qt::WaitCursor, for the duration of the save, it seems to me you would have resolved this by now. (I'm surprised a 21MB save even takes 2 seconds, but there you are --- hmm, maybe I'm over-optimistic.)

                    1 Reply Last reply
                    0
                    • S Offline
                      S Offline
                      swpease
                      wrote on last edited by
                      #13

                      Hmm... Well, I'm not sure what's going wrong on my end, so I'll just go with my original solution. I'll just have to live with the probability that somewhere out there, functional programming and containers fans are laughing at me. Thanks for the input.

                      Jon: if you're going to criticize someone for asking for an explanation to a response, I suggest you find a new hobby.

                      1 Reply Last reply
                      0

                      • Login

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