Search code examples
pythonpyqt5python-packagingfbs

Pass a .ui file created with Qt designer to fbs for packaging


i have written a Python application and I would like to distribute it. I have built a GUI on top of it and works fine so far. I use the following to set up the GUI:

qtCreatorFile = "gui.ui" 
Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)

class MyApp(QtWidgets.QMainWindow, Ui_MainWindow):
    def __init__(self):
        # Initialize parent PyQt classes
        QtWidgets.QMainWindow.__init__(self)
        self.setupUi(self)
        (....)

The application starts with the following:

if __name__ == "__main__":
     app = QtWidgets.QApplication(sys.argv)
     window = MyApp()
     window.show()
     sys.exit(app.exec_())  

If I understand correctly, for using the 'gui.ui' file withing packaging with fbs, I should load it as a resource. So I use these as a modification:

from fbs_runtime.application_context import ApplicationContext, cached_property #added to imports)

class AppContext(ApplicationContext):           # Subclass ApplicationContext
    def run(self):
        qtCreatorFile=self.get_design()    # to get the .ui file
        Ui_MainWindow, QtBaseClass = uic.loadUiType(qtCreatorFile)
        window = MyApp()
        version = self.build_settings['version']
        window.setWindowTitle("EPANET parser v" + version)
        window.show()
        return self.app.exec_()

    def get_design(self):
        qtCreatorFile=self.get_resource("gui.ui") # It is in the correct src\main\resources path
        return qtCreatorFile

    @cached_property # all tutorials suggest this , but don't understand why. ???
    def main_window(self):
        return MainWindow(self)

The fbs application should start with the following replacement of if __name__ == '__main__:':

if __name__ == '__main__':
    appctxt = AppContext()    
    exit_code = appctxt.app.exec_()
    sys.exit(exit_code)

However, I get the following error: Traceback (most recent call last): File "C:\Users\....src\main\python\main.py", line 61, in <module> class MyApp(QtWidgets.QMainWindow, Ui_MainWindow): NameError: name 'Ui_MainWindow' is not defined

I understand that the MyApp is inheriting from the Ui_MainWindow that is defined inside the AppContext class now, and MyApp cannot reference it. Any help will be greatly appreciated!


Solution

  • Instead of using uic.loadUiType() you can use uic.loadUi() that just populates the window by passing the .ui path

    main.py

    from fbs_runtime.application_context.PyQt5 import ApplicationContext, cached_property
    
    import sys
    
    from mainwindow import MyApp
    
    
    class AppContext(ApplicationContext):
        def run(self):
            self.window.resize(640, 480)
            self.window.show()
            return appctxt.app.exec_()
    
        def get_design(self):
            qtCreatorFile = self.get_resource("gui.ui")
            return qtCreatorFile
    
        @cached_property
        def window(self):
            return MyApp(self.get_design())
    
    
    if __name__ == "__main__":
        appctxt = AppContext()
        exit_code = appctxt.run()
        sys.exit(exit_code)
    

    mainwindow.py

    from PyQt5 import QtWidgets, uic
    
    
    class MyApp(QtWidgets.QMainWindow):
        def __init__(self, ui, parent=None):
            super().__init__(parent)
            uic.loadUi(ui, self)
            # ...
    
    └── src
        ├── build
        │   └── settings
        │       ├── base.json
        │       ├── linux.json
        │       └── mac.json
        └── main
            ├── icons
            │   ├── base
            │   │   ├── 16.png
            │   │   ├── 24.png
            │   │   ├── 32.png
            │   │   ├── 48.png
            │   │   └── 64.png
            │   ├── Icon.ico
            │   ├── linux
            │   │   ├── 1024.png
            │   │   ├── 128.png
            │   │   ├── 256.png
            │   │   └── 512.png
            │   ├── mac
            │   │   ├── 1024.png
            │   │   ├── 128.png
            │   │   ├── 256.png
            │   │   └── 512.png
            │   └── README.md
            ├── python
            │   ├── main.py
            │   └── mainwindow.py
            └── resources
                └── base
                    └── gui.ui