Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Using UI files: switching from generating Python class to loading UI directly



  • Hi,

    I've been using Qt Designer for creating windows and dialogs for my app, and I've been generating Python classes as suggested in the documentation: pyside6-uic mainwindow.ui > ui_mainwindow.py.
    I found that it's also possible to load .ui files directly and I decided to try that.

    I've ran into a problem that looks similar to this: https://stackoverflow.com/questions/50128293/pyside2-quiloader-returns-an-empty-window

    I figured out how to resolve this when I launch the dialog separately, but it doesn't work when I call it from another window.

    Here's what I'm doing in my_dialog.py:

    class MyDialog(QDialog):
        def __init__(self):
            super(MyDialog, self).__init__()
            # self.ui = Ui_myDialog()
            self.ui = QUiLoader().load('ui/my_dialog.ui')
            self.ui.show()
            # self.ui.setupUi(self)
            self.initialize()
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = MyDialog()
        # window.show()
    
        sys.exit(app.exec_())
    

    The commented code is from the generated class approach. Note that if I uncomment window.show() in main() it shows an empty window and my dialog.
    Otherwise this "app" works fine by itself, but I need to open this dialog from another window.

    And when I do this like so:

    my_dialog = MyDialog()
    if my_dialog.exec_():
        <do something>
    

    It shows 2 windows - my dialog and an empty window. Why is this, how to correct this?

    Also, a more general question is: what's the best practice for working with .ui files? Is generating of Python classes preferred? What are the advantages and disadvantages of this approach?
    I have no problem with generating Python classes, but this produces extra files and an extra step in the build process so using .ui files directly seemed like a nice idea to me if I could easily switch to it.

    And finally, what's the best way for handling multiple windows/dialogs of the same class? Suppose I need to open unlimited instances of MyDialog() - what would be the best way to do this? Just call MyDialog().exec_() multiple times?

    Thanks!


  • Lifetime Qt Champion

    Hi,

    exec is a blocking call so for the unlimited part, that won't do, you can however use open.

    As for minimizing the use of files, you can also directly build your UI with code, that's one more layer removed.

    Do not call show in your init, it's not the role of your widget to show itself, that's for the code handling it to decide.



  • @midnightdim said in Using UI files: switching from generating Python class to loading UI directly:

    Also, a more general question is: what's the best practice for working with .ui files? Is generating of Python classes preferred? What are the advantages and disadvantages of this approach?
    I have no problem with generating Python classes, but this produces extra files and an extra step in the build process so using .ui files directly seemed like a nice idea to me if I could easily switch to it.

    For my own part, I much prefer generating the Python classes. You have a proper class with variables for the widgets all accessible at edit-time (e.g. code completion). With QUiLoader() your self.ui is just a black box. It is true that with Python/Creator there is an extra step in the build process (and has to be done manually whenever the .ui changes, unless it has changed now for PySide6?), which is a pain, but I still feel it is worth it. Up to you. Compare the edit-time experiences.



  • @SGaist said:

    Do not call show in your init, it's not the role of your widget to show itself, that's for the code handling it to decide.

    Thanks, I commented it out. And now I don't understand how to use my dialog. I need to _exec() it to have the accept() method save the data, but I don't understand how to do this. If I use

    if my_dialog.ui.exec_():
        <do something>
    

    It shows the dialog, but accept() doesn't seem to be called when I submit it.
    And if I use my_dialog.exec_(): it shows an empty window.


Log in to reply