Using Qt Designer¶
The Qt Designer application
provides a graphical interface to generate a templated layout of Qt widgets
that can be used in an application. Two slightly different approaches have been
successful at WMKO for deploying the generated .ui XML templates.
A sample .ui file
is available, refer to the
examples for information on how to interface the template with
Python code.
Preprocessed with pyuic
¶
The pyuic
application will translate a .ui XML file into a Python class.
Note that it may be installed with a version-specific suffix, like pyuic4
or pyuic5
, as many package management systems are prepared to have multiple
versions of Qt installed. The members of the class will be appropriate PyQt
widgets, with relative names in the class matching the original naming of
the widgets in Qt Designer. These Python files can be generated via a kroot
Makefile, and installed as a Python library that can be imported for use by
the GUI application. Here is an example section from a Makefile, working with
two design templates, Main and Rotator:
DESIGNER = Main.ui Rotator.ui
SANITIZED = $(DESIGNER:%.ui=%_sanitized.ui)
SINITIZED = $(SANITIZED:%=%.sin)
TRANSLATED = $(DESIGNER:%.ui=%.py)
RELLIB = __init__.py $(TRANSLATED)
LIBSUB = python/nirspecQt
RELDAT = $(wildcard *.png)
DATSUB = nirspec/images
FILES = $(SANITIZED) $(SINITIZED) $(TRANSLATED)
$(TRANSLATED): %.py: %_sanitized.ui
pyuic $^ --output $@
# prefix *.png with @RELDIR@/data/@DATSUB/
$(SINITIZED): %_sanitized.ui.sin: %.ui
$(SED) 's/<pixmap>\(.*\).png<\/pixmap>/<pixmap>@RELDIR@\/data\/@DATSUB@\/\1.png<\/pixmap>/;s/<normaloff>\(.*\).png<\/normaloff>/<normaloff>@RELDIR@\/data\/@DATSUB@\/\1.png<\/normaloff>/' < $^ > $@ || $(RM) $@
Some of these macro definitions are kroot-specific and have implications for
which files will be installed where. In particular, note the definition of
DATSUB
here, which effectively defines a Python module name; the kpython
interpreter establishes environment variables that automatically search
$RELDIR/lib/python
when importing modules in Python code. For this
example, the GUI application would import nirspecQt
to gain access to the
templated designs.
The last target rule is doing something relatively exotic. In this rule the
relative path names for unique .png files included in the design are remapped
to their actual install location in $RELDIR/data
. So, the generation of the
.py file has dependencies:
.ui -> _sinitized.ui.sin # remapped .png paths
_sinitized.ui.sin -> _sanitized.ui # substitued for @MACRO@ values
_sanitized.ui -> .py # final generation of pyuic .py files
The nice part about getting all this done in advance is that you don’t have to worry about any of these pathing or potential translation issues at runtime, you can assume you already took care of it at build/install time.
Run-time translation¶
The PyQt5.uic.loadui()
method will effectively do the same thing as
pyuic
, but instead of the template design being an external module that you
bring in, PyQt5.uic.loadui()
will monkey-patch an existing QWidget with
the contents of the template.
One of the benefits of using this approach is that it’s more amenable to
IDE-based development, in that you can avoid the extra make install
to invoke pyuic
on the command line. The trade-off is that your code has
to work a little harder to manipulate the contents of the template on the fly.
Here is an example sequence for the just-in-time ingestion of the design template:
def setupUi(self):
reldir = os.environ['RELDIR']
filename = os.path.join(reldir, 'data', 'nirspec', 'Main.ui')
PyQt5.uic.loadUi(filename, self)