ttkbootstrap für Anfänger
Moderne Python GUIs mit Bootstrap-Look — Schritt für Schritt
1 · Was ist ttkbootstrap?
ttkbootstrap ist eine Python-Bibliothek, die die Standard-GUI tkinter mit modernen Bootstrap-Themes aufwertet. Statt grauer Systemdialoge bekommst du schöne, professionelle Oberflächen — mit minimalem Aufwand.
20+ Themes
Alle tkinter-Widgets
Drop-in-Ersatz
Open Source
tkinter kennst, musst du fast nichts Neues lernen — ttkbootstrap ist ein direkter Ersatz mit besserem Aussehen.2 · Installation
ttkbootstrap lässt sich mit pip in Sekunden installieren. Python 3.8 oder höher wird benötigt.
pip install ttkbootstrap
pip3 install ttkbootstrap.Installation prüfen
import ttkbootstrap as ttk print(ttk.__version__) # z.B. 1.10.1
Empfohlene Entwicklungsumgebungen
| Editor | Ideal für | Link |
|---|---|---|
| VS Code | Alle Levels | code.visualstudio.com |
| PyCharm CE | Fortgeschrittene | jetbrains.com/pycharm |
| Thonny | Anfänger | thonny.org |
3 · Erstes Fenster
Ein einfaches ttkbootstrap-Fenster benötigt nur wenige Zeilen. Der wichtigste Unterschied zu tkinter: ttk.Window statt tk.Tk().
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
# Fenster erstellen (Theme: "darkly" für dunkles Design)
app = ttk.Window(
title="Mein erstes Fenster",
themename="darkly",
size=(400, 300)
)
# Label
label = ttk.Label(app, text="Hallo ttkbootstrap!", font=("Helvetica", 16))
label.pack(pady=20)
# Button
button = ttk.Button(app, text="Klick mich!", bootstyle=PRIMARY)
button.pack(pady=10)
# Fenster starten
app.mainloop()
Fenster-Optionen
app = ttk.Window(
title="Meine App", # Fenstertitel
themename="darkly", # Theme
size=(600, 400), # Breite x Höhe in Pixel
resizable=(True, True), # Größe änderbar (Breite, Höhe)
position=(100, 100) # Position auf dem Bildschirm
)
# Mindest- und Maximalgröße
app.minsize(300, 200)
app.maxsize(1200, 800)
# Fenstergröße nicht änderbar
app.resizable(False, False)
4 · Themes
ttkbootstrap kommt mit über 20 fertigen Themes — helle und dunkle Varianten. Du wählst das Theme einmalig beim Start der App.
# Helle Themes "cosmo" # Sauber & modern "flatly" # Flat Design "journal" # Zeitungsartig "litera" # Elegant "lumen" # Leuchtend hell "minty" # Mintgrün "pulse" # Lebhaft lila "sandstone" # Erdtöne "simplex" # Minimalistisch "sketchy" # Handgezeichnet "spacelab" # Sachlich "united" # Orange "yeti" # Nordisch # Dunkle Themes "darkly" # Dunkel (Bootstrap-Stil) "cyborg" # Cyber / Sci-Fi "superhero" # Dunkelblau "solar" # Solarized "vapor" # Neon / Synthwave
import ttkbootstrap as ttk
app = ttk.Window(themename="darkly")
# Theme wechseln (z.B. nach Klick auf Button)
def theme_wechseln():
app.style.theme_use("cyborg")
btn = ttk.Button(app, text="Theme wechseln", command=theme_wechseln)
btn.pack(pady=20)
app.mainloop()
5 · Widgets im Überblick
ttkbootstrap kennt alle Standard-tkinter-Widgets, ergänzt um bootstyle-Parameter für Farben. Das Farbschema entspricht Bootstrap: primary, secondary, success, danger, warning, info, light, dark.
Labels & Text
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
app = ttk.Window(themename="darkly")
# Einfaches Label
ttk.Label(app, text="Normaler Text").pack(pady=5)
# Label mit Stil
ttk.Label(app, text="Primär", bootstyle=PRIMARY).pack()
ttk.Label(app, text="Gefahr", bootstyle=DANGER).pack()
ttk.Label(app, text="Erfolg", bootstyle=SUCCESS).pack()
# Große Überschrift
ttk.Label(app, text="Titel", font=("Helvetica", 20, "bold")).pack(pady=10)
app.mainloop()
Buttons
import ttkbootstrap as ttk from ttkbootstrap.constants import * app = ttk.Window(themename="darkly") # Verschiedene Button-Stile ttk.Button(app, text="Primary", bootstyle=PRIMARY).pack(pady=3) ttk.Button(app, text="Danger", bootstyle=DANGER).pack(pady=3) ttk.Button(app, text="Success", bootstyle=SUCCESS).pack(pady=3) ttk.Button(app, text="Outline", bootstyle="primary-outline").pack(pady=3) ttk.Button(app, text="Groß", bootstyle=PRIMARY, width=20).pack(pady=3) # Deaktivierter Button btn = ttk.Button(app, text="Deaktiviert", bootstyle=SECONDARY, state=DISABLED) btn.pack(pady=3) app.mainloop()
Eingabefelder
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
app = ttk.Window(themename="darkly")
# Einzeiliges Eingabefeld
name_var = ttk.StringVar()
ttk.Label(app, text="Name:").pack()
ttk.Entry(app, textvariable=name_var, bootstyle=PRIMARY, width=30).pack(pady=5)
# Passwortfeld
pw_var = ttk.StringVar()
ttk.Label(app, text="Passwort:").pack()
ttk.Entry(app, textvariable=pw_var, show="*", width=30).pack(pady=5)
# Mehrzeiliges Textfeld
ttk.Label(app, text="Notiz:").pack()
text = ttk.ScrolledText(app, width=35, height=5)
text.pack(pady=5)
# Wert auslesen
def lesen():
print("Name:", name_var.get())
print("Text:", text.get("1.0", "end"))
ttk.Button(app, text="Auslesen", command=lesen, bootstyle=SUCCESS).pack()
app.mainloop()
Weitere wichtige Widgets
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
app = ttk.Window(themename="darkly")
# Checkbox
check_var = ttk.BooleanVar()
ttk.Checkbutton(app, text="Ich stimme zu", variable=check_var,
bootstyle="success-round-toggle").pack(pady=5)
# Radiobuttons
auswahl = ttk.StringVar(value="A")
ttk.Radiobutton(app, text="Option A", variable=auswahl, value="A").pack()
ttk.Radiobutton(app, text="Option B", variable=auswahl, value="B").pack()
# Dropdown (Combobox)
ttk.Label(app, text="Stadt:").pack(pady=(10,0))
combo = ttk.Combobox(app, values=["Wien", "Innsbruck", "Salzburg", "Graz"])
combo.current(0)
combo.pack(pady=5)
# Schieberegler
ttk.Label(app, text="Lautstärke:").pack()
slider = ttk.Scale(app, from_=0, to=100, bootstyle=DANGER)
slider.pack(fill="x", padx=20, pady=5)
# Fortschrittsbalken
pb = ttk.Progressbar(app, bootstyle="success-striped", value=65)
pb.pack(fill="x", padx=20, pady=5)
app.mainloop()
6 · Layout-Manager
tkinter/ttkbootstrap kennt drei Layout-Manager: pack, grid und place. Für die meisten GUIs empfiehlt sich grid.
pack — einfach & schnell
import ttkbootstrap as ttk app = ttk.Window(themename="darkly", size=(300,200)) # Widgets werden untereinander gestapelt ttk.Label(app, text="Oben").pack(pady=5) ttk.Label(app, text="Mitte").pack() ttk.Label(app, text="Unten").pack(pady=5) # Nebeneinander mit side=LEFT frame = ttk.Frame(app) frame.pack(pady=10) ttk.Button(frame, text="Links", bootstyle="primary").pack(side="left", padx=5) ttk.Button(frame, text="Rechts", bootstyle="danger").pack(side="left", padx=5) app.mainloop()
grid — für Formulare & strukturierte Layouts
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
app = ttk.Window(themename="darkly", size=(350,200))
app.columnconfigure(1, weight=1) # Spalte 1 dehnt sich aus
# row=Zeile, column=Spalte, sticky=Ausrichtung
ttk.Label(app, text="Vorname:").grid(row=0, column=0, padx=10, pady=8, sticky="w")
ttk.Entry(app, bootstyle=PRIMARY).grid(row=0, column=1, padx=10, sticky="ew")
ttk.Label(app, text="Nachname:").grid(row=1, column=0, padx=10, pady=8, sticky="w")
ttk.Entry(app, bootstyle=PRIMARY).grid(row=1, column=1, padx=10, sticky="ew")
ttk.Label(app, text="E-Mail:").grid(row=2, column=0, padx=10, pady=8, sticky="w")
ttk.Entry(app, bootstyle=PRIMARY).grid(row=2, column=1, padx=10, sticky="ew")
# Button über beide Spalten
ttk.Button(app, text="Speichern", bootstyle=SUCCESS).grid(
row=3, column=0, columnspan=2, pady=15
)
app.mainloop()
"w" = links, "e" = rechts, "ew" = dehnt sich horizontal aus, "nsew" = dehnt sich in alle Richtungen.
7 · Events & Callbacks
Events sind Benutzeraktionen (Klick, Tastendruck, Mausbewegung). Ein Callback ist eine Funktion, die beim Event ausgeführt wird.
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
app = ttk.Window(themename="darkly", size=(350,250))
zaehler = ttk.IntVar(value=0)
def klick():
zaehler.set(zaehler.get() + 1)
label.config(text=f"Geklickt: {zaehler.get()}x")
label = ttk.Label(app, text="Geklickt: 0x", font=("Helvetica", 14))
label.pack(pady=20)
ttk.Button(app, text="Klick mich!", command=klick, bootstyle=PRIMARY).pack()
app.mainloop()
Tastatur- & Maus-Events
import ttkbootstrap as ttk
app = ttk.Window(themename="darkly", size=(400,300))
info = ttk.Label(app, text="Warte auf Eingabe...", font=("Helvetica", 12))
info.pack(pady=20)
# Tastendruck
def taste(event):
info.config(text=f"Taste gedrückt: {event.keysym}")
# Mausklick
def mausklick(event):
info.config(text=f"Mausklick bei: x={event.x}, y={event.y}")
# Maus drüber
def hover(event):
info.config(text="Maus ist über dem Fenster")
app.bind("<Key>", taste)
app.bind("<Button-1>", mausklick) # Linksklick
app.bind("<Motion>", hover) # Mausbewegung
app.bind("<Return>", lambda e: info.config(text="Enter gedrückt!"))
app.mainloop()
StringVar & Trace (reaktiv)
import ttkbootstrap as ttk
app = ttk.Window(themename="darkly", size=(350,200))
name_var = ttk.StringVar()
vorschau = ttk.Label(app, text="Vorschau: ", font=("Helvetica", 13))
vorschau.pack(pady=20)
# Automatisch reagieren wenn Eingabe sich ändert
def bei_aenderung(*args):
vorschau.config(text=f"Hallo, {name_var.get()}!")
name_var.trace_add("write", bei_aenderung)
ttk.Entry(app, textvariable=name_var, width=30).pack()
app.mainloop()
8 · Formulare bauen
Ein vollständiges Eingabeformular mit Validierung — das Herzstück vieler Desktop-Apps.
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
app = ttk.Window(title="Registrierung", themename="darkly", size=(420,380))
app.columnconfigure(1, weight=1)
# --- Variablen ---
name_var = ttk.StringVar()
email_var = ttk.StringVar()
pw_var = ttk.StringVar()
land_var = ttk.StringVar()
agb_var = ttk.BooleanVar()
# --- Felder ---
felder = [
("Vorname:", name_var, False),
("E-Mail:", email_var, False),
("Passwort:", pw_var, True),
]
for i, (text, var, geheim) in enumerate(felder):
ttk.Label(app, text=text).grid(row=i, column=0, padx=15, pady=8, sticky="w")
show = "*" if geheim else ""
ttk.Entry(app, textvariable=var, show=show, width=28).grid(
row=i, column=1, padx=15, sticky="ew")
# Dropdown
ttk.Label(app, text="Land:").grid(row=3, column=0, padx=15, pady=8, sticky="w")
ttk.Combobox(app, textvariable=land_var,
values=["Österreich","Deutschland","Schweiz"]).grid(
row=3, column=1, padx=15, sticky="ew")
# Checkbox
ttk.Checkbutton(app, text="AGB akzeptieren", variable=agb_var,
bootstyle="success-round-toggle").grid(
row=4, column=0, columnspan=2, pady=10)
# --- Validierung & Absenden ---
def absenden():
if not name_var.get():
Messagebox.show_warning("Bitte Vorname eingeben.", "Fehler")
return
if "@" not in email_var.get():
Messagebox.show_warning("Ungültige E-Mail-Adresse.", "Fehler")
return
if len(pw_var.get()) < 6:
Messagebox.show_warning("Passwort muss mind. 6 Zeichen haben.", "Fehler")
return
if not agb_var.get():
Messagebox.show_warning("Bitte AGB akzeptieren.", "Fehler")
return
Messagebox.show_info(f"Willkommen, {name_var.get()}!", "Erfolg")
ttk.Button(app, text="Registrieren", command=absenden,
bootstyle=SUCCESS, width=20).grid(
row=5, column=0, columnspan=2, pady=15)
app.mainloop()
9 · Dialoge & Popups
ttkbootstrap bringt fertige Dialoge mit — für Meldungen, Fragen, Dateiauswahl und mehr.
from ttkbootstrap.dialogs import Messagebox
import ttkbootstrap as ttk
app = ttk.Window(themename="darkly", size=(400,300))
def info():
Messagebox.show_info("Das ist eine Info-Meldung.", "Info")
def warnung():
Messagebox.show_warning("Achtung! Etwas stimmt nicht.", "Warnung")
def fehler():
Messagebox.show_error("Ein Fehler ist aufgetreten.", "Fehler")
def frage():
antwort = Messagebox.yesno("Möchtest du wirklich löschen?", "Bestätigung")
if antwort == "Yes":
print("Gelöscht!")
ttk.Button(app, text="Info", command=info, bootstyle="info").pack(pady=5)
ttk.Button(app, text="Warnung", command=warnung, bootstyle="warning").pack(pady=5)
ttk.Button(app, text="Fehler", command=fehler, bootstyle="danger").pack(pady=5)
ttk.Button(app, text="Frage", command=frage, bootstyle="primary").pack(pady=5)
app.mainloop()
Datei-Dialog
import ttkbootstrap as ttk
from tkinter import filedialog
app = ttk.Window(themename="darkly", size=(350,200))
pfad_label = ttk.Label(app, text="Kein Pfad gewählt")
pfad_label.pack(pady=20)
def datei_oeffnen():
pfad = filedialog.askopenfilename(
title="Datei auswählen",
filetypes=[("Textdateien", "*.txt"), ("Alle Dateien", "*.*")]
)
if pfad:
pfad_label.config(text=pfad)
def datei_speichern():
pfad = filedialog.asksaveasfilename(
defaultextension=".txt",
filetypes=[("Textdateien", "*.txt")]
)
if pfad:
with open(pfad, "w") as f:
f.write("Hallo Welt!")
pfad_label.config(text=f"Gespeichert: {pfad}")
ttk.Button(app, text="Datei öffnen", command=datei_oeffnen, bootstyle="primary").pack(pady=5)
ttk.Button(app, text="Datei speichern", command=datei_speichern, bootstyle="success").pack(pady=5)
app.mainloop()
10 · Praxisprojekt: Notiz-App
Ein vollständiges Praxisprojekt: eine einfache Notiz-App mit Speichern, Laden und Dark Theme.
import ttkbootstrap as ttk
from ttkbootstrap.constants import *
from ttkbootstrap.dialogs import Messagebox
from tkinter import filedialog
import os
class NotizApp:
def __init__(self):
self.app = ttk.Window(
title="Notiz-App",
themename="darkly",
size=(600, 500)
)
self.app.columnconfigure(0, weight=1)
self.app.rowconfigure(1, weight=1)
self.aktueller_pfad = None
self._ui_aufbauen()
def _ui_aufbauen(self):
# --- Toolbar ---
toolbar = ttk.Frame(self.app)
toolbar.grid(row=0, column=0, sticky="ew", padx=5, pady=5)
ttk.Button(toolbar, text="📄 Neu", command=self.neu, bootstyle="secondary", width=8).pack(side="left", padx=2)
ttk.Button(toolbar, text="📂 Öffnen", command=self.oeffnen, bootstyle="primary", width=10).pack(side="left", padx=2)
ttk.Button(toolbar, text="💾 Speichern", command=self.speichern, bootstyle="success", width=12).pack(side="left", padx=2)
ttk.Button(toolbar, text="🗑 Löschen", command=self.loeschen, bootstyle="danger", width=10).pack(side="left", padx=2)
# Zeichenzähler rechts
self.zaehler_label = ttk.Label(toolbar, text="0 Zeichen", bootstyle="secondary")
self.zaehler_label.pack(side="right", padx=10)
# --- Textbereich ---
self.textfeld = ttk.ScrolledText(self.app, font=("Consolas", 12))
self.textfeld.grid(row=1, column=0, sticky="nsew", padx=5, pady=(0,5))
self.textfeld.bind("<KeyRelease>", self._zaehlen)
# --- Statusleiste ---
self.status = ttk.Label(self.app, text="Bereit", bootstyle="inverse-secondary")
self.status.grid(row=2, column=0, sticky="ew")
def _zaehlen(self, *args):
text = self.textfeld.get("1.0", "end-1c")
self.zaehler_label.config(text=f"{len(text)} Zeichen")
def neu(self):
self.textfeld.delete("1.0", "end")
self.aktueller_pfad = None
self.app.title("Notiz-App — Neue Datei")
self.status.config(text="Neue Datei")
self._zaehlen()
def oeffnen(self):
pfad = filedialog.askopenfilename(filetypes=[("Textdateien", "*.txt"), ("Alle", "*.*")])
if pfad:
with open(pfad, "r", encoding="utf-8") as f:
inhalt = f.read()
self.textfeld.delete("1.0", "end")
self.textfeld.insert("1.0", inhalt)
self.aktueller_pfad = pfad
self.app.title(f"Notiz-App — {os.path.basename(pfad)}")
self.status.config(text=f"Geöffnet: {pfad}")
self._zaehlen()
def speichern(self):
if not self.aktueller_pfad:
pfad = filedialog.asksaveasfilename(defaultextension=".txt")
if not pfad:
return
self.aktueller_pfad = pfad
with open(self.aktueller_pfad, "w", encoding="utf-8") as f:
f.write(self.textfeld.get("1.0", "end-1c"))
self.app.title(f"Notiz-App — {os.path.basename(self.aktueller_pfad)}")
self.status.config(text=f"Gespeichert: {self.aktueller_pfad}")
def loeschen(self):
if Messagebox.yesno("Inhalt wirklich löschen?", "Bestätigung") == "Yes":
self.neu()
def starten(self):
self.app.mainloop()
if __name__ == "__main__":
NotizApp().starten()
🎓 Glückwunsch!
Du kennst jetzt alle Grundlagen von ttkbootstrap.