Python PyQt Desktop Apps — Core Concepts

PyQt vs PySide

Both PyQt and PySide wrap the same C++ Qt framework. PyQt is maintained by Riverbank Computing under a GPL/commercial license. PySide is the official Qt Company binding under LGPL. The APIs are nearly identical — most code works with both by changing the import. This article uses “PyQt” but everything applies to PySide6 as well.

The application and window

Every Qt app needs exactly one QApplication instance and at least one widget:

from PyQt6.QtWidgets import QApplication, QMainWindow, QLabel
import sys

app = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle("First App")
window.setCentralWidget(QLabel("Hello, Qt!"))
window.resize(400, 300)
window.show()
app.exec()

QMainWindow provides a menu bar, toolbar area, status bar, and a central widget slot out of the box.

Signals and slots

Qt’s core communication pattern replaces callbacks with signals (events emitted by widgets) and slots (functions that respond):

button.clicked.connect(self.on_save)
line_edit.textChanged.connect(self.on_filter)
slider.valueChanged.connect(lcd.display)

Signals can connect to any callable — methods, lambdas, or other signals. You can also define custom signals in your own classes. This decouples the sender from the receiver and makes it easy to wire complex UIs without spaghetti code.

Layout management

Qt offers several layout classes that handle widget sizing and positioning automatically:

  • QVBoxLayout — stacks widgets vertically
  • QHBoxLayout — arranges widgets horizontally
  • QGridLayout — row/column grid, supports spanning
  • QFormLayout — label-field pairs, ideal for settings dialogs

Layouts nest inside each other. A typical form has a vertical layout containing a grid of fields, then a horizontal layout for OK/Cancel buttons at the bottom.

Essential widgets

WidgetUse case
QPushButtonStandard clickable button
QLineEditSingle-line text input
QTextEditRich-text multi-line editor
QComboBoxDropdown selection
QTableViewDisplay tabular data with a model
QTreeViewHierarchical data display
QFileDialogNative open/save file dialogs
QTabWidgetTabbed container panels
QProgressBarVisual progress indicator

Model/View architecture

For lists, tables, and trees, Qt separates data (model) from presentation (view). Instead of inserting strings into a table widget directly, you subclass QAbstractTableModel and implement rowCount(), columnCount(), and data(). The view automatically updates when the model changes, handles sorting and selection, and can display the same model in multiple views simultaneously.

This pattern scales to millions of rows — the view only requests data for visible cells.

Threading with QThread

Like all GUI frameworks, Qt’s widgets must only be modified from the main thread. For background work:

from PyQt6.QtCore import QThread, pyqtSignal

class Worker(QThread):
    progress = pyqtSignal(int)
    finished = pyqtSignal(list)

    def run(self):
        for i in range(100):
            # do work
            self.progress.emit(i + 1)
        self.finished.emit(results)

The worker emits signals that safely cross thread boundaries, and the main thread connects slots to update the UI.

Common misconception

“PyQt apps look the same on every platform.”

By default, Qt uses the native platform style — buttons, scrollbars, and menus look different on Windows, macOS, and Linux to match each OS. You can override this with app.setStyle("Fusion") for a consistent cross-platform look, or apply custom QSS (Qt Style Sheets, similar to CSS) for branded designs.

When to choose PyQt

Pick PyQt/PySide when you need polished, native-feeling desktop apps with complex widgets (tables, trees, docking panels), or when your app will grow large enough to benefit from the Model/View pattern. For simple one-dialog tools, Tkinter may be faster to start with. For GPU-heavy or game-like UIs, Dear PyGui might be a better fit.

One thing to remember: PyQt’s signals-and-slots pattern and Model/View architecture make it the go-to framework when Python desktop apps need to scale beyond simple scripts into full-featured software.

pythonpyqtguidesktopqt

See Also

  • Python Dearpygui Imagine a video game menu builder for Python — Dear PyGui uses your graphics card to draw fast, smooth interfaces for tools and dashboards.
  • Python Kivy Mobile Apps Imagine writing one recipe that works in every kitchen — Kivy lets you build a single Python app that runs on phones, tablets, and computers.
  • Python Tkinter Gui Think of building a cardboard control panel to understand how Python's built-in Tkinter lets you create windows, buttons, and text boxes without installing anything extra.
  • Ci Cd Why big apps can ship updates every day without turning your phone into a glitchy mess — CI/CD is the behind-the-scenes quality gate and delivery truck.
  • Containerization Why does software that works on your computer break on everyone else's? Containers fix that — and they're why Netflix can deploy 100 updates a day without the site going down.