For many of us, a shotgrid toolkit app starts with cloning tk-multi-starterapp, therefore much of the workflow is inherited from that approach.
This includes, designing with a .ui file then using
pyside-rcc to build the .ui files into python files and to pack the resources, respectively.
That's not altogether too complex but can have some speedbumps. For example, being on an M2 Mac I can't
pip install PySide2. It simply doesn't support the chipset, I can
brew install it... but that version doesn't ship with
pyside-rcc. Furthermore it sets:
Which, (again, potentially is an M2 chipset thing) doesn't point to any binaries.
sed command uses non-mac compatible syntax so
brew install gsed is necessary along with changing the command itself to
And lastly, as if that wasn't enough caveats,
pyside-uic is often called
pyside2-uic, likewise for
Wouldn't it be nice if this all just went away?
Let's walkthrough doing just that. First, we need to change our imports, we need to use some stuff that doesn't live in
sgtk.platform.qt. The toolkit docs explain how, and when to access PySide2 specific imports. The biggest change is that modules correspond to their official qt locations rather then the shotgrid amalgamation of locations mostly colocated under
from sgtk.platform.qt5 import ( QtCore, QtUiTools, QtWidgets, )
The following code takes care of the rest.
class AppDialog(QtWidgets.QWidget): """ Main application dialog window """ def __init__(self): """ Constructor """ super().__init__() self._app = sgtk.platform.current_bundle() self.ui = self._load_ui() # We can access and modify UI widgets and their attributes # just like normal. self.ui.MyLabel.setText("Yo") def _load_ui(self): # Setup resource dir resource_dir = Path(self._app.disk_location) / "resources" # Open UI File ui_file = QtCore.QFile(str(resource_dir / "dialog.ui")) ui_file.open(QtCore.QFile.ReadOnly) # Setup Loader # # by setting the resource dir as the working dir, relative # image paths from Creator will work fine. loader = QtUiTools.QUiLoader() loader.setWorkingDirectory(str(resource_dir)) # Load the UI into a property self.ui = loader.load(ui_file) # Close the UI File ui_file.close() return self.ui
That's it. No more building!
As always there are downsides to consider:
self.uiwon't have IDE introspection. I find I target few enough UI elements, or can glean the name quickly by having the point-and-click QT Creator file open that it's not a huge deal. (Or you can use
pyside2-uicto build some stubs once the UI has been more or less locked-down.)
- Performance. While I don't have any metrics to share, I'm sure dynamically spinning up the UI and not packing the resources into their binary format has an effect. Is it noticeable? Not in the types of scripts I'm running.
With Pyside6 support seemingly around the corner, and with identical support for QUiLoader, this may pose one more advantage yet: no need to also update the tooling around the app to Pyside6-uic and Pyside6-rcc. Again, not a huge imposition, but I'm a script-kiddie at heart, get this build step 'outta here.