Programmieren lernen am Raspberry Pi – Teil 3: GUI erstellen

In den vorherigen beiden Teilen haben wir grundlegende Funktionen und die Nutzung der programmierbaren GPIOs kennengelernt. Üblicherweise wird von den meisten Nutzern erwartet, dass ein Programm auch eine grafische Oberfläche hat, um bestimmte Funktionen zu steuern.

Darum geht es im dritten Teil: Wir erstellen mit Hilfe von der Bibliothek Tkinter eine grafische Oberfläche. Mit Hilfe dieser können u.a. auch GPIOs gesteuert werden. Schlussendlich wartet am Ende des Tutorials noch eine Aufgabe darauf gelöst zu werden.

 

Zubehör

Auch hier wieder vorweg der Hinweis, dass das Tutorial nur einen Teil des Ganzen umfasst. Gerade da die Erstellung eines User Interface eine ganz eigene Geschichte für sich ist und die von uns verwendete Bibliothek sehr viel mehr Funktionen hat, als wir in diesem Tutorial behandeln, ist der Blick in eines der Python Nachschlagewerke immer nützlich.

Da wir in diesem Teil jedoch primär keine Hardware ansprechen, ist neben dem Raspberry Pi nichts weiter nötig. Du solltest allerdings den Pi entweder per HDMI an einen Bildschirm verbunden haben, oder aber dich per Remotedesktopverbindung über deinen PC verbinden. Besonders gut lässt sich eine grafische Oberfläche auch mit z.B. dem Raspberry Pi Touchscreen verbinden.

Am Ende des Tutorials stelle ich noch eine Aufgabe, für diejenigen die das Gelernte gleich selbst umsetzen wollen (keine Sorge – die Lösung gibt es auch). Dazu ist weiterhin folgendes nötig:

 

Vorbereitung

Die Bibliothek von Tkinter ist nicht immer installiert, daher ist dies der erste Schritt. Wir öffnen ein neues Terminal Fenster (geht auch per SSH) und geben folgendes ein:

sudo apt-get install python python-tk idle python-pmw python-imaging --yes

Nachdem alles durchgelaufen ist, kannst du den Dateiexplorer öffnen und im Homeverzeichnis (/home/pi) einen neuen Ordner mit dem Namen „python-GUI“ (ohne Anführungszeichen) per Rechtsklick anlegen. Öffne diesen Ordner nur erstelle per Rechtsklick -> Create New -> Empty File eine Datei mit dem Namen „gui.py“ (ohne Anführungszeichen).

Durch Rechtsklick auf diese Datei kannst du sie mit verschiedenen Editoren bearbeiten. Ein Klick auf Open öffnet sie mit dem Standardeditor, worin wir gleich unseren Code schreiben.

Du könntest die folgenden Schritte auch sequentiell wie zuvor in der Python Konsole ausführen. Dies bietet sich dann an, wenn du die Funktionalität der aufgerufenen Befehle nachvollziehen willst – ist allerdings im Produktivbetrieb nicht all zu sinnvoll.

 

In jenem Skript importieren wir als aller erstes die Bibliothek:

Achtung: Wenn du Python 2.7 verwendest, muss Tkinter groß geschrieben, wohingegen es bei der Verwendung von Python 3 klein geschrieben wird.

 

 

GUI erstellen

Zunächst fügen wir den einfachen Aufbau ein, damit ein leeres Fenster erstellt wird. Später definieren wir die Elemente, welche angezeigt werden sollen. Zunächst aber geben wir lediglich den Titel und die Hintergrundfarbe des Fensters an. Die Farbe wird dabei durch einen RGB Hex Wert angegeben, wobei #FFFFFF für Weiß steht.

Dies ist der Code, den wir einfügen:

Wir öffnen ein Terminal und wechseln in das Verzeichnis (cd ~/python-GUI). Dort starten wir das Skript:

sudo python3 gui.py

In der unteren Ecke öffnet sich nun unser definiertes Fenster:

Nun kann unser grafisches Interface noch nichts, außer sich öffnen. Daher wollen wir in den nächsten Schritten Elemente hinzufügen. Jeglicher Code kommt zwischen Zeile 8 und 10.

 

Frames

Damit unser Programm eine Struktur bekommt, müssen wir uns zunächst Gedanken zum Layout machen. Ich habe testweise folgenden Aufbau vorgesehen:

Dabei können beide Seiten über sog. Frames definiert werden. Ein Frame braucht ein übergeordnetes Element (in welchem es eingefügt wird) sowie seine Höhe und Breite.

Darüber hinaus können wir die Position des Frames in seinem übergeordnetem Element angeben. Stelle dir dabei vor, dass jedes Element eine Art Gitter hat und wir die Reihe und Spalte angeben. Da wir zwei nebeneinander platzierte Frames haben möchten, befinden diese sich in der selben Zeile, allerdings in einer anderen Spalte:

Unser resultierendes Ergebnis sieht nun folgend aus:

Wie du siehst haben beide Frames auch einen Abstand zu den Seiten. An den horizontalen Kanten ist dieser 10 Pixel und an den vertikalen nur 3 Pixel (padx und pady). Übrigens ist es auch bei diesen Elementen möglich die Hintergrundfarbe etc. einzustellen.

Die Elemente innerhalb eines Frames werden nach der Initialisierung dieses Frames angegeben.

 

Labels (und Bilder)

Labels sind quasi Beschriftungen – also Texte, die nicht bearbeitet werde können. Diese sind z.B. für  Infoboxen oder andere Informationen zu nutzen. Im folgenden habe ich zwei Beispieltexte im linken Frame eingefügt, welche untereinander angezeigt werden. Der Text kann auch Zeilenumbrüche enthalten, indem man \n in der Zeichenkette nutzt:

Labels können außerdem dazu genutzt werden, um Bilder anzuzeigen. Falls wir bereits ein Bild gespeichert haben, können wir dieses nutzen. Ansonsten geben wir im Terminal einfach kurz folgenden Befehl ein, womit wir ein Platzhalter Bild herunterladen:

wget http://placehold.it/200x200

Mit einem zusätzlichen Parameter können wir dem Label ein Bild zuweisen:

Führen wir das Skript aus, bekommen wir ein folgendes Programm zu Gesicht:

Wie du siehst, passt sich der Platz des Frames an. Mit einem größeren Y-Padding könnten wir den Frame wieder vergrößern.

 

Eingabefelder (Inputs)

Nun kommen wir zum rechten Frame. Als erstes wollen wir hier eiu Eingabefeld erstellen, welches später z.B. für Benutzereingaben genutzt werden kann.

Ein solches Feld erstellen wir mit diesem Befehl:

Die Breite ist hier allerdings nicht in Pixeln, sondern in Zeichen angegeben, welche gleichzeitig angezeigt werden können.

Was du noch für das Eingabefeld definieren kannst, steht in der Dokumentation.

 

Button

In dem Layout von oben sind als nächstes zwei Buttons zu sehen. Nun sollen diese natürlich auch Funktionen bekommen. Dazu soll der rote Knopf die Eingabe des vorher erstellten Textfelds auslese und der gelbe Button einfach das Ergebnis aus 1+1 ausgeben (da dies nur zu Vorführungszwecken dient, sehen wir mal über die Sinnhaftigkeit des gelben Buttons hinweg 😉 ).

Wir erstellen dazu erst einmal zwei Funktionen, wovon die erste nur den Wert des eben erstellen Textfeldes (E1) ausließt und im Terminal ausgibt. Die zweite Funktion, gibt einfach „2“ aus. Die Funktionen werden gleich den Buttons übergeben.

def callback1():
    print(E1.get())
 def callback2():
    print(1 + 1)

Bevor wir nun die Buttons erstellen, öffnen wir noch ein weiteres Layout für die horizontal angeordneten Buttons.
Die Buttons an sich sind schnell erstellt und bekommen einen Text, eine Hintergrundfarbe („bg“ in HEX), eine Breite (width) sowie eine Funktion (command). Diese Funktion wird aufgerufen, sobald der jeweilige Button gedrückt wurde.

Wenn wir nun etwas eingeben und Button 1 drücken, erscheint die Eingabe im Terminal:

 

Slider / Schieberegler

Zu guter Letzt wollen wir noch einen Slider erstellen. Dieser ist quasi eine grafische Darstellung eines numerischen Eingabefelds mit vordefinierten Bereich (z.B. von 0-180). In der unteren Aufgabe wird dieser auch gebraucht. Darüber hinaus kann die Schrittgröße (resolution) angegeben werden, was im Endeffekt der Genauigkeit entspricht.

Den Code erweitern wir wie folgt:

Und damit ist unser Programm auch fertig:

Tipp: Auch bei Slidern kann wieder der Command Parameter genutzt werden (allerdings sollte die Funktion dafür einen Eingabeparameter akzeptieren).

 

Weiteres

Neben den hier vorgestellten Elementen, gibt es noch viele weitere, u.a. Canvas, mit welchen man Zeichnungen / Skizzen erstellen kann. Da dies den Rahmen des Tutorials sprengen würde, leite ich an dieser Stelle mal auf die Dokumentation weiter, da dort auch alle verfügbaren Komponenten aufgelistet sind. Auf den Unterseiten findest du außerdem noch Beispielcode.

 

Zusammenfassung & Ausführung

Falls du bei einem der Punkte nicht mitgekommen bist bzw. du dein Skript noch einmal vergleichen willst, gibt es hier noch einmal die komplette Fassung:

Du kannst diesen Code z.B. per SSH oder FTP ganz einfach auf den Raspberry Pi laden. Falls du dich per SSH verbunden hast, rufst du folgenden Befehl im entsprechenden Ordner auf:

sudo nano gui.py

Nachdem du den Code eingefügt hast (geht in Putty per Rechtsklick), speicherst du mit STRG+O. Anschließend kehrst du mit STRG+X in die Kommandozeile zurück.

Die Ausführung solltest du allerdings nicht von der Remote-Kommandozeile ausführen, sondern im Desktop Modus:

sudo python3 gui.py

 

Testaufgabe + Lösung

Wie versprochen gibt es noch eine kleine Testaufgabe: Erstelle eine neue Programmoberfläche, die lediglich einen Slider enthält, mit welchem ein GPIO gesteuert wird. Im Speziellen soll der Winkel eines Servomotors gesteuert werden.

Falls du noch nicht mit Servomotoren vertraut bist, hilft ein Blick in dieses Tutorial. Im nächsten Teil dieser Reihe werden wir PWM noch genauer betrachten.

Falls du soweit bist (oder nicht weiter kommst) findest du hier die Lösung:

Übrigens: Da Python und Tkinter ebenso auf Windows und MacOS laufen, kann damit natürlich auch eine Programmoberfläche für PCs und Macs erstellt werden.

28 Kommentare

  1. Geile Sache, das!!!
    Damit komm ich nen Riesenschritt weiter in meinem Projekt…

    Super Tut!!!

    Fragen hab ich trotzdem…
    Frage 1: Benötigt der Raspi dafür ne Desktopumgebung, oder läuft diese GUI auch ohne?

    Frage 2: Wie kann man Registerkarten / Reiter programmieren?

    LG Skipper

    Antworten
      • Hallo Felix…

        Zu 1.
        Anzeigen will ich das ganze auf nem kleinen Touchscreen, wollte mir aber – wenn möglich – die Desktopumgebung einsparen, zumal diese GUI immer im Vollbild ausgeführt werden und auch direkt beim Start geladen werden soll..

        Zu 2.
        Genau diese Dinger meinte ich.. Früher hießen die mal „Reiter“ oder „Registerkarten“, heute heißen sie dann eben „Tabs“…

        Ich hätte die Tabs gern am unteren Bildschirmrand, geht das auch?

        LG Skipper

      • Hey,
        naja, auf dem Touchscreen würde ja auch eine Desktopumgebung angezeigt werden (auch wenn es im Vollbild ist).
        Bzgl der zweiten Frage: Schau mal hier, da hat jemand ein Beispiel gepostet.
        LG, Felix

  2. das find ich ja klasse
    mit übungsaufgaben wie ich es vorgeschlaegn hatte leider kann ich die derzeit nich machen muss erst ein neune pi ordern. meiner ist an die wand gedübelt und macht mit dem ws2812b und hyperion meine stube bund 🙂

    aber ich holle es nach versprochen

    Antworten
  3. Ich habe ein Problem
    Nachdem ich fleissig eingetippt hab und auch nachdem ich nochmal alles per drag and drop eingefügt hab bekomme ich folgende Fehlermeldung

    pi@vaexthus1:~/python-GUI $ sudo python3 gui.py
    File „gui.py“, line 24
    print(E1.get())
    ^
    IndentationError: expected an indented block

    Wie gesagt, es handelt sich um den Originalcode

    Antworten
  4. Hi,
    bei mir klappt bereits das Einrichten des Fensters nicht. Wenn ich das Fenster starte bekomme ich in der letzten Zeile root.mainloop() einen SyntaxError angezeigt „root“ ist rot hinterlegt (python 3.4.2)
    Was ist da los?
    Martin

    Antworten
      • ja,habe ich. Allerdings genau abgeschrieben Zeile 3:
        root = Tk() #…
        auch nach Änderung in root=tk() gleiches Ergebnis. Den Ordner python-GUI und darin die Datei gui.py habe ich auch zuvor erstellt, und auch tkinter (nicht, denn war schon vorher) installiert – kleingeschrieben wg. python3.

  5. Hi,
    bei mir kommt, sobald man versucht den Platz fuer das Bild einzufuegen die Meldung, dass das Bild nicht existiert.
    Es liegt an folgendem Teil des Codes (Habs in der Shell getestet):
    imageEx = PhotoImage(file = ‚200×200‘)
    und
    Label(leftFrame, image=imageEx).grid(row=2, column=0, padx=10, pady=3)

    Die Meldung zum Ersten:

    Traceback (most recent call last):
    File „“, line 1, in
    imageEx = PhotoImage(file = ‚200×200‘)
    File „/usr/lib/python3.4/tkinter/__init__.py“, line 3419, in __init__
    Image.__init__(self, ‚photo‘, name, cnf, master, **kw)
    File „/usr/lib/python3.4/tkinter/__init__.py“, line 3375, in __init__
    self.tk.call((‚image‘, ‚create‘, imgtype, name,) + options)
    _tkinter.TclError: couldn’t open „200×200“: no such file or directory

    Und zum zweiten:

    Traceback (most recent call last):
    File „“, line 1, in
    Label(leftFrame, image=imageEx).grid(row=2, column=0, padx=10, pady=3)
    NameError: name ‚imageEx‘ is not defined

    Ich hab echt keine Ahnung
    Danke fuer deine Hilfe 🙂

    Antworten
  6. Hallo Felix,
    da sich das alles für mich besser auf dem Bildschirm meines Notebooks darstellt und bearbeiten lässt, habe ich mir python 3.5.1 auf dem Notebook installiert. Für Arbeiten am GUI ist es nicht nötig, dass ich den Pi benutze, da ja alles sich nur am Bildschirm abspielt und kein Zugriff auf die Pins der GPIO gebraucht wird.
    Bis zum Einbinden der Grafik geht das. Den Befehl „wget http://placehold.it/200×200“ kann ich allerdings mit einem Windows-Rechner nicht nachvollziehen. Wie kann ich – unter python3 auf Windows-Rechnern- ein (vorhandenes) Foto oder Bild in das GUI einfügen?
    Gruß Martin

    Antworten
  7. Evtl. eine dumme Anfängerfrage…
    Aber ich würde das „GUI“ gerne im Browser, also Remote ausführen. Kannst Du da evtl. noch ein Tutorial machen ?

    Also ähnlich im obigen Beispiel den Servomotor ansteuern, aber eben über dem Browser von einem PC, oder Tablett aus….

    Antworten
  8. Ich hoffe mir kann von euch jemand helfen.

    Wie kann ich einen Frame z.B. wie in Zeile 8 und 9 mit einer bestimmte Farbe („#99ccff“)
    Füllen?? Quasie wie beim Background.

    Danke schonmal im Vorraus!

    LG Unimogler

    Antworten
  9. Hi
    Ich habe das Programm etwas geändert um ein Motor rechts oder links laufen zu lassen und die Geschwindigkeit mit einem Slider zu regeln nur ist das Problem das wenn ich links rum laufen lasse ist bei dem Regler 100% = 0% und 0% = 100

    Antworten
  10. Hallo,
    Ich habe das Programm etwas umgeschrieben, so dass ich die GPIO pins ansteuern kann, (mit einem Button „GPIO high“, mit dem anderen „GPIO low“) funktioniert auch soweit. Jetzt meine frage: ist es möglich, mit dem selben Button einen GPIO Pin Ein und Aus zu Schalten?
    Vielen Dank im Vorraus
    Mfg

    Antworten
  11. Super Anleitung. Ich möchte beim Start des reapberry, das das programm ausgeführt und auf dem touchdisplay angezeigt wird. Wie stelle ich da an?

    Antworten
  12. Hallo Felix. Das erste Fenster wird bei mir erst garnicht dargestellt. Ich habe alles nach deiner Beschreibung gemacht (hoffe ich). Um einen Fehler zu finden, hier mein Skript:
    Die Datei „gui.py“

    from tkinter import *
    
    root = Tk() # Fenster erstellen
    root.wm_title("Raspberry Pi GUI") # Fenster Titel
    root.config(background = "#FFFFFF") # Hintergrundfarbe des Fensters
    
    # Hier kommen die Elemente hin
    
    root.mainloop() # GUI wird upgedated. Danach keine Elemente setzen

    Fehlermeldung nach ausführen des Befehls „sudo python3 gui.py“

    pi@raspberrypi:~/python-GUI $ sudo python3 gui.py
    Traceback (most recent call last):
    File „gui.py“, line 3, in
    root = Tk() # Fenster erstellen
    File „/usr/lib/python3.5/tkinter/__init__.py“, line 1880, in __init__
    self.tk = _tkinter.create(screenName, baseName, className, interactive, wantobjects, useTk, sync, use)
    _tkinter.TclError: no display name and no $DISPLAY environment variable

    Das File „/usr/lib/python3.5/tkinter/__init__.py“ ist vorhanden.

    Kannst du etwas damit anfangen, ich nicht?

    Antworten
    • Hast du das ganze über SSH versucht zu starten? Wenn ja, hast du X11 o.ä. installiert? Falls nein, kann das so nicht klappen (GUI braucht ein Display).

      Antworten
  13. Hallo Felix, habe die halbe Nacht versucht, den Fehler zu finden. Des Rätzels Lösung ist: der Befehl zu starten des Skrips muss wohl offentsichtlich im Terminal des Raspi erfolgen, denn da geht das konstruierte Fenster auf. Ich hatte es per SSH in Putty auf dem PC versucht.

    Antworten

Hinterlasse einen Kommentar

Deine Email Adresse wird nicht veröffentlicht.

Blog abonnieren

Abonniere Raspberry Pi Tutorials, um kein Tutorial mehr zu verpassen!