When using fbs (fman build system) to package your PyQt5 applications, your main entry point is an ApplicationContext subclass. This context object is where you typically define helper methods -- like resource loaders -- and set up your main window. But what happens when your MainWindow needs to call a method on the ApplicationContext? For example, to load a resource image using get_resource()?
This creates a small chicken-and-egg situation: your MainWindow is created inside the ApplicationContext, but it also needs a reference back to the ApplicationContext. Fortunately, the solution is straightforward -- you just pass self when creating the window.
The Problem
Here's a typical fbs project structure where the issue shows up:
import sys
from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtWidgets import QMainWindow
class MainWindow(QMainWindow):
def __init__(self, ctx):
super().__init__()
self.ctx = ctx
class AppContext(ApplicationContext):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.window = MainWindow() # Oops! Missing the context argument.
def run(self):
self.window.show()
return self.app.exec_()
def getImg(self):
return self.get_resource('sample.png')
if __name__ == '__main__':
appctxt = AppContext()
sys.exit(appctxt.run())
The MainWindow.__init__ method expects a ctx parameter, but when the window is created inside AppContext.__init__, no argument is passed. Even if you fix that, you might wonder: how can I pass the AppContext to the window, when the AppContext hasn't finished initializing yet?
The Solution: Pass self
In Python, even though __init__ hasn't finished running, the object (self) already exists by the time __init__ is called. That means you can safely pass self to other objects during initialization. The AppContext instance is fully usable as a reference -- your MainWindow just stores it for later use.
Here's the fix:
self.window = MainWindow(self) # Pass the AppContext instance to MainWindow
By passing self, your MainWindow now holds a reference to the AppContext, and can call any of its methods whenever it needs to.
Complete Working Example
Here's the full corrected code:
import sys
from fbs_runtime.application_context.PyQt5 import ApplicationContext
from PyQt5.QtWidgets import QMainWindow, QLabel, QVBoxLayout, QWidget
class MainWindow(QMainWindow):
def __init__(self, ctx):
super().__init__()
self.ctx = ctx
self.setWindowTitle("fbs App Context Example")
layout = QVBoxLayout()
# Use the context to access a resource.
img_path = self.ctx.getImg()
label = QLabel(f"Image path: {img_path}")
layout.addWidget(label)
container = QWidget()
container.setLayout(layout)
self.setCentralWidget(container)
class AppContext(ApplicationContext):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.window = MainWindow(self) # Pass self to give the window access to this context.
def run(self):
self.window.show()
return self.app.exec_()
def getImg(self):
return self.get_resource('sample.png')
if __name__ == '__main__':
appctxt = AppContext()
sys.exit(appctxt.run())
Inside MainWindow, you can now call self.ctx.getImg() or any other method defined on your AppContext. This pattern works for any number of windows or widgets -- just pass the context through to whatever component needs it.
PyQt/PySide Development Services — Stuck in development hell? I'll help you get your project focused, finished and released. Benefit from years of practical experience releasing software with Python.
Summary
When your MainWindow needs access to the ApplicationContext in an fbs project, pass self from the context when creating the window. Your window stores that reference and can use it freely to access resources, shared state, or any methods you've defined on the context. This cross-referencing pattern is common in Python and works perfectly well even during __init__.
Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 15,000 copies sold!
Packaging Python Applications with PyInstaller by Martin Fitzpatrick
This step-by-step guide walks you through packaging your own Python applications from simple examples to complete installers and signed executables.