# Kapitel 14: Desktop-GUIs mit Tkinter & OOP πŸ–₯️✨ Bisher liefen alle unsere Python-Programme im Terminal (der Konsole) ab: Text eingeben mit `input()`, Text ausgeben mit `print()`. Das ist super fΓΌr den Einstieg, aber echte moderne Desktop-Programme haben grafische BenutzeroberflΓ€chen (**GUI = Graphical User Interface**) mit Fenstern, Buttons, Eingabefeldern und Maus-Klicks! In diesem Kapitel lernst du, wie du mit Pythons integriertem Modul **`tkinter`** und **Objektorientierter Programmierung (OOP)** professionelle Desktop-Programme baust. --- ## πŸ“Ί 1. Vom Schwarz-Weiß-Fernseher zum Touchscreen (Event-Driven) | Terminal (Konsole) | Grafische OberflΓ€che (Tkinter GUI) | | :--- | :--- | | **Linearer Ablauf:** Schritt 1 → Schritt 2 → `input()` → Ende | **Ereignisgesteuert (Event-Driven):** Das Fenster wartet in einer Dauerschleife (`mainloop`) auf Benutzeraktionen | | Nur reiner Text | Buttons, Eingabefelder, Farben, Fenster | | Programm beendet sich nach AusfΓΌhrung | Programm bleibt geΓΆffnet, bis das Fenster geschlossen wird | ### Der Event-Loop (`root.mainloop()`): Ein GUI-Programm lΓ€uft nicht einfach von oben nach unten durch. Sobald das Fenster aufgebaut ist, ΓΌbergibt Python die Kontrolle an den **Event-Loop**: ```python root.mainloop() # Wartet geduldig auf Klicks, TastaturanschlΓ€ge oder Fenster-Schließen ``` --- ## 🧱 2. Die wichtigsten Tkinter-Widgets Ein **Widget** (Window Gadget) ist ein grafisches Bauelement: | Widget | Klasse | Zweck | Wichtigste Optionen / Methoden | | :--- | :--- | :--- | :--- | | **Hauptfenster** | `tk.Tk()` | Das Betriebssystem-Fenster | `.title("Titel")`, `.geometry("400x300")`, `.mainloop()` | | **Textanzeige** | `tk.Label` | Zeigt Text oder Zahlen an | `text="Hallo"`, `font=("Arial", 14)`, `fg="blue"`, `bg="white"` | | **SchaltflΓ€che** | `tk.Button` | Klickbarer Knopf | `text="Klick"`, `command=self.methode` | | **Eingabefeld** | `tk.Entry` | Einzeilige Texteingabe | `.get()`, `.insert(0, "Start")`, `.delete(0, "end")` | | **Container** | `tk.Frame` | Gruppiert mehrere Widgets | Hilft beim sauberen Verschachteln von Layouts | --- ## πŸ“ 3. Das Grid-Layout-System (Raster) Um Elemente auf dem Bildschirm auszurichten, nutzen wir den **Grid-Layout-Manager**. Er funktioniert wie eine Tabelle oder ein Schachbrett: ``` Spalte 0 Spalte 1 β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” Zeile 0 β”‚ πŸ”’ Überschrift (columnspan=2) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Zeile 1 β”‚ Große ZΓ€hleranzeige: "0" (columnspan=2) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Zeile 2 β”‚ Status: "Klicks: 0" (columnspan=2) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Zeile 3 β”‚ βž• ErhΓΆhen β”‚ βž– Verringern β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ Zeile 4 β”‚ β†Ί ZurΓΌcksetzen (columnspan=2) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Die wichtigsten Parameter bei `.grid()`: - `row=0, column=1`: Bestimmt Zeile und Spalte. - `columnspan=2`: LΓ€sst das Element ΓΌber 2 Spalten spannen. - `padx=10, pady=5`: Γ„ußerer Abstand (Padding) in Pixeln. - `sticky="ew"`: Dehnt das Element nach Osten und Westen (links & rechts) aus. > ⚠️ **Goldene Regel:** Mische niemals `.pack()` und `.grid()` im selben Eltern-Container! Verwende innerhalb eines Fensters oder Frames konsistent einen Layout-Manager. --- ## βš™οΈ 4. Event-Driven Programming: Was passiert beim Klick? Wenn ein Button geklickt wird, fΓΌhrt Tkinter die bei `command` hinterlegte Methode aus: ```python # RICHTIG: Referenz auf die Methode ΓΌbergeben (ohne Klammern!) self.btn_plus = tk.Button(self.root, text="+", command=self.klick_plus) # FALSCH: WΓΌrde die Methode SOFORT beim Start aufrufen, statt erst beim Klick! self.btn_plus = tk.Button(self.root, text="+", command=self.klick_plus()) ``` --- ## πŸ›οΈ 5. Clean Architecture: Model-View-Controller (MVC) Warum packen wir nicht alles in eine einzige Datei/Funktion? Weil professioneller Code modular und automatisiert testbar sein muss! ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Model (ZaehlerLogik) β”‚ β”‚ View/Controller (ZaehlerApp) β”‚ β”‚ - wert: int β”‚ β”‚ - root: tk.Tk β”‚ β”‚ - schrittweite: int β”‚ ◄────── β”‚ - label_anzeige: tk.Label β”‚ β”‚ - erhoehen() -> int β”‚ β”‚ - btn_plus: tk.Button β”‚ β”‚ - verringern() -> int β”‚ β”‚ - klick_plus() β”‚ β”‚ (100% reines Python, keine GUI) β”‚ β”‚ (Tkinter-Widgets & Ereignisse)β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` 1. **`ZaehlerLogik` (Model):** Verwaltet die Daten (Zahlen, Grenzen, Schrittweiten). Es weiß nichts von Fenstern oder Buttons und kann in Unittests in Millisekunden geprΓΌft werden. 2. **`ZaehlerApp` (View & Controller):** Erstellt die OberflΓ€che und ruft bei Klicks die Methoden von `self.logik` auf. --- ## 🎯 6. Deine Aufgaben in `aufgabe.py` Γ–ffne `14_gui_mit_tkinter/aufgabe.py` und vervollstΓ€ndige die Klassen: 1. **TODO 1:** `ZaehlerLogik.__init__` mit `startwert`, `min_wert`, `max_wert`, `schrittweite=1`, `klick_anzahl=0`. 2. **TODO 2:** `erhoehen()`, `verringern()` (mit Clamping an Min/Max) und `zuruecksetzen()`. 3. **TODO 3:** `setze_schrittweite()`, `ist_gerade()` und `__str__()`. 4. **TODO 4:** `ZaehlerApp.__init__` (Fenster-Konfiguration, Widgets anlegen und im Grid platzieren). 5. **TODO 5:** Event-Handler `klick_plus()`, `klick_minus()`, `klick_reset()`, `klick_schritt_setzen()`. 6. **TODO 6:** `aktualisiere_anzeige()` (Labels synchronisieren und farblich hervorheben). --- ## πŸ§ͺ 7. Testen & AusfΓΌhren ### Automatische Tests ausfΓΌhren: ```bash python3 test_aufgabe.py ``` ### Startbare grafische Applikation ausprobieren: ```bash python3 gui_app.py ``` *(Hinweis: Die grafische OberflΓ€che benΓΆtigt eine Desktop-Umgebung mit Display)*