352 lines
22 KiB
HTML
352 lines
22 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="de">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Kapitel 14: Desktop-GUIs mit Tkinter & OOP</title>
|
||
<link rel="stylesheet" href="../assets/style.css">
|
||
</head>
|
||
<body>
|
||
|
||
<header>
|
||
<div class="header-container">
|
||
<nav class="nav-links">
|
||
<a href="../index.html">🏠 Zur Kursübersicht</a>
|
||
<span>›</span>
|
||
<a href="../13_persistenz_json_und_csv/index.html">Kapitel 13</a>
|
||
<span>›</span>
|
||
<span style="color: white; font-weight: 600;">Kapitel 14</span>
|
||
</nav>
|
||
<div class="header-badge">Kapitel 14 • Schulabgleich 27.0 Tkinter</div>
|
||
<h1>Desktop-GUIs mit Tkinter & OOP 🖥️✨</h1>
|
||
<p>Vom Text-Terminal zum echten Betriebssystem-Fenster mit Buttons, Eingabefeldern, Layout-Grids und ereignisgesteuerter OOP-Architektur.</p>
|
||
</div>
|
||
</header>
|
||
|
||
<main class="container">
|
||
|
||
<!-- 1. Das Konzept: Vom Terminal zum Touchscreen -->
|
||
<section class="card">
|
||
<h2>1. Vom Terminal zur grafischen Oberfläche (GUI)</h2>
|
||
|
||
<p>
|
||
Bisher liefen all deine Python-Programme linear im schwarzen Terminal ab: Text einlesen mit <code>input()</code>, Text ausgeben mit <code>print()</code>.
|
||
Echte Desktop-Software (wie Spotify, VS Code oder ein Taschenrechner) funktioniert jedoch völlig anders: Sie besitzt ein <strong>Fenster</strong>, das geduldig auf <strong>Mausklicks</strong> und <strong>Tastatureingaben</strong> wartet.
|
||
</p>
|
||
|
||
<div class="box box-analogie">
|
||
<div class="box-title">📺 Die Fernseh-Analogie: Vom Schwarz-Weiß-Fernseher zum Touchscreen</div>
|
||
<ul>
|
||
<li><strong>Terminal (Linear):</strong> Wie ein alter Filmstreifen. Bild für Bild läuft starr von oben nach unten ab. Am Ende ist der Film vorbei.</li>
|
||
<li><strong>GUI (Ereignisgesteuert / Event-Driven):</strong> Wie ein interaktiver Touchscreen. Das System schläft im Hintergrund (im sogenannten <strong>Event-Loop</strong>). Sobald du auf einen Knopf drückst, feuert ein Signal und deine Methode reagiert blitzschnell darauf!</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<h3>Der Herzschlag einer GUI: Der Event-Loop</h3>
|
||
<p>
|
||
Ein GUI-Programm beendet sich nicht sofort, sondern übergibt die Kontrolle an <code>root.mainloop()</code>:
|
||
</p>
|
||
|
||
<div class="code-container">
|
||
<div class="code-header">
|
||
<div class="code-dots">
|
||
<span class="code-dot dot-red"></span>
|
||
<span class="code-dot dot-yellow"></span>
|
||
<span class="code-dot dot-green"></span>
|
||
</div>
|
||
<span>Python (Minimales Tkinter-Fenster)</span>
|
||
</div>
|
||
<pre><span class="kw">import</span> <span class="var">tkinter</span> <span class="kw">as</span> <span class="var">tk</span>
|
||
|
||
<span class="var">root</span> = <span class="var">tk</span>.<span class="fn">Tk</span>() <span class="cm"># 1. Hauptfenster erzeugen</span>
|
||
<span class="var">root</span>.<span class="fn">title</span>(<span class="str">"Mein erstes GUI-Fenster"</span>) <span class="cm"># 2. Fenstertitel festlegen</span>
|
||
<span class="var">root</span>.<span class="fn">geometry</span>(<span class="str">"400x300"</span>) <span class="cm"># 3. Fenstergröße (Breite x Höhe)</span>
|
||
|
||
<span class="var">label</span> = <span class="var">tk</span>.<span class="fn">Label</span>(<span class="var">root</span>, <span class="var">text</span>=<span class="str">"Hallo Welt! 👋"</span>, <span class="var">font</span>=(<span class="str">"Arial"</span>, <span class="num">16</span>))
|
||
<span class="var">label</span>.<span class="fn">pack</span>(<span class="var">pady</span>=<span class="num">20</span>) <span class="cm"># 4. Widget im Fenster platzieren</span>
|
||
|
||
<span class="var">root</span>.<span class="fn">mainloop</span>() <span class="cm"># 5. Ereignisschleife starten (wartet auf Events)</span></pre>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 2. Die wichtigsten Widgets im Überblick -->
|
||
<section class="card">
|
||
<h2>2. Bausteine einer GUI: Die wichtigsten Widgets</h2>
|
||
|
||
<p>
|
||
In Tkinter heißen alle visuellen Bedienelemente <strong>Widgets</strong> (Window Gadgets). Jedes Widget ist ein Python-Objekt, das wir in unserem Fenster platzieren können:
|
||
</p>
|
||
|
||
<table style="width: 100%; border-collapse: collapse; margin: 15px 0;">
|
||
<thead>
|
||
<tr style="background: var(--primary-light); text-align: left;">
|
||
<th style="padding: 10px; border: 1px solid var(--border-color);">Widget</th>
|
||
<th style="padding: 10px; border: 1px solid var(--border-color);">Klasse</th>
|
||
<th style="padding: 10px; border: 1px solid var(--border-color);">Zweck</th>
|
||
<th style="padding: 10px; border: 1px solid var(--border-color);">Wichtige Parameter & Methoden</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
<tr>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Hauptfenster</strong></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>tk.Tk()</code></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);">Rahmen & Titelleiste des Betriebssystems</td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>.title()</code>, <code>.geometry("BxH")</code>, <code>.mainloop()</code></td>
|
||
</tr>
|
||
<tr style="background: #fafafa;">
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Textanzeige</strong></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>tk.Label</code></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);">Zeigt Texte, Titel oder Zahlenwerte</td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>text="..."</code>, <code>font=("Arial", 14)</code>, <code>fg="color"</code>, <code>.config(text=...)</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Schaltfläche</strong></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>tk.Button</code></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);">Knopf, der beim Anklicken eine Methode ausführt</td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>text="..."</code>, <code>command=self.klick_methode</code>, <code>bg="color"</code></td>
|
||
</tr>
|
||
<tr style="background: #fafafa;">
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Eingabefeld</strong></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>tk.Entry</code></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);">Einzeiliges Textfeld für Benutzereingaben</td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>.get()</code>, <code>.insert(0, text)</code>, <code>.delete(0, "end")</code></td>
|
||
</tr>
|
||
<tr>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><strong>Container</strong></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);"><code>tk.Frame</code></td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);">Unsichtbare Box zum Gruppieren von Widgets</td>
|
||
<td style="padding: 10px; border: 1px solid var(--border-color);">Unterteilt komplexe Layouts in saubere Blöcke</td>
|
||
</tr>
|
||
</tbody>
|
||
</table>
|
||
</section>
|
||
|
||
<!-- 3. Layout Manager: Das Grid System -->
|
||
<section class="card">
|
||
<h2>3. Layout-Manager: Das 2D-Grid-System (Raster)</h2>
|
||
|
||
<p>
|
||
Widgets müssen auf dem Bildschirm positioniert werden. Der mächtigste und sauberste Layout-Manager in Tkinter ist <strong><code>grid()</code></strong>.
|
||
Er teilt den Raum wie eine Excel-Tabelle oder ein Schachbrett in <strong>Zeilen (<code>row</code>)</strong> und <strong>Spalten (<code>column</code>)</strong> ein:
|
||
</p>
|
||
|
||
<div style="background: #f1f5f9; border: 2px dashed #94a3b8; border-radius: var(--radius-md); padding: 20px; margin: 20px 0; font-family: var(--font-mono); font-size: 0.9rem;">
|
||
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px; text-align: center;">
|
||
<div style="grid-column: 1 / span 2; background: #e0e7ff; border: 1px solid #6366f1; padding: 12px; border-radius: 6px; font-weight: bold; color: #3730a3;">
|
||
row=0, column=0, columnspan=2 → 🔢 Titel: "Python Klick-Zähler"
|
||
</div>
|
||
<div style="grid-column: 1 / span 2; background: #ffffff; border: 2px solid #6366f1; padding: 16px; border-radius: 6px; font-size: 1.4rem; font-weight: bold; color: #4f46e5;">
|
||
row=1, column=0, columnspan=2 → Zählerstand: "0"
|
||
</div>
|
||
<div style="grid-column: 1 / span 2; background: #f8fafc; border: 1px solid #cbd5e1; padding: 8px; border-radius: 6px; color: #64748b;">
|
||
row=2, column=0, columnspan=2 → Status-Info: "Klicks: 0 | Gerade Zahl"
|
||
</div>
|
||
<div style="background: #d1fae5; border: 1px solid #10b981; padding: 12px; border-radius: 6px; font-weight: bold; color: #065f46;">
|
||
row=3, column=0<br>➕ Erhöhen
|
||
</div>
|
||
<div style="background: #fee2e2; border: 1px solid #ef4444; padding: 12px; border-radius: 6px; font-weight: bold; color: #991b1b;">
|
||
row=3, column=1<br>➖ Verringern
|
||
</div>
|
||
<div style="grid-column: 1 / span 2; background: #f1f5f9; border: 1px solid #94a3b8; padding: 10px; border-radius: 6px; color: #1e293b;">
|
||
row=4, column=0, columnspan=2 → ↺ Zurücksetzen (Reset)
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="box box-warning">
|
||
<div class="box-title">⚠️ Häufigster Anfängerfehler: .pack() und .grid() niemals mischen!</div>
|
||
Verwende innerhalb eines Fensters (oder innerhalb eines Frames) <strong>entweder nur <code>grid()</code> oder nur <code>pack()</code></strong>.
|
||
Wenn du beide Layout-Manager im selben übergeordneten Fenster mischst, friert Python in einer Endlosschleife ein!
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 4. Event-Driven & Methoden-Referenzen -->
|
||
<section class="card">
|
||
<h2>4. Event-Driven Programming: Was geschieht beim Klick?</h2>
|
||
|
||
<p>
|
||
Wenn der Benutzer auf einen Button klickt, soll ein Stück Code ausgeführt werden. In Tkinter übergeben wir dafür das <strong><code>command</code>-Attribut</strong>:
|
||
</p>
|
||
|
||
<div class="code-container">
|
||
<div class="code-header">
|
||
<span>Python: Button-Befehle richtig übergeben</span>
|
||
</div>
|
||
<pre><span class="cm"># ✅ RICHTIG: Nur den Methodennamen übergeben (OHNE Klammern!)</span>
|
||
<span class="var">self</span>.<span class="attr">btn_plus</span> = <span class="var">tk</span>.<span class="fn">Button</span>(<span class="var">self</span>.<span class="attr">root</span>, <span class="var">text</span>=<span class="str">"➕"</span>, <span class="var">command</span>=<span class="var">self</span>.<span class="fn">klick_plus</span>)
|
||
|
||
<span class="cm"># ❌ FALSCH: Mit Klammern wird die Methode SOFORT beim Erstellen aufgerufen!</span>
|
||
<span class="var">self</span>.<span class="attr">btn_plus</span> = <span class="var">tk</span>.<span class="fn">Button</span>(<span class="var">self</span>.<span class="attr">root</span>, <span class="var">text</span>=<span class="str">"➕"</span>, <span class="var">command</span>=<span class="var">self</span>.<span class="fn">klick_plus</span>())</pre>
|
||
</div>
|
||
|
||
<div class="box box-tipp">
|
||
<div class="box-title">💡 Warum ohne Klammern?</div>
|
||
Mit <code>self.klick_plus</code> übergibst du dem Button eine <strong>Visitenkarte (Referenz)</strong> der Methode. Der Button behält diese Visitenkarte und ruft die Methode erst dann an, wenn der Benutzer wirklich mit der Maus daraufklickt.
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 5. Professionelle OOP-Architektur (MVC) -->
|
||
<section class="card">
|
||
<h2>5. Saubere Software-Architektur: Model-View-Trennung (MVC) 🏛️</h2>
|
||
|
||
<p>
|
||
In der professionellen Entwicklung schreibt man GUI-Apps niemals als wilden Spaghetticode, sondern trennt die <strong>Logik (Berechnung & Daten)</strong> strikt von der <strong>Präsentation (Fenster & Buttons)</strong>:
|
||
</p>
|
||
|
||
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 15px; margin: 20px 0;">
|
||
<div style="background: #ffffff; border: 2px solid var(--primary); border-radius: var(--radius-sm); padding: 15px;">
|
||
<h4 style="color: var(--primary); margin-bottom: 8px;">1. Model: <code>ZaehlerLogik</code></h4>
|
||
<p style="font-size: 0.9rem; color: var(--text-muted);">
|
||
Reines Python! Verwaltet <code>wert</code>, <code>schrittweite</code>, Grenzwerte und Berechnungen.<br>
|
||
<strong>Vorteil:</strong> 100% unabhängig von Bildschirmen und in Sekundenbruchteilen per Unit Test prüfbar!
|
||
</p>
|
||
</div>
|
||
|
||
<div style="background: #ffffff; border: 2px solid var(--success); border-radius: var(--radius-sm); padding: 15px;">
|
||
<h4 style="color: var(--success); margin-bottom: 8px;">2. View / Controller: <code>ZaehlerApp</code></h4>
|
||
<p style="font-size: 0.9rem; color: var(--text-muted);">
|
||
Hält die Widgets (<code>Label</code>, <code>Button</code>, <code>Entry</code>).<br>
|
||
Bei einem Button-Klick ruft sie Methoden der <code>ZaehlerLogik</code> auf und spiegelt das Ergebnis im Label wider.
|
||
</p>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="code-container">
|
||
<div class="code-header">
|
||
<span>Struktur einer OOP-GUI-Klasse</span>
|
||
</div>
|
||
<pre><span class="kw">class</span> <span class="fn">ZaehlerApp</span>:
|
||
<span class="kw">def</span> <span class="fn">__init__</span>(<span class="var">self</span>, <span class="var">root</span>: <span class="var">tk</span>.<span class="fn">Tk</span>):
|
||
<span class="var">self</span>.<span class="attr">root</span> = <span class="var">root</span>
|
||
<span class="var">self</span>.<span class="attr">root</span>.<span class="fn">title</span>(<span class="str">"Python Zähler"</span>)
|
||
|
||
<span class="cm"># 1. Datenmodell einbinden</span>
|
||
<span class="var">self</span>.<span class="attr">logik</span> = <span class="fn">ZaehlerLogik</span>()
|
||
|
||
<span class="cm"># 2. Widgets erstellen</span>
|
||
<span class="var">self</span>.<span class="attr">label_anzeige</span> = <span class="var">tk</span>.<span class="fn">Label</span>(<span class="var">self</span>.<span class="attr">root</span>, <span class="var">text</span>=<span class="str">"0"</span>, <span class="var">font</span>=(<span class="str">"Arial"</span>, <span class="num">32</span>))
|
||
<span class="var">self</span>.<span class="attr">label_anzeige</span>.<span class="fn">grid</span>(<span class="var">row</span>=<span class="num">0</span>, <span class="var">column</span>=<span class="num">0</span>)
|
||
|
||
<span class="var">self</span>.<span class="attr">btn_plus</span> = <span class="var">tk</span>.<span class="fn">Button</span>(<span class="var">self</span>.<span class="attr">root</span>, <span class="var">text</span>=<span class="str">"➕"</span>, <span class="var">command</span>=<span class="var">self</span>.<span class="fn">klick_plus</span>)
|
||
<span class="var">self</span>.<span class="attr">btn_plus</span>.<span class="fn">grid</span>(<span class="var">row</span>=<span class="num">1</span>, <span class="var">column</span>=<span class="num">0</span>)
|
||
|
||
<span class="kw">def</span> <span class="fn">klick_plus</span>(<span class="var">self</span>) -> <span class="kw">None</span>:
|
||
<span class="var">self</span>.<span class="attr">logik</span>.<span class="fn">erhoehen</span>()
|
||
<span class="var">self</span>.<span class="fn">aktualisiere_anzeige</span>()
|
||
|
||
<span class="kw">def</span> <span class="fn">aktualisiere_anzeige</span>(<span class="var">self</span>) -> <span class="kw">None</span>:
|
||
<span class="var">self</span>.<span class="attr">label_anzeige</span>.<span class="fn">config</span>(<span class="var">text</span>=<span class="fn">str</span>(<span class="var">self</span>.<span class="attr">logik</span>.<span class="attr">wert</span>))</pre>
|
||
</div>
|
||
</section>
|
||
|
||
<!-- 6. Deine Aufgaben in aufgabe.py -->
|
||
<section class="card">
|
||
<h2>6. 🎯 Deine Aufgaben in <code>aufgabe.py</code></h2>
|
||
|
||
<p>Öffne die Datei <code>14_gui_mit_tkinter/aufgabe.py</code> und implementiere die Klassen Schritt für Schritt:</p>
|
||
|
||
<ul class="task-list">
|
||
<li class="task-item">
|
||
<input type="checkbox" class="task-checkbox" id="t14_1">
|
||
<label for="t14_1" class="task-label">
|
||
<strong>TODO 1 (Logik-Init):</strong> <code>ZaehlerLogik.__init__</code> mit <code>startwert</code>, <code>min_wert</code>, <code>max_wert</code>, <code>schrittweite=1</code> und <code>klick_anzahl=0</code>.
|
||
</label>
|
||
</li>
|
||
<li class="task-item">
|
||
<input type="checkbox" class="task-checkbox" id="t14_2">
|
||
<label for="t14_2" class="task-label">
|
||
<strong>TODO 2 (Rechnen & Grenzen):</strong> <code>erhoehen()</code>, <code>verringern()</code> (Grenzwerte mit <code>min()</code> / <code>max()</code> einhalten!) und <code>zuruecksetzen()</code>.
|
||
</label>
|
||
</li>
|
||
<li class="task-item">
|
||
<input type="checkbox" class="task-checkbox" id="t14_3">
|
||
<label for="t14_3" class="task-label">
|
||
<strong>TODO 3 (Zusatz-Logik):</strong> <code>setze_schrittweite(schritt)</code> (nur wenn <code>schritt > 0</code>), <code>ist_gerade()</code> und Dunder <code>__str__()</code>.
|
||
</label>
|
||
</li>
|
||
<li class="task-item">
|
||
<input type="checkbox" class="task-checkbox" id="t14_4">
|
||
<label for="t14_4" class="task-label">
|
||
<strong>TODO 4 (GUI-Aufbau):</strong> <code>ZaehlerApp.__init__</code> (Fenstertitel, Geometrie, Instanziierung von <code>ZaehlerLogik</code>, Widgets erstellen und im Grid platzieren).
|
||
</label>
|
||
</li>
|
||
<li class="task-item">
|
||
<input type="checkbox" class="task-checkbox" id="t14_5">
|
||
<label for="t14_5" class="task-label">
|
||
<strong>TODO 5 (Event-Handler):</strong> Methoden <code>klick_plus</code>, <code>klick_minus</code>, <code>klick_reset</code> und <code>klick_schritt_setzen</code> mit Fehlerbehandlung für <code>Entry</code>.
|
||
</label>
|
||
</li>
|
||
<li class="task-item">
|
||
<input type="checkbox" class="task-checkbox" id="t14_6">
|
||
<label for="t14_6" class="task-label">
|
||
<strong>TODO 6 (Display-Sync):</strong> <code>aktualisiere_anzeige()</code> zur Aktualisierung der Labels <code>label_anzeige</code> und <code>label_info</code>.
|
||
</label>
|
||
</li>
|
||
</ul>
|
||
|
||
<h3>💡 Lösungshinweise (Aufklappen bei Bedarf)</h3>
|
||
|
||
<details>
|
||
<summary>🔍 Tipp zu TODO 2: Clamping an Grenzwerte (min/max)</summary>
|
||
<div class="details-content">
|
||
<p>Um einen Wert nach oben und unten sauber zu deckeln:</p>
|
||
<div class="code-container">
|
||
<pre><span class="cm"># Erhöhen mit oberer Grenze:</span>
|
||
<span class="var">self</span>.<span class="attr">wert</span> = <span class="fn">min</span>(<span class="var">self</span>.<span class="attr">max_wert</span>, <span class="var">self</span>.<span class="attr">wert</span> + <span class="var">self</span>.<span class="attr">schrittweite</span>)
|
||
|
||
<span class="cm"># Verringern mit unterer Grenze:</span>
|
||
<span class="var">self</span>.<span class="attr">wert</span> = <span class="fn">max</span>(<span class="var">self</span>.<span class="attr">min_wert</span>, <span class="var">self</span>.<span class="attr">wert</span> - <span class="var">self</span>.<span class="attr">schrittweite</span>)</pre>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
|
||
<details>
|
||
<summary>🔍 Tipp zu TODO 5d: Fehler beim Entry-Auslesen abfangen</summary>
|
||
<div class="details-content">
|
||
<p>Benutzer können Tippfehler machen (z.B. Buchstaben eingeben). Fange das mit <code>try-except</code> ab:</p>
|
||
<div class="code-container">
|
||
<pre><span class="var">eingabe</span> = <span class="var">self</span>.<span class="attr">entry_schritt</span>.<span class="fn">get</span>().<span class="fn">strip</span>()
|
||
<span class="kw">try</span>:
|
||
<span class="var">neuer_schritt</span> = <span class="fn">int</span>(<span class="var">eingabe</span>)
|
||
<span class="kw">if</span> <span class="var">self</span>.<span class="attr">logik</span>.<span class="fn">setze_schrittweite</span>(<span class="var">neuer_schritt</span>):
|
||
<span class="var">self</span>.<span class="fn">aktualisiere_anzeige</span>()
|
||
<span class="kw">else</span>:
|
||
<span class="var">self</span>.<span class="attr">label_info</span>.<span class="fn">config</span>(<span class="var">text</span>=<span class="str">"⚠️ Schrittweite muss > 0 sein!"</span>)
|
||
<span class="kw">except</span> <span class="fn">ValueError</span>:
|
||
<span class="var">self</span>.<span class="attr">label_info</span>.<span class="fn">config</span>(<span class="var">text</span>=<span class="str">"⚠️ Bitte eine ganze Zahl eingeben!"</span>)</pre>
|
||
</div>
|
||
</div>
|
||
</details>
|
||
</section>
|
||
|
||
<!-- 7. Testen & Navigation -->
|
||
<section class="card">
|
||
<h2>7. 🧪 Lösung überprüfen & Starten</h2>
|
||
|
||
<h3>1. Automatische Tests ausführen:</h3>
|
||
<div class="code-container">
|
||
<div class="code-header">
|
||
<span>Terminal (im Ordner 14_gui_mit_tkinter)</span>
|
||
</div>
|
||
<pre><code>python3 test_aufgabe.py</code></pre>
|
||
</div>
|
||
|
||
<h3>2. Fertige grafische Applikation starten:</h3>
|
||
<div class="code-container">
|
||
<div class="code-header">
|
||
<span>Terminal</span>
|
||
</div>
|
||
<pre><code>python3 gui_app.py</code></pre>
|
||
</div>
|
||
|
||
<div class="footer-nav">
|
||
<a href="../13_persistenz_json_und_csv/index.html" class="btn btn-secondary">← Zurück zu Kapitel 13</a>
|
||
<a href="../index.html" class="btn btn-secondary">🏠 Kursübersicht</a>
|
||
<a href="../15_parameter_und_container/index.html" class="btn">Weiter zu Kapitel 15 →</a>
|
||
</div>
|
||
</section>
|
||
|
||
</main>
|
||
|
||
</body>
|
||
</html>
|