#PySide6

15 posts

PySide6 in Practice #8 Release Polish: Icons, Versioning, Signing, GitHub Actions
5 min read

PySide6 in Practice #8 Release Polish: Icons, Versioning, Signing, GitHub Actions

The series finale: finishing the app into something you can hand to others. Managing icons, names, and resources with a PyInstaller spec file, defining the version in one place and feeding it to the app and the build, why unsigned apps get blocked on download and the lay of macOS notarization and Windows signing, a GitHub Actions matrix that builds for three operating systems, and a retrospective of the whole series.

PySide6 in Practice #7 Testing: pytest-qt and a Per-Layer Strategy
4 min read

PySide6 in Practice #7 Testing: pytest-qt and a Per-Layer Strategy

Dismantling the belief that GUI apps are hard to test, using the layer structure: why Qt-free core tests should be the most numerous, verifying the repository against a temp-file database, how pytest-qt's qtbot manages QApplication and the event loop for you, testing a model's contract (rowCount, data, setData), waiting on signals with waitSignal and widget interaction tests, and running Qt tests headless in CI.

PySide6 in Practice #6 The Settings Screen: QSettings, Dark Theme, Data Backup
4 min read

PySide6 in Practice #6 The Settings Screen: QSettings, Dark Theme, Data Backup

Handing the hardcoded decisions to the user: how QSettings stores values in each platform's standard location and its type traps, wiring the settings screen to live behavior (reminder hour, close-button action), dark and light themes via stylesheet swapping with system-theme detection, and the final piece of respecting user data — CSV export and database backup.

PySide6 in Practice #5 Tray Residency and Reminders: An App That Survives Its Window
5 min read

PySide6 in Practice #5 Tray Residency and Reminders: An App That Survives Its Window

Implementing the residency that turns a habit tracker into a real tool: putting an icon and menu in the system tray with QSystemTrayIcon, converting window close into hide via closeEvent and the UX debate around it, sending daily reminders at a set hour with QTimer, the limits and platform differences of tray notifications, and single-instance handling that prevents two copies of the app.

PySide6 in Practice #4 The Stats Screen: Painting a Contribution Heatmap with QPainter
5 min read

PySide6 in Practice #4 The Stats Screen: Painting a Contribution Heatmap with QPainter

Drawing the screen no stock widget provides: keeping statistics logic (completion rate, streaks) in the Qt-free core layer where it stays testable, painting a GitHub-style heatmap widget with paintEvent and QPainter, coordinate math and size handling with sizeHint, hit-testing the cell under the mouse for tooltips, and the custom-widget rule that repaints are requested through update().

PySide6 in Practice #3 The Today Screen: A Custom Model and Check Toggling
4 min read

PySide6 in Practice #3 The Today Screen: A Custom Model and Check Toggling

Building the app's first real screen: why stuffing items directly into a list widget hits its limits fast in real apps, subclassing QAbstractListModel to connect the repository to the view, exposing multiple faces of data through roles, the path a check toggle travels from view through model to database, updating views precisely with the dataChanged signal, and the add-habit dialog.

PySide6 in Practice #2 The SQLite Data Layer: Repository Pattern and Migrations
5 min read

PySide6 in Practice #2 The SQLite Data Layer: Repository Pattern and Migrations

Building the app's memory: why SQLite is the default for desktop apps, finding the OS-specific app-data folder correctly, designing the habits and checks schema, the repository pattern that confines SQL to one place, and the tiny user_version-based migration scheme that keeps user data intact across app updates.

PySide6 in Practice #1 Project Design: App Architecture Through a Habit Tracker
4 min read

PySide6 in Practice #1 Project Design: App Architecture Through a Habit Tracker

First post of a hands-on series that takes a PySide6 beginner all the way to a finished app: what we build (a local habit tracker) and why this subject, breaking feature requirements into screens, splitting code into UI, core, and data layers and why, uv-based project setup, and the main-window skeleton that will carry the next seven parts.

Build a Desktop App with PySide6 #7: Packaging and Distribution — Building Executables with PyInstaller
7 min read

Build a Desktop App with PySide6 #7: Packaging and Distribution — Building Executables with PyInstaller

Bundle the app with PyInstaller so it runs on computers without Python installed. The onedir vs onefile trade-off, including data files, platform-specific caveats, and pyside6-deploy — the final part of the series.

Build a Desktop App with PySide6 #6: Threads and Timers — Keeping the UI Responsive
6 min read

Build a Desktop App with PySide6 #6: Threads and Timers — Keeping the UI Responsive

See exactly why wiring a long task to a button freezes the whole window, then fix it with the QThread + Worker pattern — the canonical code that keeps the UI responsive. Also covers QTimer for periodic work.

Build a Desktop App with PySide6 #5: Model/View — Connecting Data to Lists and Tables
7 min read

Build a Desktop App with PySide6 #5: Model/View — Connecting Data to Lists and Tables

We hit the limits of stuffing data directly into widgets and move to Qt model/view. Subclassing QAbstractTableModel, change notification, a QSortFilterProxyModel search filter, and selection handling — all practiced on a todo table.

Build a Desktop App with PySide6 #4: Qt Designer and UI Files — Draw the Screen, Then Load It
7 min read

Build a Desktop App with PySide6 #4: Qt Designer and UI Files — Draw the Screen, Then Load It

Draw your screen with Qt Designer, which ships with PySide6, and load the .ui file in two ways: pyside6-uic and QUiLoader. We practice the code-and-screen separation workflow on the todo app form.