Industrial-strength Qt bindings for large, professional desktop applications.
Qt is a vast, mature C++ application framework used in commercial software worldwide β from video editors and CAD tools to embedded displays. Python accesses Qt through two binding families: PyQt (Riverbank Computing, GPL or commercial license) and PySide (official Qt Company binding, LGPL). Their APIs are nearly identical; most PyQt6 code runs on PySide6 with import renames.
Qt is far more than widgets: it includes networking, SQL, multimedia, WebEngine, charts, 3D, Bluetooth, and the declarative QML language for fluid, animated UIs.
Choose PySide6 for permissive LGPL licensing (safer for proprietary apps). Choose PyQt6 if you prefer Riverbank's ecosystem and accept GPL or buy a commercial license. Functionally they are interchangeable for most projects.
app.exec().QVBoxLayout, QHBoxLayout, QGridLayout, QFormLayout replace manual positioning.button.clicked.connect(handler).QTableView, QTreeView bind to data models for large datasets..ui files loaded with QUiLoader or converted to Python.| Module | Contains |
|---|---|
QtWidgets | Buttons, labels, tables, dialogs, main windows |
QtCore | Signals, timers, threads, file I/O, settings |
QtGui | Fonts, colors, icons, images, clipboard |
QtCharts | Line, bar, pie charts (add-on module) |
QtMultimedia | Audio/video playback and capture |
QtWebEngineWidgets | Embedded Chromium browser |
pip install PySide6 # recommended for most projects
pip install PySide6-Addons # charts, web engine, etc.
# Alternative:
pip install PyQt6
# Optional: Qt Designer is included; run:
pyside6-designer
import sys
from PySide6.QtWidgets import QApplication, QWidget, QPushButton, QVBoxLayout, QLabel
app = QApplication(sys.argv)
win = QWidget()
win.setWindowTitle("PySide6 demo")
layout = QVBoxLayout(win)
label = QLabel("Counter: 0")
button = QPushButton("Increment")
layout.addWidget(label)
layout.addWidget(button)
count = {"n": 0}
def bump():
count["n"] += 1
label.setText(f"Counter: {count['n']}")
button.clicked.connect(bump)
win.show()
sys.exit(app.exec())
import sys
from PySide6.QtWidgets import (
QApplication, QMainWindow, QTextEdit, QMenuBar
)
from PySide6.QtGui import QAction
class Editor(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Simple Editor")
self.editor = QTextEdit()
self.setCentralWidget(self.editor)
bar = self.menuBar()
file_menu = bar.addMenu("File")
quit_action = QAction("Quit", self)
quit_action.triggered.connect(self.close)
file_menu.addAction(quit_action)
app = QApplication(sys.argv)
win = Editor()
win.resize(600, 400)
win.show()
sys.exit(app.exec())
Never block the GUI thread. Use QThread and signals to update the UI when work finishes.
from PySide6.QtCore import QThread, Signal
from PySide6.QtWidgets import QPushButton, QLabel, QVBoxLayout, QWidget
import time
class Worker(QThread):
finished = Signal(str)
def run(self):
time.sleep(2)
self.finished.emit("Done!")
class Window(QWidget):
def __init__(self):
super().__init__()
self.label = QLabel("Idle")
btn = QPushButton("Start")
btn.clicked.connect(self.start)
QVBoxLayout(self).addWidget(self.label)
self.layout().addWidget(btn)
def start(self):
self.label.setText("Workingβ¦")
self.worker = Worker()
self.worker.finished.connect(self.label.setText)
self.worker.start()
QSettings to persist window size, recent files, and preferences..ui files from Qt Designer for faster iteration on layout.QFormLayout for aligned label-field pairs.qasync to integrate asyncio with the Qt event loop.Building a serious, complex, long-lived desktop application that needs rich widgets, maintainable structure, and professional polish. Avoid for tiny scripts or mobile-first projects.
Useful guides and tools (from webpage_links.xlsx).