Einstieg in Python (Teil 10)
Interaktiv mit Tkinter!
In den letzten Beiträgen dieser Serie ging es überwiegend um Datenausgaben, wie allgemeine Zahlenwerte, Sensordaten oder auch Lichtsignale von LEDs. Einer der wichtigsten Vorteile von Python ist jedoch, dass auch interaktive Steuerungen sehr leicht programmiert werden können. Hierfür bietet sich die Tkinter-Bibliothek hervorragend an. Tkinter ist die standardmäßige Python-Bibliothek zur Erstellung grafischer Benutzeroberflächen (GUIs – „Graphical User Interface“). Mit Tkinter können Fenster, Buttons, Textfelder, Menüs und andere GUI-Elemente erstellt werden. Steuerungsaufgaben, vom einfachen Ein- und Ausschalten einer LED bis hin zu kompletten Heimautomatisierungen, können damit problemlos umgesetzt werden.
Flexible Steuerung über Fenster
Die Tkinter-Bibliothek ist nach der Installation von Python üblicherweise vollständig einsatzbereit. Im Bedarfsfall kann die Nachinstallation auf Systemen wie dem Raspberry Pi mit folgendem Befehl erfolgen:
sudo apt-get install python3-tk
Die ordnungsgemäße Funktion wird mit einem kurzen Testprogramm überprüft:
import tkinter
tkinter._test()
Die _test-Methode sorgt dafür, dass ein eigenständiges Fenster erzeugt wird (Bild 1). Innerhalb dieses Fensters finden sich verschiedene Elemente: Ein Textlabel, ein klickbarer Button „Click me!“, der bei jedem Klick seinen Text verändert, und ein QUIT-Button, der die Anwendung schließt. Dieses einfache Beispiel zeigt bereits die grundlegenden Bausteine einer Tkinter-Anwendung.
Bei jeder GUI wird zunächst ein Hauptfenster erstellt. Dieses Fenster ist die Programmoberfläche, die wie bei anderen Anwendungen vergrößert, minimiert und geschlossen werden kann. Anschließend wird dieses Fenster mit interaktiven Elementen, den sogenannten „Widgets“, befüllt.

Die Python-Tkinter-Widgets
Steuerelemente wie Texte, Buttons oder Eingabefelder werden als „Widgets“ bezeichnet. Der Text im Testfenster ist ein „Label“, der „Click me!“-Button ist ein „Button“-Widget. Tkinter stellt zahlreiche weitere Widgets zur Verfügung. Zuerst erzeugen wir mit tkinter.Tk() ein sogenanntes Tk-Objekt, welches das Hauptfenster der GUI darstellt. Die Referenz auf dieses Objekt speichern wir in einer Variablen, die üblicherweise root genannt wird:
root = tkinter.Tk()
Damit das Fenster tatsächlich erscheint, muss die sogenannte Tkinter-Event-Loop gestartet werden. Dies geschieht mit der mainloop()-Methode:
root.mainloop()
Nun erscheint ein leeres, aber bereits voll funktionsfähiges GUI-Fenster. Um den Text „Hello Python“ auszugeben, fügen wir ein Label-Widget hinzu und positionieren es mit dem pack-Layout-Manager:
import tkinter
root = tkinter.Tk()
label = tkinter.Label(root, text="Hello Python")
label.pack()
root.mainloop()
Der Layout-Manager pack sorgt dafür, dass das Fenster gerade so groß ist, wie es der Inhalt erfordert. Das Label wird standardmäßig oben zentriert angezeigt (Bild 2).

Die Fenstergröße und -position können mit der geometry-Methode angepasst werden. Auch ein Titel lässt sich festlegen.
root.geometry("breite x höhe" +x +y)
Widgets werden mit pack nacheinander horizontal oder vertikal gestapelt. Dies ist ideal für einfache Layouts. Wichtige Optionen hierfür sind:
- side (z. B. tk.TOP, tk.BOTTOM, tk.LEFT, tk.RIGHT) für die Ausrichtung.
- fill (z. B. tk.X, tk.Y, tk.BOTH): Bestimmt, ob das Widget den verfügbaren Raum ausfüllt.
- expand (True/False): Gibt an, ob das Widget zusätzlichen Raum nutzen soll.
Das folgende Programm (stuctured_window.py) demonstriert die Anwendung dieser Optionen und erzeugt die Ausgabe in Bild 3.

Ausrichtungs- und Fülloptionen erstellt wurde.
import tkinter as tk
root = tk.Tk()
root.title("Pack Beispiel mit Textfeldern")
root.geometry("400x300")
entry1 = tk.Entry(root, bg="lightblue")
entry1.insert(0, "Oben, keine Füllung")
entry1.pack(side=tk.TOP)
entry2 = tk.Entry(root, bg="lightgreen")
entry2.insert(0, "Unten, horizontal gefüllt")
entry2.pack(side=tk.BOTTOM, fill=tk.X)
entry3 = tk.Entry(root, bg="lightyellow")
entry3.insert(0, "Links, vertikal gefüllt")
entry3.pack(side=tk.LEFT, fill=tk.Y)
entry4 = tk.Entry(root, bg="lightpink")
entry4.insert(0, "Rechts, komplett gefüllt + expandiert")
entry4.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
root.mainloop()
Zusätzlich wurden verschiedene Hintergrundfarben (bg für background) festgelegt. Die Vordergrundfarbe (Textfarbe) kann entsprechend mit dem Parameter fg (foreground) angepasst werden. Ein Beispiel dazu findet sich im Download-Paket (Colours.py).
Interaktive Steuerung: Ein digitaler Spielwürfel
Eine beliebte Anwendung für Tkinter sind einfache Spiele. Als Anregung für eigene Entwicklungen dient hier ein softwarebasierter Spielwürfel, der sein echtes Gegenstück grafisch simuliert. Wir verwenden ein Canvas-Widget zur Darstellung der Würfelaugen und einen Button, um eine Zufallszahl zwischen 1 und 6 zu „würfeln“.
import tkinter as tk
import random
# Hauptfenster erstellen
root = tk.Tk()
root.title("Würfelsimulation")
root.geometry("300x400")
# Canvas für die Würfelanzeige
canvas = tk.Canvas(root, width=200, height=200, bg="white")
canvas.pack(pady=50)
# Funktion zum Zeichnen der Würfelpunkte
def draw_dice(number):
canvas.delete("all")
# Vorherige Punkte löschen
canvas.create_rectangle(10, 10, 190, 190, outline="black", width=2)
# Würfelrahmen
# Positionen der Punkte (Mitte = 100, 100)
positions = {
1: [(100, 100)], # Mitte
2: [(50, 50), (150, 150)], # Diagonale
3: [(50, 50), (100, 100), (150, 150)], # Diagonale + Mitte
4: [(50, 50), (50, 150), (150, 50), (150, 150)], # Ecken
5: [(50, 50), (50, 150), (150, 50), (150, 150), (100, 100)], # Ecken + Mitte
6: [(50, 50), (50, 100), (50, 150), (150, 50), (150, 100), (150, 150)] # 3x3 ohne Mitte
}
# Punkte zeichnen
for pos in positions[number]:
x, y = pos
canvas.create_oval(x - 10, y - 10, x + 10, y + 10, fill="black")
# Funktion zum Würfeln
def roll_dice():
number = random.randint(1, 6) # Zufällige Zahl von 1 bis 6
draw_dice(number) # Würfel neu zeichnen
result_label.config(text=f"Gewürfelt: {number}") # Ergebnis anzeigen
# Button zum Würfeln
roll_button = tk.Button(root, text="Würfeln!", command=roll_dice, font=("Arial", 14), bg="lightgreen")
roll_button.pack(pady=20)
# Label für das Ergebnis
result_label = tk.Label(root, text="Gewürfelt: -", font=("Arial", 12))
result_label.pack(pady=10)
# Initialen Würfel zeichnen (z. B. 1)
draw_dice(1)
# Hauptschleife starten
root.mainloop()
Im Programm wird ein Fenster erstellt, in dem ein Canvas als Zeichenfläche dient. Die Positionen der Würfelpunkte sind für jede Zahl von 1 bis 6 vordefiniert:
- 1: ein Punkt in der Mitte
- 2: zwei Punkte diagonal gegenüber
- 3: drei Punkte diagonal inklusive Mitte
- 4: vier Punkte in den Ecken
- 5: vier Ecken plus Mitte
- 6: sechs Punkte in zwei Reihen
Die Funktion roll_dice erzeugt eine Zufallszahl und ruft draw_dice auf, um den Würfel neu zu zeichnen. Ein Button löst diesen Vorgang aus, und ein Label zeigt das Ergebnis an (Bild 4).

Raspberry Pi als Taschenrechner
Dass man mit Tkinter auch ernsthaftere Anwendungen programmieren kann, zeigt das folgende Beispiel: ein voll funktionsfähiger Taschenrechner als grafische Emulation (Calculator.py).
import tkinter as tk
def calculate():
try:
expression = entry.get()
result = eval(expression)
entry.delete(0, tk.END)
entry.insert(tk.END, str(result))
except Exception as e:
entry.delete(0, tk.END)
entry.insert(tk.END, "Error")
def clear():
entry.delete(0, tk.END)
root = tk.Tk()
root.title("Einfacher Taschenrechner")
entry = tk.Entry(root, width=30, borderwidth=5)
entry.grid(row=0, column=0, columnspan=4, padx=10, pady=10)
buttons = [
"7", "8", "9", "/",
"4", "5", "6", "*",
"1", "2", "3", "-",
"0", ".", "=", "+"
]
row_val = 1
col_val = 0
for button in buttons:
command = lambda b=button: calculate() if b == "=" else entry.insert(tk.END, b)
tk.Button(root, text=button, padx=20, pady=20, command=command).grid(row=row_val, column=col_val)
col_val += 1
if col_val > 3:
col_val = 0
row_val += 1
tk.Button(root, text="C", padx=20, pady=20, command=clear).grid(row=row_val, column=col_val)
root.mainloop()
Die Funktion calculate liest den Ausdruck aus dem Eingabefeld, wertet ihn mit eval() aus und zeigt das Ergebnis an. Die Tasten werden in einem Raster (Grid) platziert. Je nach gedrückter Taste wird der Wert in das Eingabefeld eingefügt, die Berechnung ausgelöst oder das Feld gelöscht. Bild 5 zeigt den fertigen Taschenrechner.

Dynamische Grafiken und Uhren
Mit Tkinter lassen sich auch dynamische, sich selbstständig aktualisierende Grafiken umsetzen. Ein schönes Beispiel hierfür ist eine programmierte Analoguhr, die einer klassischen Bahnhofsuhr nachempfunden ist (Bild 6).

import tkinter as tk
from math import sin, cos, radians
import time
class AnalogClock:
def __init__(self, root):
self.root = root
self.root.title("Analog Clock")
self.canvas = tk.Canvas(root, width=400, height=400, bg='white')
self.canvas.pack()
self.MX = 200
self.MY = 200
self.R = 190
self.draw_clock_face()
self.s1 = -1
self.update_clock()
def draw_clock_face(self):
for i in range(60):
x, y = self.get_point(self.R, i)
size = 4 if i % 5 == 0 else 2
self.canvas.create_oval(x - size, y - size, x + size, y + size, fill='black')
def get_point(self, length, angle):
w1 = radians(angle * 6 - 90)
x1 = self.MX + length * cos(w1)
y1 = self.MY + length * sin(w1)
return (x1, y1)
def update_clock(self):
zeit = time.localtime()
s = zeit.tm_sec
m = zeit.tm_min
h = zeit.tm_hour
if h > 12:
h = h - 12
hm = (h + m / 60.0) * 5
if s != self.s1:
self.canvas.delete("hands")
x, y = self.get_point(120, hm)
self.canvas.create_line(self.MX, self.MY, x, y, width=6, fill='black', tags="hands")
x, y = self.get_point(170, m)
self.canvas.create_line(self.MX, self.MY, x, y, width=4, fill='black', tags="hands")
x, y = self.get_point(180, s)
self.canvas.create_line(self.MX, self.MY, x, y, width=2, fill='red', tags="hands")
self.s1 = s
self.root.title("Aktuelle Zeit: " + time.asctime())
self.root.after(1000, self.update_clock)
root = tk.Tk()
clock = AnalogClock(root)
root.bind('<Escape>', lambda e: root.quit())
root.mainloop()
Die Uhr wird auf einem 400×400 Pixel großen Canvas gezeichnet. Zunächst wird das Zifferblatt mit Markierungen für Minuten und Stunden erstellt. Die Positionen werden mit trigonometrischen Funktionen berechnet. Die Zeiger für Stunde, Minute und Sekunde werden jede Sekunde neu gezeichnet, um die aktuelle Zeit anzuzeigen. Sie unterscheiden sich in Länge, Dicke und Farbe, um gut lesbar zu sein:
- Stundenzeiger: kurz, dick und schwarz.
- Minutenzeiger: mittellang, mitteldick und schwarz.
- Sekundenzeiger: lang, dünn und rot.
Aktive Hardwaresteuerung per GUI
Eine der wichtigsten Anwendungen von Tkinter ist die Steuerung von Hardware. Um beispielsweise eine LED am Raspberry Pi zu schalten, kombinieren wir eine Tkinter-GUI mit der GPIO-Schnittstelle (Bild 7). Die LED wird an GPIO 17 angeschlossen, und über Buttons in der GUI wird sie ein- oder ausgeschaltet.

Das Programm (LEDcontrol.py) initialisiert den GPIO-Pin als Ausgang und erstellt ein Fenster mit zwei Buttons („LED an“ und „LED aus“) sowie einem Statuslabel (Bild 8).

import tkinter as tk
import RPi.GPIO as GPIO
LED_PIN = 17
GPIO.setmode(GPIO.BCM)
GPIO.setup(LED_PIN, GPIO.OUT)
GPIO.output(LED_PIN, GPIO.LOW)
def led_an():
GPIO.output(LED_PIN, GPIO.HIGH)
status_label.config(text="LED ist AN")
def led_aus():
GPIO.output(LED_PIN, GPIO.LOW)
status_label.config(text="LED ist AUS")
root = tk.Tk()
root.title("LED-Steuerung")
root.geometry("300x200")
status_label = tk.Label(root, text="LED ist AUS", font=("Arial", 14))
status_label.pack(pady=20)
an_button = tk.Button(root, text="LED an", command=led_an, bg="lightgreen", font=("Arial", 12))
an_button.pack(pady=10)
aus_button = tk.Button(root, text="LED aus", command=led_aus, bg="lightcoral", font=("Arial", 12))
aus_button.pack(pady=10)
def cleanup():
GPIO.cleanup()
root.destroy()
root.protocol("WM_DELETE_WINDOW", cleanup)
root.mainloop()
Die Funktionen led_an() und led_aus() setzen den GPIO-Pin auf HIGH bzw. LOW und aktualisieren den Text im Statuslabel. Wichtig ist die cleanup()-Funktion, die beim Schließen des Fensters aufgerufen wird, um die GPIO-Pins sicher zurückzusetzen.
Automatisierung im Griff: Motorsteuerung
Um die Drehzahl eines kleinen DC-Motors zu steuern, erstellen wir eine GUI mit einem Schieberegler („Slider“). Die Hardwarebasis bildet ein Raspberry Pi, der den Motor über eine Transistorstufe ansteuert, da der Motor mehr Strom benötigt, als ein GPIO-Pin direkt liefern kann. Die Drehzahl wird mittels Pulsweitenmodulation (PWM) geregelt.
import tkinter as tk
from tkinter import ttk
import RPi.GPIO as GPIO
# GPIO-Setup
MOTOR_PIN = 17 # GPIO-Pin für den Motor
GPIO.setmode(GPIO.BCM) # BCM-Nummerierung
GPIO.setup(MOTOR_PIN, GPIO.OUT) # Pin als Ausgang
pwm = GPIO.PWM(MOTOR_PIN, 100) # PWM mit 100 Hz Frequenz
pwm.start(0) # Start mit 0 % Duty Cycle (Motor aus)
# Funktion zur Drehzahlsteuerung
def update_drehzahl(value):
duty_cycle = float(value) # Wert von 0 bis 100
pwm.ChangeDutyCycle(duty_cycle) # PWM anpassen
status_label.config(text=f"Drehzahl: {int(duty_cycle)}%")
# GUI erstellen
root = tk.Tk()
root.title("DC-Motor Drehzahlsteuerung")
root.geometry("300x200")
status_label = tk.Label(root, text="Drehzahl: 0%", font=("Arial", 14))
status_label.pack(pady=10)
# Rahmen für Schieberegler und Werte
frame = tk.Frame(root)
frame.pack(pady=10, padx=20, fill="x")
# Label für 0
label_min = tk.Label(frame, text="0", font=("Arial", 12))
label_min.pack(side="left")
# Schieberegler für Drehzahl (0 bis 100)
slider = ttk.Scale(frame, from_=0, to=100, orient="horizontal", command=update_drehzahl)
slider.pack(side="left", expand=True, fill="x")
# Label für 100
label_max = tk.Label(frame, text="100", font=("Arial", 12))
label_max.pack(side="right")
# Cleanup beim Schließen
def cleanup():
pwm.stop() # PWM beenden
GPIO.cleanup() # GPIO aufräumen
root.destroy() # Fenster schließen
root.protocol("WM_DELETE_WINDOW", cleanup)
# Hauptschleife starten
root.mainloop()
Die Funktion update_drehzahl wird bei jeder Änderung des Schiebereglers aufgerufen und passt den Duty Cycle des PWM-Signals an. Dadurch ändert sich die Motorgeschwindigkeit (Bild 9). Für einen sicheren Betrieb ist eine externe Spannungsquelle für den Motor empfehlenswert, um den Raspberry Pi vor Überlastung und Spannungsspitzen zu schützen (Bild 10 + Bild 11 + Bild 12).




Ergänzungen und Übungen
Erweiterungsideen zum Spielwürfel
- Animation: Wie könnte man eine kurze Animation (z. B. schnelles Wechseln der Augenzahlen) einsetzen, um den Würfel vor dem endgültigen Ergebnis „rollen“ zu lassen?
- Farben: Gestalten Sie den Würfelrahmen oder die Punkte farbig.
- Größe: Wie lässt sich die Größe des Würfels dynamisch anpassen?
Erweiterungsideen zum Taschenrechner
- Wie könnten wissenschaftliche Funktionen (Sinus, Cosinus, etc.) eingebaut werden?
- Wie kann man den Taschenrechner um grafische Funktionen, z.B. einen Funktionsplotter, erweitern?
Erweiterungsideen zur Motorsteuerung
- Was ist zu beachten, wenn man leistungsstärkere Motoren betreiben will?
- Wie könnte man die Steuerung um einen Vorwärts- und Rückwärtslauf erweitern (z.B. mit einer H-Brücke)?
Zusammenfassung und Ausblick
In diesem Artikel haben Sie die Grundlagen der interaktiven grafischen Programmierung mit Tkinter kennengelernt. Von einfachen Softwareanwendungen wie Uhren und Taschenrechnern bis hin zur Hardwaresteuerung für LEDs oder DC-Motoren sind die Möglichkeiten vielfältig. Im nächsten Beitrag werden wir uns fortgeschrittenere Anwendungen ansehen, insbesondere die Darstellung von analogen Messwerten über virtuelle Messinstrumente. Dies öffnet die Tür zu Projekten wie Wetterstationen, Motorüberwachung im Kfz-Bereich oder komplexen Hausautomatisierungen.
Material
- Raspberry Pi mit Netzteil
- Breadboard und Jumperkabel
- LED mit Vorwiderstand oder LED-Modul
- Kleiner DC-Motor
- NPN-Transistor oder Transistormodul
- Diode und Widerstand
Über den Autor
Dr. Günter Spanner ist als Autor zu den Themen Elektronik, Sensortechnik und Mikrocontroller einem weiten Fachpublikum bekannt. Schwerpunkt seiner hauptberuflichen Tätigkeit für verschiedene Großkonzerne wie Siemens und ABB ist die Projektleitung im Bereich Entwicklung und Technologie-Management. Der Dozent für Physik und Elektrotechnik hat zudem zahlreiche Fachartikel und Bücher veröffentlicht sowie Kurse und Lernpakete erstellt.