PyQt6 Bauplan Fenster

Teil 1 – Grundlagen: QApplication, QWidget, QLabel, QPushButton, QLineEdit, Layouts

Quadratische Gleichung als nutzbare Anwendung

Zurück Teil 2: Zentrierung & Icon Teil 3: Qt Style Sheets Teil 4: Matplotlib-Einbettung Teil 5: Menüleiste & Dialog. Endgültige Version! Bitte Lesen

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!



PyQt6 Bauplan1


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.


Python Code
#!/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.


Python Code
#!/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.


Python Code
#!/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.


Zurück Teil 2: Zentrierung & Icon Teil 3: Qt Style Sheets Teil 4: Matplotlib-Einbettung Teil 5: Menüleiste & Dialog. Endgültige Version! Bitte Lesen