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. PySide2: Best practice for using modal dialog loaded from a .ui file
Forum Updated to NodeBB v4.3 + New Features

PySide2: Best practice for using modal dialog loaded from a .ui file

Scheduled Pinned Locked Moved Unsolved Qt for Python
2 Posts 3 Posters 2.2k Views 1 Watching
  • 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.
  • Doug WoodD Offline
    Doug WoodD Offline
    Doug Wood
    wrote on last edited by
    #1

    Hi All,

    I was having a difficult time getting a simple modal dialog to work in PySide2 when loading the dialog from a .ui file and so I am writing this post for some advice/feedback on my solution.

    The context is that I have a main window, which is itself a single dialog widget and I wanted to open the modal dialog after the user clicks a button in the main dialog. Simple, right? I originally put the code for launching the sub dialog in the slot connected to the pressed signal of the button in the main dialog, but lots of things went wrong, like multiple copies of the sub dialog appearing on screen -- it seemed like the slot was getting called twice somehow, but if I commented out just the code to open the subdialog, it was not getting called twice. Weird.

    I eventually figured out that one has to instantiate the sub dialog object OUTSIDE the slot that tries to use it. Do not create the dialog object from the .ui file inside a slot and then try to use it immediately in that slot. I don't recall if this is an issue with Qt in C++. Perhaps it is and I forgot about this "rule."

    So now I am creating the instance of the sub dialog class as a member variable in the init of of the main dialog class, then using the member variable in the slot called then the user presses a button in the main dialog and things are working OK now. If this is what one needs to do, then I think It would be very good to note this clearly in the online docs about QDialog and QUiLoader.

    As for best practices, I find it awkward (see code below) to have to manage the object tree that comes out of QUiLoader as a separate member variable (self.window or self.ui) inside an object that is already a QDialog. Is there anyway to get QUiLoader to load the UI directly into an object which is a subclass of QDialog, or to create a QDialog from a .ui file?

    Here is a snippet of my code for creating the sub dialog class:

    class USlideIDsListDialog(QDialog):
        def __init__(self, parent=None):
            super(USlideIDsListDialog, self).__init__(parent)
            loader = QUiLoader()
            uifile = QFile(os.path.abspath("slide_list_dialog.ui"))
            if uifile.open(QFile.ReadOnly):
                self.window = loader.load(uifile, parent)
                uifile.close()
                self.window.doneButton.pressed.connect(self.do_done)
                self.window.cancelButton.pressed.connect(self.do_cancel)
    # more window initialization here...
    
        def show(self):
            self.window.show()
    
        def exec_(self):
            self.window.exec_()
    
        def do_cancel(self):
          # do nothing, no changes to settings
            self.window.close()
            self.reject()
    
        def do_done(self):
            # code to save some stuff to the settings goes here...
            self.window.close()
            self.accept()
    

    Then, in the script for the main dialog window I have this slot which is called when the user presses a button in the main dialog (to open the sub dialog window):

        @Slot()
        def do_slide_list_dialog(self):
            self.slide_list_dialog.show()
            self.slide_list_dialog.exec_()
            print(self.slide_list_dialog.result())
    

    Note: the .ui file has a QDialog object at its root and the QDialog is set in creator as Application Modal.

    Is there a better way to do this in PySide2?

    Thank you for your feedback,
    Doug

    JonBJ 1 Reply Last reply
    0
    • Doug WoodD Doug Wood

      Hi All,

      I was having a difficult time getting a simple modal dialog to work in PySide2 when loading the dialog from a .ui file and so I am writing this post for some advice/feedback on my solution.

      The context is that I have a main window, which is itself a single dialog widget and I wanted to open the modal dialog after the user clicks a button in the main dialog. Simple, right? I originally put the code for launching the sub dialog in the slot connected to the pressed signal of the button in the main dialog, but lots of things went wrong, like multiple copies of the sub dialog appearing on screen -- it seemed like the slot was getting called twice somehow, but if I commented out just the code to open the subdialog, it was not getting called twice. Weird.

      I eventually figured out that one has to instantiate the sub dialog object OUTSIDE the slot that tries to use it. Do not create the dialog object from the .ui file inside a slot and then try to use it immediately in that slot. I don't recall if this is an issue with Qt in C++. Perhaps it is and I forgot about this "rule."

      So now I am creating the instance of the sub dialog class as a member variable in the init of of the main dialog class, then using the member variable in the slot called then the user presses a button in the main dialog and things are working OK now. If this is what one needs to do, then I think It would be very good to note this clearly in the online docs about QDialog and QUiLoader.

      As for best practices, I find it awkward (see code below) to have to manage the object tree that comes out of QUiLoader as a separate member variable (self.window or self.ui) inside an object that is already a QDialog. Is there anyway to get QUiLoader to load the UI directly into an object which is a subclass of QDialog, or to create a QDialog from a .ui file?

      Here is a snippet of my code for creating the sub dialog class:

      class USlideIDsListDialog(QDialog):
          def __init__(self, parent=None):
              super(USlideIDsListDialog, self).__init__(parent)
              loader = QUiLoader()
              uifile = QFile(os.path.abspath("slide_list_dialog.ui"))
              if uifile.open(QFile.ReadOnly):
                  self.window = loader.load(uifile, parent)
                  uifile.close()
                  self.window.doneButton.pressed.connect(self.do_done)
                  self.window.cancelButton.pressed.connect(self.do_cancel)
      # more window initialization here...
      
          def show(self):
              self.window.show()
      
          def exec_(self):
              self.window.exec_()
      
          def do_cancel(self):
            # do nothing, no changes to settings
              self.window.close()
              self.reject()
      
          def do_done(self):
              # code to save some stuff to the settings goes here...
              self.window.close()
              self.accept()
      

      Then, in the script for the main dialog window I have this slot which is called when the user presses a button in the main dialog (to open the sub dialog window):

          @Slot()
          def do_slide_list_dialog(self):
              self.slide_list_dialog.show()
              self.slide_list_dialog.exec_()
              print(self.slide_list_dialog.result())
      

      Note: the .ui file has a QDialog object at its root and the QDialog is set in creator as Application Modal.

      Is there a better way to do this in PySide2?

      Thank you for your feedback,
      Doug

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

      @Doug-Wood
      I'm struggling to understand the situation you are in.

      You are not supposed to have create a "holding" QDialog which then has a self.window member which is the actual dialog, if that is what you are saying.

      but lots of things went wrong, like multiple copies of the sub dialog appearing on screen -- it seemed like the slot was getting called twice somehow, but if I commented out just the code to open the subdialog, it was not getting called twice. Weird.

      I eventually figured out that one has to instantiate the sub dialog object OUTSIDE the slot that tries to use it. Do not create the dialog object from the .ui file inside a slot and then try to use it immediately in that slot. I don't recall if this is an issue with Qt in C++. Perhaps it is and I forgot about this "rule."

      Not sure, you would have to explain. But in any case I'm not sure I'd want to be creating a dialog out of QUiLoader.load(ui_file) each time I'm about to show it, I'd probably create it once and then re-use it.

      I don't do things via QUiLoader, I prefer having pyside2-uic generate a Python class. I don't know if you have looked at that, or if you wish to use QUiLoader.

      1 Reply Last reply
      1

      • Login

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