Getting started
What you need
Qt Designer ships with PySide6 as pyside6-designer; there is nothing separate
to install.
Run it
With uv and just:
just setup # install the app, PySide6 and the dev tools into .venv
just run # launch the GUI
Without just, run uv sync and then uv run python -m app, or uv run app.
Without uv, pip install -e . in an environment of your own and run
python -m app.
Check it
just check # formatter, linter, type checker; changes nothing
just test # the tests, run without a display
just fmt applies the formatting. just test runs the tests in tests/ with
pytest and pytest-qt on Qt's offscreen
platform. They click the buttons and read the widgets of the real pages. A
Python or Qt warning raised while a test runs fails it, as a failed assertion
does, and one test fails when a generated ui_*.py module is out of date with
its form. Where the installed PySide6 is not the version that generated the
modules, that test skips, or fails in CI. The tests do not show what the GUI
looks like.
A pull request into main runs just check, just test and
just docs-build in GitHub Actions.
The files
The application is the app package in src/app/.
| File | Purpose |
|---|---|
src/app/__init__.py |
The application and organisation names |
src/app/__main__.py |
Entry point for python -m app and the app command |
src/app/main_window.py |
The main window: sidebar, pages, menu, saved window size |
src/app/pages/ |
One module per page |
src/app/contacts.py |
The example data and its table model |
src/app/worker.py |
The example long task, which runs on a second thread |
src/app/theme.py |
The light and dark palettes, and the saved choice |
src/app/icons/ |
The sidebar icons, as SVG files |
src/app/ui/*.ui |
Qt Designer forms, one per window or page |
src/app/ui/ui_*.py |
Generated from the .ui files; do not edit by hand |
tests/ |
The tests behind just test |
docs/, mkdocs.yml |
This site |
How a page is put together
Every page is the same three pieces:
- A form,
ui/<name>_page.ui, drawn in Qt Designer. It holds the layout, the labels and the object name of each widget, and no colours. - A generated module,
ui/ui_<name>_page.py, whichjust uicwrites from the form. - A class in
pages/<name>.pythat builds the form and says what the widgets do:
class SettingsPage(QWidget):
def __init__(self, parent: QWidget | None = None) -> None:
super().__init__(parent)
self.ui = Ui_SettingsPage()
self.ui.setupUi(self)
self.ui.theme_combo.addItems(THEMES)
self.ui.theme_combo.setCurrentText(saved_theme())
self.ui.theme_combo.currentTextChanged.connect(self._set_theme)
The widgets are reached through self.ui, by the object names given in
Designer. MainWindow.__init__ creates each page and adds it to the sidebar.