Diese Webseite ist eine kleine Lernreihe zu PyQt6, die ich mir im Laufe der Jahre zusammengestellt
habe. Quasi vom Einsteiger bis zu einer kompletten Anwendung. Beginnen wir mit einer Applikation
"Quadratische Gleichung". Dabei würde jedes Kapitel auf dem vorherigen aufbauen und ein vollständiges,
lauffähiges Beispiel enthalten, fast wie ein kleines Lehrbuch. Ich denke, das wäre eine sehr praxisnahe
Möglichkeit, PyQt6 systematisch zu lernen. Ein guter Ansatz ist, PyQt6 wie einen Baukasten zu betrachten.
Du schreibst das komplette Fenster direkt in Python, ohne den Qt-Designer. Sobald du das Prinzip
Widget → Layout → Signal → Slot verstanden hast, lassen sich auch komplexere Programme Schritt
für Schritt aufbauen.
Ich möchte die Lernreihe so aufbauen, dass sie nicht nur zeigt, wie etwas funktioniert, sondern auch, warum.
Das macht es später viel einfacher, eigene Programme zu entwickeln. Stell dir vor, wir bauen ein Haus, zuerst
das Fundament, dann die Einrichtung und zum Schluss die Extras. Los geht’s!
Diese Webseite stellt für den Quellcode Download- und Kopierfunktionen zur Verfügung. Das geht nur mit JavaScript.
Wenn du mich für einen unsicheren Kantonisten hältst, verlasse diese Webseite. Alle Informationen und Angebote
sind ohne Gewähr!
Für die Anwendung „Quadratische Gleichung“ habe ich drei verschiedene Oberflächen gebaut. Dieses Kapitel,
PyQt6-Grundlagen-Teil 1, behandelt Layouts. Weiter unten in dieser Beschreibung findest du den Quellcode.
Einige Begriffe, wie QHBoxLayout/QVBoxLayout, wiederholen sich laufend, das ist bewusst so gemacht.
Die Layout-Klassen QHBoxLayout, QVBoxLayout und QFormLayout stammen aus dem Qt-Framework und dienen der
automatischen Anordnung (Geometrieverwaltung) von grafischen Elementen (Widgets) wie Buttons, Textfeldern
oder Labels in Benutzeroberflächen.
QHBoxLayout (Horizontal Box Layout)Funktion: Ordnet Widgets in einer horizontalen Reihe nebeneinander an
(von links nach rechts). Anwendungsbereich: Perfekt für nebeneinanderliegende Elemente, beispielsweise
eine Reihe von Buttons (wie "Speichern" und "Abbrechen") am unteren Rand eines Fensters oder eine Toolbar.
Beispiel: layout->addWidget(button1); layout->addWidget(button2).
QVBoxLayout (Vertical Box Layout)Funktion: Ordnet Widgets vertikal untereinander an (von oben nach unten).
Anwendungsbereich: Ideal für Formulare oder Stapel von Elementen, bei denen ein Widget das nächste logisch
fortführt.Beispiel: Das Menü links, darunter ein Eingabefeld, darunter ein Button.
QFormLayout (Formular-Layout)Funktion: Ordnet Widgets in einem zweispaltigen Raster an. Die linke Spalte ist
typischerweise für Beschriftungen (Labels) reserviert, während die rechte Spalte die Eingabefelder enthält.
Anwendungsbereich: Der Standard für klassische Eingabemasken und Formulare (z. B. Benutzername, Passwort, E-Mail).
Besonderheit: Es kümmert sich automatisch um die Ausrichtung der Beschriftungen, damit das Formular sauber
und professionell aussieht. Beispiel: layout->addRow("Name:", lineEditName);
Was wir hier behandeln: ➔ Eine eigene Fensterklasse erstellen. ➔ Widgets erzeugen. ➔ Widgets mit Layouts anordnen.
➔ Einen Button mit einer Methode verbinden. ➔ Das Fenster strukturiert aufbauen.
Struktur der Klasse Quadratische Gleichung: QuadraticSolver erbt von QWidget - das ist die Basis für jedes
eigenständige Fenster in PyQt6. Im Konstruktor (__init__) passiert alles Wichtige: Eingabefelder (QLineEdit):
Statt fester Labels benutze ich setPlaceholderText(), sodass "a", "b", "c" im leeren Feld als Platzhalter
erscheinen, das spart Platz und wirkt aufgeräumter. Layouts statt fester Koordinaten: QHBoxLayout reiht die
Felder horizontal (a x² + b x + c = 0), QVBoxLayout stapelt dann Eingabezeile, Button und Ergebnis-Label
vertikal übereinander. Das ist der PyQt6-Standardweg, nie mit move(x, y) arbeiten, sondern Layouts nutzen,
damit sich das Fenster bei Größenänderung sauber anpasst. Signal/Slot-Verbindung:
self.button_calc.clicked.connect(self.calculate) – das ist das Herzstück von Qt's Ereignissystem. Der Button
sendet bei Klick das Signal clicked, und dieses ist mit der Methode calculate verbunden (dem "Slot").
Berechnung: Ich fange ungültige Eingaben mit try/except ValueError ab, prüfe a == 0 gesondert und unterscheide
die drei Fälle der Diskriminante (zwei Lösungen, eine Lösung, komplexe Lösungen). Kommas werden automatisch zu
Punkten konvertiert, falls jemand "1,5" statt "1.5" eingibt. main()-Funktion: QApplication verwaltet die
Event-Loop der gesamten Anwendung (nur eine Instanz pro Programm!), window.show() macht das Fenster sichtbar,
app.exec() startet die Event-Loop, die auf Benutzerinteraktionen wartet.
Die Programme sind bewusst in drei Bereiche aufgeteilt: MainWindow ➔ create_widgets() ➔ create_layout()
➔ create_connections(). Diese Aufteilung findest du in vielen professionellen PyQt-Projekten. Sie macht den
Code übersichtlich und erleichtert spätere Erweiterungen.
create_widgets() ➔ Hier werden alle sichtbaren Elemente erstellt. ➔ QLabel (Textbeschriftung) ➔ QLineEdit
(Eingabefeld) ➔ QPushButton (Schaltfläche).
create_layout() ➔ Hier wird festgelegt, wo die Widgets erscheinen. ➔ Für jede Eingabezeile verwenden wir
ein QHBoxLayout. ➔ Diese drei Zeilen werden anschließend untereinander in ein QVBoxLayout eingefügt. So entsteht
automatisch ein sauber angeordnetes Fenster, das sich bei einer Größenänderung sinnvoll anpasst.
create_connections() ➔ Hier werden Signale mit Funktionen verbunden. ➔ self.btnBerechnen.clicked.connect(self.button_clicked)
Das bedeutet: Wenn auf den Button geklickt wird, rufe button_clicked() auf. Dieses Signal-/Slot-Prinzip ist
eines der wichtigsten Konzepte in Qt.
button_clicked() ➔ Im Moment macht die Funktion nur Folgendes: ➔ die Werte für a, b und c auslesen. Die
Diskriminante berechnen. Die Nullstellen bestimmen. Den Scheitelpunkt berechnen. Später bauen wir weitere
Funktionen ein, z.B. den Graphen aktualisieren.
#!/usr/bin/env python3
# *****************************************************************************
# PyQt6 Fenster Bauplan -1- (kein Qt Designer / .ui-Datei).
# Installation der Abhängigkeit: pip install PyQt6
# Start: python pyqt6_pq_V1.py (c) Hans Busche Datum: 21.07.2026
# *****************************************************************************
import sys
import math
from PyQt6.QtWidgets import (QApplication, QWidget, QVBoxLayout,
QHBoxLayout, QLabel, QLineEdit, QPushButton, QMessageBox)
class QuadraticEquationSolver(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
# Hauptfenster
self.setWindowTitle('Quadratische Gleichungen')
self.resize(450, 200)
# Layouts
main_layout = QVBoxLayout()
# Eingabeaufforderung
instruction = QLabel("Gib den Koeffizienten für " \
"ax² + bx + c = 0 ein:")
main_layout.addWidget(instruction)
# Eingabefelder für a, b, c
input_layout = QHBoxLayout()
self.input_a = QLineEdit()
self.input_a.setPlaceholderText("a")
self.input_b = QLineEdit()
self.input_b.setPlaceholderText("b")
self.input_c = QLineEdit()
self.input_c.setPlaceholderText("c")
input_layout.addWidget(QLabel("a:"))
input_layout.addWidget(self.input_a)
input_layout.addWidget(QLabel("b:"))
input_layout.addWidget(self.input_b)
input_layout.addWidget(QLabel("c:"))
input_layout.addWidget(self.input_c)
main_layout.addLayout(input_layout)
# Berechnen-Button
self.btn_calc = QPushButton('Berechnen')
self.btn_calc.clicked.connect(self.solve_equation)
main_layout.addWidget(self.btn_calc)
# Ausgabefeld
self.lbl_result = QLabel("Ergebnis: -")
self.lbl_result.setStyleSheet("font-weight: bold; " \
"font-size: 14px; padding: 10px;")
main_layout.addWidget(self.lbl_result)
self.setLayout(main_layout)
def solve_equation(self):
try:
# Werte auslesen und Eingaben konvertieren
a = float(self.input_a.text())
b = float(self.input_b.text())
c = float(self.input_c.text())
except ValueError:
QMessageBox.warning(self, "Fehler", "Gültige Zahlen eingeben.")
return
if a == 0:
QMessageBox.warning(self, "Fehler", "Der Koeffizient 'a' darf " \
"nicht 0 sein. Es handelt sich sonst nicht um eine " \
"quadratische Gleichung.")
return
# Diskriminante berechnen: D = b² - 4ac
discriminant = (b**2) - (4 * a * c)
if discriminant > 0:
# Zwei Lösungen
x1 = (-b + math.sqrt(discriminant)) / (2 * a)
x2 = (-b - math.sqrt(discriminant)) / (2 * a)
self.lbl_result.setText(f"Zwei Lösungen:\nx₁ = {x1:.3f}\nx₂ = {x2:.3f}")
elif discriminant == 0:
# Genau eine Lösung
x = -b / (2 * a)
self.lbl_result.setText(f"Eine eindeutige Lösung:\nx = {x:.3f}")
else:
# Keine reellen Lösungen
self.lbl_result.setText("Keine reellen Lösungen\n(Die " \
"Diskriminante ist negativ).")
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = QuadraticEquationSolver()
ex.show()
sys.exit(app.exec())
# *****************************************************************************
# Ende
# *****************************************************************************
Python Code zum Fenster 1, vorerst interessiert uns nur die Layout-Technik:
In diesem Code steuert PyQt6 die Anordnung der Elemente über zwei unsichtbare Boxen, die wie
Bausteine ineinander gestapelt sind. Hier ist die einfache Erklärung, wie diese Layout-Technik
im Programm funktioniert:
QVBoxLayout (Vertikal): Ordnet Elemente von oben nach unten an.
QHBoxLayout (Horizontal): Ordnet Elemente von links nach rechts an.
Der Aufbau im Code (Schritt für Schritt):
Die Haupt-Box (main_layout, Zeile 23): Das ist ein vertikales Layout
(QVBoxLayout). Alles, was hier hineinkommt, wird untereinander gestapelt.
Die erste Reihe (Text, Zeile 25): Der Text „Gib den Koeffizienten...“ wird oben in die Haupt-Box gelegt.
Die zweite Reihe (Die Schachtel-Technik): Hier wird ein horizontales Layout
(input_layout, Zeile 29) erstellt. Die Beschriftungen und Eingabefelder
für a, b und c werden darin nebeneinander aufgereiht. Danach wird diese
ganze Reihe als ein Baustein in die Haupt-Box eingefügt
(main_layout.addLayout, Zeile 42).
Die dritte Reihe (Button): Der „Berechnen“-Knopf wird unter den Eingabefeldern in die Haupt-Box gelegt.
Die vierte Reihe (Ergebnis): Das Ergebnisfeld bildet den Abschluss ganz unten.
Mit (self.setLayout(main_layout), Zeile 52) wird dem Fenster gesagt:
„Nutze diese gestapelte Haupt-Box als Bauplan.“ Der Vorteil dieser Technik ist, dass sich alle Felder
automatisch sauber verschieben, wenn du die Größe des Fensters mit der Maus veränderst.
#!/usr/bin/env python3
# *****************************************************************************
# PyQt6 Fenster Bauplan -2- (kein Qt Designer / .ui-Datei).
# Installation der Abhängigkeit: pip install PyQt6
# Start: python pyqt6_pq_V2.py (c) Hans Busche Datum: 19.07.2026
# *****************************************************************************
import sys
import math
from PyQt6.QtWidgets import (
QApplication,
QWidget,
QLabel,
QLineEdit,
QPushButton,
QVBoxLayout,
QHBoxLayout,
)
class QuadraticSolver(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Quadratische Gleichung")
# --- Eingabefelder für a, b, c ---
self.input_a = QLineEdit()
self.input_a.setPlaceholderText("a")
self.input_b = QLineEdit()
self.input_b.setPlaceholderText("b")
self.input_c = QLineEdit()
self.input_c.setPlaceholderText("c")
# Zeile mit den drei Eingabefeldern nebeneinander,
# dazwischen kleine Labels zur Lesbarkeit der Formel
input_row = QHBoxLayout()
input_row.addWidget(self.input_a)
input_row.addWidget(QLabel("x² +"))
input_row.addWidget(self.input_b)
input_row.addWidget(QLabel("x +"))
input_row.addWidget(self.input_c)
input_row.addWidget(QLabel("= 0"))
# --- Button ---
self.button_calc = QPushButton("Berechnen")
self.button_calc.clicked.connect(self.calculate)
# --- Ergebnis-Anzeige ---
self.result_label = QLabel("")
# --- Gesamtlayout (senkrecht gestapelt) ---
main_layout = QVBoxLayout()
main_layout.addLayout(input_row)
main_layout.addWidget(self.button_calc)
main_layout.addWidget(self.result_label)
self.setLayout(main_layout)
def calculate(self):
#Liest a, b, c aus, prüft die Eingabe und berechnet die Nullstellen.
try:
a = float(self.input_a.text().replace(",", "."))
b = float(self.input_b.text().replace(",", "."))
c = float(self.input_c.text().replace(",", "."))
except ValueError:
self.result_label.setText("Bitte gültige Zahlen " \
"für a, b und c eingeben.")
return
if a == 0:
self.result_label.setText("a darf nicht 0 " \
"sein (sonst keine quadratische Gleichung).")
return
diskriminante = b**2 - 4 * a * c
if diskriminante > 0:
x1 = (-b + math.sqrt(diskriminante)) / (2 * a)
x2 = (-b - math.sqrt(diskriminante)) / (2 * a)
self.result_label.setText(f"Zwei Lösungen: x1 = {x1:.4g}, x2 = {x2:.4g}")
elif diskriminante == 0:
x = -b / (2 * a)
self.result_label.setText(f"Eine Lösung: x = {x:.4g}")
else:
realteil = -b / (2 * a)
imagteil = math.sqrt(-diskriminante) / (2 * a)
self.result_label.setText(
f"Keine reelle Lösung: x1 = {realteil:.4g} + {imagteil:.4g}i, "
f"x2 = {realteil:.4g} - {imagteil:.4g}i"
)
def main():
app = QApplication(sys.argv)
window = QuadraticSolver()
window.show()
sys.exit(app.exec())
if __name__ == "__main__":
main()
Python Code zum Fenster 2, die Layout-Technik ist mit Fenster 1
nahezu identisch. Hier tauchen wir etwas tiefer in die Struktur ein:
QuadraticSolver, Zeile20, erbt von QWidget - das ist die
Basis für jedes eigenständige Fenster in PyQt6. Im Konstruktor
(__init__), Zeile 21, passiert alles Wichtige:
Eingabefelder (QLineEdit): Statt fester Labels benutze ich
setPlaceholderText(), Zeile 26, 28, 30, sodass "a", "b", "c"
im leeren Feld als Platzhalter erscheinen, das spart Platz und wirkt aufgeräumter.
Layouts statt fester Koordinaten: QHBoxLayout reiht die Felder horizontal (a x² + b x + c = 0),
QVBoxLayout stapelt dann Eingabezeile, Button und Ergebnis-Label vertikal übereinander.
Das ist der PyQt6-Standardweg, nie mit move(x, y) arbeiten, sondern Layouts nutzen,
damit sich das Fenster bei Größenänderung sauber anpasst.
Signal/Slot-Verbindung: self.button_calc.clicked.connect(self.calculate) – das ist das
Herzstück von Qt's Ereignissystem. Der Button sendet bei Klick das Signal clicked,
und dieses ist mit der Methode calculate verbunden (dem "Slot"). Berechnung: Ich
fange ungültige Eingaben mit try/except ValueError ab, prüfe a == 0 gesondert
und unterscheide die drei Fälle der Diskriminante (zwei Lösungen, eine Lösung,
komplexe Lösungen). Kommas werden automatisch zu Punkten konvertiert, falls
jemand "1,5" statt "1.5" eingibt. main()-Funktion: QApplication verwaltet
die Event-Loop der gesamten Anwendung (nur eine Instanz pro Programm!), window.show()
macht das Fenster sichtbar, app.exec() startet die Event-Loop, die auf
Benutzerinteraktionen wartet.
#!/usr/bin/env python3
# *****************************************************************************
# PyQt6 Fenster Bauplan -3- (kein Qt Designer / .ui-Datei).
# Installation der Abhängigkeit: pip install PyQt6
# Start: python pyqt6_pq_V3.py (c) Hans Busche Datum: 12.07.2026
# *****************************************************************************
import sys
import math
from PyQt6.QtWidgets import (
QApplication, QMainWindow, QWidget, QVBoxLayout,
QFormLayout, QLineEdit, QPushButton, QLabel
)
from PyQt6.QtCore import Qt
class QuadraticSolver(QMainWindow):
def __init__(self):
super().__init__()
# Fenster-Titel und Standardgröße
self.setWindowTitle("Quadratische Gleichungen Löser")
self.resize(400, 250)
# Haupt-Widget und Layout setzen
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout()
central_widget.setLayout(main_layout)
# Formular-Layout für die Parameter a, b und c
form_layout = QFormLayout()
self.input_a = QLineEdit()
self.input_a.setPlaceholderText("z. B. 1")
form_layout.addRow("Parameter a:", self.input_a)
self.input_b = QLineEdit()
self.input_b.setPlaceholderText("z. B. -3")
form_layout.addRow("Parameter b:", self.input_b)
self.input_c = QLineEdit()
self.input_c.setPlaceholderText("z. B. 2")
form_layout.addRow("Parameter c:", self.input_c)
main_layout.addLayout(form_layout)
# Berechnen-Button
self.calc_button = QPushButton("Berechnen")
# Signal und Slot verbinden (Button-Klick ruft Funktion auf)
self.calc_button.clicked.connect(self.calculate)
main_layout.addWidget(self.calc_button)
# Ergebnis-Label
self.result_label = QLabel("Gib die Werte ein und klicke auf 'Berechnen'.")
self.result_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.result_label.setWordWrap(True)
main_layout.addWidget(self.result_label)
def calculate(self):
"""Löst die quadratische Gleichung ax^2 + bx + c = 0"""
try:
# Eingaben auslesen und in Fließkommazahlen (float) umwandeln
a = float(self.input_a.text().replace(',', '.'))
b = float(self.input_b.text().replace(',', '.'))
c = float(self.input_c.text().replace(',', '.'))
if a == 0:
self.result_label.setText("Fehler: 'a' darf " \
"nicht 0 sein (keine quadratische Gleichung).")
return
# Diskriminante D = b² - 4ac
d = b**2 - 4*a*c
# Scheitelpunkt berechnen: S(xs, ys)
xs = -b / (2 * a)
ys = c - (b**2 / (4 * a))
if d > 0:
x1 = (-b + math.sqrt(d)) / (2 * a)
x2 = (-b - math.sqrt(d)) / (2 * a)
result_text = (
f"Zwei reale Nullstellen:
"
f"x₁ = {x1:.4f}
x₂ = {x2:.4f}
"
f"Scheitelpunkt: S({xs:.2f} | {ys:.2f})"
)
elif d == 0:
x1 = -b / (2 * a)
result_text = (
f"Eine doppelte Nullstelle:
"
f"x = {x1:.4f}
"
f"Scheitelpunkt: S({xs:.2f} | {ys:.2f})"
)
else:
result_text = (
f"Keine reellen Nullstellen (D < 0).
"
f"Scheitelpunkt: S({xs:.2f} | {ys:.2f})"
)
self.result_label.setText(result_text)
except ValueError:
self.result_label.setText("Fehler: Bitte gültige " \
"Zahlen für a, b und c eingeben.")
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QuadraticSolver()
window.show()
sys.exit(app.exec())
Python Code zum Fenster 3, die Layout-Technik. „Mehrere Wege führen nach Rom“:
In dieser ersten Phase bauen wir die Logik für die quadratische Gleichung (ax² + bx + c = 0) und das
funktionale GUI-Layout mit Eingabefeldern, Berechnungs-Button und Ausgabefeld. Wenn wir das Grundgerüst von
Anfang an auf QMainWindow aufbauen, lassen sich spätere Features wie Menüleisten (Teil 5) oder Plots (Teil 4)
ohne großen Umbau nahtlos integrieren.
Erläuterung der Bausteine: QMainWindow & Central Widget. Ein QMainWindow benötigt ein zentrales Widget
(setCentralWidget), in dem alle Unterelemente (Layouts, Eingabefelder, Buttons) abgelegt werden.
Layouts (QVBoxLayout & QFormLayout): QFormLayout ist ideal für Formulare, da es Beschriftungen
(Labels) und Eingabefelder automatisch sauber nebeneinander ausrichtet. QVBoxLayout ordnet Formular,
Button und Ergebnis vertikal untereinander an.
Signale und Slots (clicked.connect): PyQt6 arbeitet mit dem Signal/Slot-Prinzip. Wenn der Anwender
auf den Button drückt (clicked), wird die Methode self.calculate ausgeführt.
Fehlerbehandlung: Mit try-except fangen wir Falscheingaben ab (z. B. Buchstaben statt Zahlen oder
leere Felder), damit die Anwendung nicht abstürzt.
PyQt6 Bauplan Fenster. Ohne Gewähr © 2026 Hans Busche