Qt Style Sheets (QSS) ist eine mächtige Funktion des Qt-Frameworks, mit der das visuelle Erscheinungsbild
von Desktop-Anwendungen vollständig angepasst werden kann. Die Syntax basiert direkt auf der aus der
Webentwicklung bekannten Stylesheet-Sprache CSS (Cascading Style Sheets). Mit QSS trennen Entwickler das
logische Design der Benutzeroberfläche von der visuellen Gestaltung. Anstatt Farben, Rahmen oder
Schriftarten direkt im Code der UI-Komponenten (Widgets) hart zu codieren, werden Gestaltungsregeln
definiert. Diese Regeln lassen sich flexibel auf die gesamte Applikation oder einzelne Fenster übertragen.
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!
#!/usr/bin/env python3
import sys
import math
import os
from PyQt6.QtWidgets import (
QApplication,
QWidget,
QLabel,
QLineEdit,
QPushButton,
QVBoxLayout,
QHBoxLayout,
QFrame,
)
from PyQt6.QtGui import QIcon
from PyQt6.QtCore import Qt
# Verzeichnis dieser Datei, damit das Icon unabhängig vom Startort gefunden wird
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ICON_PATH = os.path.join(BASE_DIR, "icon.png")
class QuadraticSolver(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("Quadratische Gleichung")
# --- Icon ---
if os.path.exists(ICON_PATH):
self.setWindowIcon(QIcon(ICON_PATH))
# --- Feste Startgröße ---
self.resize(420, 200)
# --- Größenbeschränkungen ---
# Mindestgröße: darunter würden Eingabefelder und Button zu eng werden
self.setMinimumSize(360, 160)
# Maximalgröße: das Fenster soll nicht beliebig aufreißbar sein,
# da ein reines Eingabeformular bei zu großer Fläche unproportioniert wirkt
self.setMaximumSize(700, 350)
# --- Eingabefelder für a, b, c ---
self.input_a = QLineEdit()
self.input_a.setPlaceholderText("a")
self.input_a.setObjectName("coeffInput")
self.input_b = QLineEdit()
self.input_b.setPlaceholderText("b")
self.input_b.setObjectName("coeffInput")
self.input_c = QLineEdit()
self.input_c.setPlaceholderText("c")
self.input_c.setObjectName("coeffInput")
# Formel-Labels bekommen einen eigenen Objektnamen,
# damit sie sich optisch von der Ergebnis-Anzeige unterscheiden
formula_label_1 = QLabel("x² +")
formula_label_1.setObjectName("formulaLabel")
formula_label_2 = QLabel("x +")
formula_label_2.setObjectName("formulaLabel")
formula_label_3 = QLabel("= 0")
formula_label_3.setObjectName("formulaLabel")
# 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(formula_label_1)
input_row.addWidget(self.input_b)
input_row.addWidget(formula_label_2)
input_row.addWidget(self.input_c)
input_row.addWidget(formula_label_3)
# Rahmen um die Eingabezeile, damit die Formel optisch als
# zusammengehörige Einheit erkennbar ist
input_frame = QFrame()
input_frame.setObjectName("inputFrame")
input_frame.setLayout(input_row)
# --- Button ---
self.button_calc = QPushButton("Berechnen")
self.button_calc.setObjectName("calcButton")
self.button_calc.clicked.connect(self.calculate)
self.button_calc.setCursor(Qt.CursorShape.PointingHandCursor)
# --- Ergebnis-Anzeige ---
self.result_label = QLabel("")
self.result_label.setObjectName("resultLabel")
self.result_label.setWordWrap(True)
# --- Gesamtlayout (senkrecht gestapelt) ---
main_layout = QVBoxLayout()
main_layout.addWidget(input_frame)
main_layout.addWidget(self.button_calc)
main_layout.addWidget(self.result_label)
main_layout.setContentsMargins(20, 20, 20, 20)
main_layout.setSpacing(14)
self.setLayout(main_layout)
self.apply_styles()
# Fenster mittig auf dem Bildschirm positionieren
self.center_on_screen()
def apply_styles(self):
"""Definiert das Aussehen aller Widgets über ein zentrales QSS-Stylesheet."""
self.setStyleSheet("""
/* Fensterhintergrund */
QWidget {
background-color: #f4f6fb;
font-family: "Segoe UI", Arial, sans-serif;
font-size: 14px;
}
/* Rahmen um die Eingabezeile */
QFrame#inputFrame {
background-color: #ffffff;
border: 1px solid #d0d7e6;
border-radius: 10px;
padding: 10px;
}
/* Eingabefelder a, b, c */
QLineEdit#coeffInput {
background-color: #ffffff;
border: 2px solid #c7cede;
border-radius: 6px;
padding: 6px 8px;
min-width: 50px;
max-width: 70px;
font-weight: 600;
color: #1f2937;
}
QLineEdit#coeffInput:hover {
border-color: #93a3c4;
}
QLineEdit#coeffInput:focus {
border-color: #2962bd;
background-color: #eef3fc;
}
/* Formel-Labels (x² +, x +, = 0) */
QLabel#formulaLabel {
color: #3a4257;
font-weight: 600;
background: transparent;
}
/* Berechnen-Button */
QPushButton#calcButton {
background-color: #2962bd;
color: #ffffff;
border: none;
border-radius: 8px;
padding: 10px 16px;
font-weight: 600;
}
QPushButton#calcButton:hover {
background-color: #2650a0;
}
QPushButton#calcButton:pressed {
background-color: #1e3f80;
}
/* Ergebnis-Anzeige */
QLabel#resultLabel {
background: transparent;
color: #1f2937;
font-size: 14px;
padding-top: 4px;
}
""")
def center_on_screen(self):
"""Positioniert das Fenster mittig auf dem primären Bildschirm."""
screen = QApplication.primaryScreen()
if screen is None:
return
screen_geometry = screen.availableGeometry()
window_geometry = self.frameGeometry()
center_point = screen_geometry.center()
window_geometry.moveCenter(center_point)
# move() erwartet die obere linke Ecke, daher aus window_geometry entnehmen
self.move(window_geometry.topLeft())
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()
Objektnamen statt globaler Selektoren:
Mit setObjectName("coeffInput"), [Zeile: 45, 49, 53], gebe ich Widgets einen
eindeutigen Namen, den ich im Stylesheet Mit via
QLineEdit#coeffInput { ... }, [Zeile: 124, 134, 137], gezielt anspreche – ähnlich
einer CSS-ID. Das ist wichtig, weil ein Fenster oft mehrere QLineEdit- oder QLabel-Typen enthält, die
unterschiedlich aussehen sollen (hier z. B. die Formel-Labels vs. das Ergebnis-Label).
QSS (Qt Style Sheets):
setStyleSheet(), [Zeile 107],
nimmt eine CSS-ähnliche Syntax entgegen. Zentrale Konzepte im Code: Pseudo-Zustände wie :hover, :focus, :pressed – Qt
übernimmt automatisch das Umschalten je nach Mausposition/Fokus, ganz ohne eigene Event-Handler. border-radius erzeugt
abgerundete Ecken bei Feldern, Rahmen und Button. Ich style auf Klassenebene (QWidget { ... }) für Basiswerte
wie Schriftart und Hintergrund, und überschreibe gezielt mit den #objectName-Selektoren, wo es abweichen soll.
Das ist die gleiche Kaskadierungs-Logik wie in Web-CSS.
Der Rahmen um die Eingabezeile:
Statt die drei Felder + Labels direkt ins Hauptlayout zu hängen, packe ich sie jetzt in ein
QFrame (input_frame), [Zeile 74-78]. Ein reines QHBoxLayout selbst ist nicht
"stylebar" (Layouts haben kein eigenes Aussehen), ein QFrame aber schon – daher dieser kleine Container-Trick,
um den weißen Kasten mit Rahmen um die Formel zu bekommen.
Kleine Zusatzverbesserungen:
setCursor(Qt.CursorShape.PointingHandCursor), [Zeile 84], beim Button signalisiert
visuell "klickbar". setContentsMargins() [Zeile 96] und
setSpacing() [Zeile 97] im Hauptlayout sorgen für Luft am Fensterrand und zwischen
den Elementen, statt dass alles am Rand klebt. setWordWrap(True) [Zeile 89] beim
Ergebnis-Label verhindert, dass lange Texte (z. B. die komplexe Lösung) über den Fensterrand hinauslaufen.
Warum apply_styles(), [Zeile 100, 105], als eigene Methode?
So bleibt der
Konstruktor lesbar (Struktur vs. Optik getrennt), und du kannst später z. B. einen Dark-Mode als
zweite Methode apply_dark_styles() ergänzen und je nach Bedarf umschalten.
PyQt6 Bauplan Fenster Phase 3. Ohne Gewähr © 2026 Hans Busche