PySide comes with the Qt Designer, a WYSIWYG GUI editor that allows you to quickly create GUIs, sparing you from having to write the boring code by hand. This designer exports the interfaces as UI files, which you can either dynamically load at runtime using the QUiLoader, or convert them beforehand with the
pyside-uic CLI tool to Python code.
I prefer the latter for two reasons: I imagine that loading, parsing and creating the GUI with the
QUiLoader at runtime will probably take time proportional to the size and complexity of the application in question. I didn’t run any benchmarks, and this might be less of an issue than I think, but I don’t see a reason why — if I can easily do so with my toolchain — I shouldn’t prefer to simply import Python code directly, entirely avoiding this potential pitfall for larger applications.
Additionally, you obviously have to work with Python code for PyCharm’s excellent code completion features to work.
Make sure to create a backup of your project before attempting to use the toolchain!
To make use of the toolchain you’ll need to install the
File Watchers plugin from within PyCharm. After doing so, download and unpack this zip file and import the file watchers contained in
convert-ui-files-and-compile-resource-files.xml (see below for information on the other files contained):
- Convert Qt Designer form files to Python modules
- Compile Qt resource files
Afterwards you’ll have to specify which files the second file watcher should monitor with a custom scope (since there’s no file type for Qt resource files in PyCharm) that matches files with the *.qrc extension.
The file watchers are kept as generic as possible, however some assumptions had to be made about the general project structure and Python setup on the system:
PySide is installed in a virtualenv.1
The converted Python UI modules will be saved with the same name and to the same directory as the UI files with the file extension
The file watcher that compiles the Qt resource files executes the
pyside-rcctool with the
-py3option, causing the compiled resource files to be compatible with Python 3, but incompatible with Python 2. If you are planning on using the latter, simply remove the option from the file watcher’s parameters after importing it.
After editing and saving the UI files (and their resources) with the designer, the file watchers should now automatically trigger and process the modified files.
There’s also a third file watcher and a small set of scripts to post-process the generated Python UI modules further. Currently they just remove the
QtCore.QMetaObject.connectSlotsByName instruction, which allows the application to run without warnings about missing slots being printed to stderr when you don’t want to use Qt’s naming conventions for your slots.3 This is all it does currently:
def remove_connect_slots_by_name(red): # [...] for node in red.find_all('name', 'connectSlotsByName'): target = node.parent.value target.replace('#' + target.dumps()) # [...]
red is a RedBaron FST.4 Instead of running the post-processing script directly, a second script is used that effectively only runs it on every second execution: The first execution modifies the file and creates a temporary marker indicating that the file has been successfully modified; the second execution deletes this marker and immediately exits the script. This might seem a bit convoluted, but it was the easiest way to prevent parsing the module with RedBaron twice (which can take a bit of time), since the file watchers will be triggered on each modification of the target files (including their own modifications to them).5
After copying the two Python scripts (from the download above) to your content root6 and importing the file watcher contained in
post-process-ui-modules.xml, you need to limit it to another custom scope that matches files with the extension
_ui.py to prevent modification of possibly unrelated files.
Incidentally this is also my first blog post: Hello World!
Please let me know if there’s anything not working, thank you.
This is important for determining the correct location of the PySide tools using PyCharm’s macros. Namely the
PyInterpreterDirectorymacro will point to the
Scriptsfolder in a virtualenv, while pointing to the Python installation folder when using the system Python installation as the configured interpreter. ↩
I assume when no sources root is configured, the compiled resource files will be simply written to the content root folder. ↩
For more information on what this does, you can check the documentation. I could simply use Qt’s naming conventions for my slots, but I prefer to stick with PEP 8 as much as possible, even if that means manually connecting the signals. ↩
Using RedBaron might be overkill, a simple .replace() would have done the job as well, but this guarantees that I only modify exactly what I expect to modify — also I got to use a really cool piece of software. Besides, I might add more processors in the future. ↩
If you have suggestions on how to handle this better, please let me know. I thought about dynamically setting and removing environment variables, but this appeared to be simpler in the end. ↩
The location is of course adjustable by modifying the program path in the file watcher. ↩
Follow me on Twitter via @ccryzed!
So what do you think? Did I miss something? Is any part unclear? Leave your comments below.