Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Grafische Benutzeroberflächen (GUIs)

Make code user-friendly. For interactive reading and executing code blocks Binder and find b10-gui.ipynb, or install Python and JupyterLab locally.

Eine grafische Benutzeroberfläche (GUI) erleichtert die Einstellung von Eingabevariablen von Skripten. Dies ist besonders nützlich für die Wiederverwendung eines Skripts, das Sie vor langer Zeit geschrieben haben, ohne das ganze Skript erneut im Detail studieren zu müssen. Obwohl es zweifelhaft ist, ob GUIs noch in Zeiten von Webanwendungen geeignet sind, müssen große und insbesondere urheberrechtlich geschützte Daten lokal verarbeitet werden. Letztlich kann für die lokale Datenverarbeitung eine GUI sehr bequem sein, selbst geschriebene, benutzerdefinierte Programme auszuführen.

Für Python stehen mehrere GUI-Bibliotheken (Pakete) zur Verfügung und dieses Kapitel baut auf der tkinter Bibliothek. Alternativen sind z.B. wxPython oder Jython(a Java Implementierung von Python2). tkinter ist eine Standardbibliothek, die nicht zusätzlich installiert werden muss. Geben Sie zum Beispiel im Terminal ein (z.B. Anaconda Prompt, PyCharm oder Linux Terminal - nicht in Python selbst):

python -m tkinter

tkinter arbeitet an den beliebtesten Plattformen (Linux, macOS, Windows) und ist nicht nur an Python, sondern auch an Ruby, Perl, Tcl (der Ursprung vontkinter) und viele weitere Sprachen. Da es Sprachen wie Ruby oder Perl unterstützt, kann tkinter sowohl für lokale GUIs als auch für Webanwendungen verwendet werden.

Die erste GUI

Der erste Schritt ist import tkinter, in der Regel unter Verwendung des Alias as tk. Mit tk.Tk() kann ein sogenanntes Elternfenster (z.B. top) erstellt werden, in dem weitere Elemente untergebracht werden. Alle weiteren Elemente werden als tk Child-Objekte des Elternfensters erstellt und im Elternfenster unter Verwendung der pack() oder grid()-Methode platziert. Hier verwenden wir die meisten pack und grid wird nützlich sein, um Elemente an einer exakten Position am Fenster zu platzieren (z.B.tk.ELEMENT.grid(row=INT, column=INT)). Um die GUI anzuzeigen, muss das Elternfenster top nach der Anordnung aller Elemente mit top.mainloop() gestartet werden. Der folgende Codeblock zeigt, wie man ein Elternfenster mit einem Labelelement (tk.Label) erstellt.

import tkinter as tk
top = tk.Tk()
a_label = tk.Label(top, text = "A label just shows some text.")
a_label.pack()
top.mainloop()
python GUI tkinter

Figure 1:Die daraus resultierende GUI.

Nach dem Aufruf der mainloop() Methode befindet sich das Fenster in einem wait Zustand. Das bedeutet, dass das Fenster darauf wartet, dass events durch User-Action ausgelöst wird (z.B. einen Klick auf einen Button). Dieser wird als eventgesteuerte Programmierung bezeichnet, wobei event-Handler anstelle eines einzigen linearen Flusses in Form einer Folge von (Python) Befehlen aufgerufen werden.

Für den Moment verwendet unser Fenster Standardwerte, zum Beispiel für den Fenstertitel, die Größe und die Hintergrundfarbe. Diese Fenstereigenschaften können mit den Attributen title, minsize oder maxsize und configure des Elternfensters top modifiziert werden:

top = tk.Tk()
a_label = tk.Label(top, text="A label just shows some text.")
a_label.pack()

top.title("My first GUI App")
top.minsize(628, 382)
top.configure(bg="sky blue")
top.mainloop()
python GUI tkinter with label config

Figure 2:Die konfigurierte GUI.

Einen Button hinzufügen, um eine Funktion anzurufen

Derzeit zeigt das Fenster nur ein (Boring-)Label und wartet auf Ereignisse, die nicht existieren. Mit einem tk.Button können wir einen Event-Trigger hinzufügen, der noch etwas zum Auslösen braucht. Dazu definieren Sie eine call_back-Funktion, die eine Infobox erstellt, die ein Objekt von showinfo von tkinter.messagebox ist (d.h. sie muss importiert werden).

from tkinter.messagebox import showinfo
# more message boxes: askokcancel, askyesno

def call_back(message):
    showinfo("This is an Infobox", message)


top = tk.Tk()
a_label = tk.Label(top, text="Here is the button.")
a_label.pack()
# add a button
a_button = tk.Button(top, text = ">> Click <<", command=lambda: call_back("Greetings from the Button."))
a_button.pack()
top.mainloop()
python GUI tkinter with button

Figure 3:Die GUI mit einer Schaltfläche, die eine Infobox anruft.

A Vanilla tkinter Programm

Der oben genannte Code blockiert Instantiate tkinter Objekte (widgets) im nichtobjektorientierten Skriptstil. Wenn wir jedoch eine GUI schreiben, wollen wir wahrscheinlich eine Anwendung (App) starten, indem wir das Skript ausführen. Deshalb werden tkinter Widgets in der Regel als Objekte von benutzerdefinierten Klassen erstellt, die typischerweise von tk.Frame erben. Der folgende Codeblock recastt daher das vorangegangene Beispiel in einen objektorientierten Code mit der Vorlage aus der section on Python classes.

Das nachfolgende Beispiel erstellt eine VanillaApp, die ein Kind von tk.Frame ist (tkinters master Frame). Die Initialisierungsmethode __init__ muss dazu anrufen tk.Frame und pack(), um das Fenster zu initialisieren. Danach können wir andere widgets wie Labels und Buttons wie zuvor platzieren. In der VanillaApp können wir auch die obige call_back-Funktion als Methode direkt implementieren. Darüber hinaus lassen Sie das Skript eigenständig laufen (nicht durch ein schönes Jupyter Notebook unterstützt) indem Sie eine if __name__ == "__main__": VanillaApp().mainloop()-Anweisung am Ende des Skripts hinzufügen (weitere Informationen über die __main__-Anweisung in der section on packages).

# define the VanillaApp class
class VanillaApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)
        self.pack()
        
        table_label = tk.Label(master, text="Do you want vanilla ice?")
        table_label.pack()
        vanilla_button = tk.Button(master, text = "I want Vanilla", command=lambda: call_back("Here is Vanilla!"))
        vanilla_button.pack()
        no_vanilla_button = tk.Button(master, text = "I want something else", command=lambda: call_back("Here is bread!"))
        no_vanilla_button.pack()
        
    def call_back(self, message):
        showinfo("This is an Infobox", message)


# instantiate a VanillaApp object
if __name__ == "__main__":
    VanillaApp().mainloop()
python GUI tkinter vanilla label button

Figure 4:Die VanillaApp GUI mit zwei Tasten und einem Label.

Machen Sie Script eine eigenständige App

Der oben genannte Codeblock, der die VanillaApp-Klasse bereitstellt, kann an eine externe Python-Datei kopiert und gespeichert werden, wie z.B. vanilla_app.py. Als nächstes in Anaconda Prompt (Windows) oder Linux Terminal starten Sie die GUI wie folgt (je nach verwendetem Python installation):

  1. Aktivieren Sie beispielsweise die erforderliche Umgebung:

    • Windows/Anaconda: conda activate flussenv

    • Linux/Virtualenv: source vflussenv/bin/activate

  2. Navigieren Sie in das Verzeichnis, in dem sich das Skript befindet (verwenden Sie cd in Windows oder Linux/macOS).

  3. Geben Sie python vanilla_app.py (oder python -m vanilla_app.py) ein, um die GUI zu starten.

Diese Befehlsfolge kann auch an eine Batch- oder Bash-Datei (.bat unter Windows) oder Shell-Skript (.sh unter Linux/macOS - alternative Dokumentation) geschrieben werden. Nach dem Schreiben und Speichern einer Batch- oder Bash-Datei, doppelklicken Sie auf die Datei, um die Python-basierte GUI zu starten.

Mehr Widgets

Es gibt viele weitere Widgets als Labels und Buttons und die untenstehende Figur zeigt einige von ihnen einschließlich:

  • Eine Definition des GUI-Fensternamens mit master.title("Window name")

  • Eine Definition des GUI-Fenstersymbols (ICO) mit master.iconbitmap("directory/icon-file.ico")

  • tk.Menu mit Dropdown-Kaskade

  • tk.Label (siehe oben)

  • tk.Button (siehe oben)

  • tk.Entry ist ein leeres Feld, in dem Nutzer Werte oder Wörter eingeben können

  • ttk.Combobox that is a drop-down menu in the master frame (tk-themed ttk widget)

  • tk.Listbox mit einem tk.Scrollbar, wobei die Scrollbar benötigt wird, um Einträge zu Listboxen zu navigieren, die nicht im sichtbaren Bereich der Listbox-Größe liegen

  • tk.Checkbutton that can be checked (ticked) to set a tk.BooleanVar() object to True (default: not checked -> False)
    Alternatively, have a look at tk.Radiobutton to enable selections from a multiple-choice frame (rather than the False-True-only frame of a checkbutton)

  • tk.PhotoImage um ein sub-sampled-Bild in der GUI anzuzeigen

python GUI tkinter with widgets entry combobox listbox checkbutton radiobutton photo image

Figure 5:GUI mit mehreren Widgets wie Menü, Label, Button, Eintrag, Combobox, Listbox, Checkbutton und PhotoImage.

Der nächste Block enthält den Code, der die tkinter Widgets in der Figur erstellt (die script, image und icon sind im Kursrepository erhältlich):

import tkinter as tk
from tkinter.messagebox import showinfo
from tkinter import ttk


class MyApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)

        self.master.title("Master Title")
        self.master.iconbitmap("gui/sample-icon.ico")

        # Set geometry: upper-left corner of the window
        ww = 628  # width
        wh = 382  # height
        wx = (self.master.winfo_screenwidth() - ww) / 2
        wy = (self.master.winfo_screenheight() - wh) / 2
        # assign geometry
        self.master.geometry("%dx%d+%d+%d" % (ww, wh, wx, wy))
        # assign space holders around widgets
        self.dx = 5
        self.dy = 5

        # Menu Bar
        self.mbar = tk.Menu(self)  # create standard menu bar
        self.master.config(menu=self.mbar)  # make self.mbar standard menu bar
        # add menu entry
        self.ddmenu = tk.Menu(self, tearoff=0)
        self.mbar.add_cascade(label="A Drop Down Menu", menu=self.ddmenu)  # attach entry it to standard menu bar
        self.ddmenu.add_command(label="Drop Down Entry 1", command=lambda: self.hello("Drop Down Menu!"))

        # Label
        self.a_label = tk.Label(master, text="A Label")
        self.a_label.grid(column=0, row=0, padx=self.dx, pady=self.dy)

        # Button
        self.a_button = tk.Button(master, text="A Button", command=lambda: self.hello("The Button!"))
        self.a_button.grid(column=0, row=1, padx=self.dx, pady=self.dy)

        # Entry
        self.an_entry = tk.Entry(master, width=20)
        self.an_entry.grid(column=0, row=2, padx=self.dx, pady=self.dy)

        # Combobox
        self.cbox = ttk.Combobox(master, width=20)
        self.cbox.grid(column=0, row=3, padx=self.dx, pady=self.dy)
        self.cbox['state'] = 'readonly'
        self.cbox['values'] = ["Combobox Entry 1", "Combobox Entry 2", "Combobox Entry ..."]
        self.cbox.set("Combobox Entry 1")
        self.cbox_selection = self.cbox.get()

        # Listbox with Scrollbar
        self.scrlbar = tk.Scrollbar(master, orient=tk.VERTICAL)
        self.scrlbar.grid(sticky=tk.W, column=1, row=4, padx=self.dx, pady=self.dy)
        self.lbox = tk.Listbox(master, height=3, width=20, yscrollcommand=self.scrlbar.set)
        for e in ["Listbox Entry 1", "Listbox Entry 2", "With Scrollbar ->", "lb entry n"]:
            self.lbox.insert(tk.END, e)
        self.lbox.grid(sticky=tk.E, column=0, row=4, padx=self.dx, pady=self.dy)
        self.scrlbar.config(command=self.lbox.yview)
        self.lbox_selection = self.lbox.get(0)

        # Checkbutton
        self.check_variable = tk.BooleanVar()
        self.cbutton = tk.Checkbutton(master, text="Tick this Checkbutton", variable=self.check_variable)
        self.cbutton.grid(sticky=tk.E, column=2, row=0, padx=self.dx, pady=self.dy)

        # Image
        logo = tk.PhotoImage(file="gui/sunny-image.gif")
        logo = logo.subsample(2, 2)  # controls size
        self.l_img = tk.Label(master, image=logo)
        self.l_img.image = logo
        self.l_img.grid(row=1, column=2, rowspan=4)
        # create a placeholder to relax layout
        tk.Label(text="                                                    ").grid(row=0, column=1)
        
    @staticmethod
    def hello(message):
        showinfo("Got Message from ...", message)


if __name__ == '__main__':
    MyApp().mainloop()

Es gibt viele weitere Optionen (widgets) und TkDocs bietet einen detaillierten, modernen Überblick über verfügbare tkinterObjekte.

tkinter

In the above example, the checkbox receives a tk.BooleanVar(), which takes a True value when a user checks the checkbox. There are more variables that can be associated with tkinter widgets (e.g., tk.Entry, tk.Listbox, or ttk.Combobox). tkinter variables correspond basically to Python data types with special methods that are required to set or retrieve (get) user-defined values of these data types. Here is an overview of tkinter variables:

  • tk.BooleanVar() ist ein boolean, das True oder False

  • tk.DoubleVar() ist ein numerischer Floating Point (float) variabel

  • tk.IntVar() ist eine numerische integer Variable

  • tk.StringVar() ist ein string (d.h. typischerweise ein Text)

Wie weiß Python, wann man einen benutzerdefinierten Wert abruft? Typischerweise möchten wir benutzerdefinierte Werte auswerten, wenn wir eine Funktion anrufen, die benutzerdefinierte Werte als Eingabeargumente empfängt. Default, vordefinierte Standardwerte in einem Skript können mit VARIABLE.set() gesetzt werden und die Benutzereinstellungen können mit VARIABLE.get() abgerufen werden. Die folgenden script und die icon sind im Kurs-Repository erhältlich.

from tkinter.messagebox import showinfo
import random

class MyApp(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master)

        self.master.title("GUI with variables")
        self.master.iconbitmap("gui/sample-icon.ico")

        # Set geometry: upper-left corner of the window
        ww = 628  # width
        wh = 100  # height
        wx = (self.master.winfo_screenwidth() - ww) / 2
        wy = (self.master.winfo_screenheight() - wh) / 2
        # assign geometry
        self.master.geometry("%dx%d+%d+%d" % (ww, wh, wx, wy))

        self.a_label = tk.Label(master, text="Enter a value to call:")
        self.a_label.grid(column=0, row=0, padx=5, pady=5)
        
        # define tk.StringVar() and assign it to an entry
        self.user_entry = tk.StringVar()
        self.an_entry = tk.Entry(master, width=20, textvariable=self.user_entry)
        self.an_entry.grid(column=1, row=0, padx=5, pady=5)

        # define Button to trigger call back
        self.a_button = tk.Button(master, text="Call Message!", command=lambda: self.message_distributor())
        self.a_button.grid(column=2, row=0, padx=5, pady=5)

        # define a Checkbutton to use either user input or a random message
        self.check_variable = tk.BooleanVar()
        self.cbutton = tk.Checkbutton(master, text="Check this box to use a random message instead of the entry", variable=self.check_variable)
        self.cbutton.grid(sticky=tk.E, column=0, columnspan=3, row=1, padx=5, pady=5)
        self.check_variable.set(False)

        
    def message_distributor(self):
        if not self.check_variable.get():
            showinfo("User message", self.user_entry.get())
        else:
            showinfo("Random message", self.random_message())
        
    def random_message(self):
        random_words = ["summer", "winter", "is", "cold", "hot", "will be"]
        return " ".join(random.sample(random_words, 3))


if __name__ == '__main__':
    MyApp().mainloop()
python GUI tkinter bound to variables

Figure 6:Die GUI an Tk-Variablen gebunden.

Design, Place und Modify Widgets

Die obigen Codebeispiele verwenden sowohl die OBJECT.grid() als auch die OBJECT.pack() Methoden (Geometriemanager) um Widgets in der GUI zu platzieren. Es gibt einen zusätzlichen Geometriemanager in Form der place-Methode. Die Wahl eines bequemen Geometriemanagers hängt von Ihren Vorlieben ab und es gibt Pros und Kons für die drei Geometriemanager:

  • pack

    • automatisch Widgets innerhalb einer Box

    • funktioniert am besten für einfache GUIs, wo alle Widgets in einer Spalte oder Zeile

    • komplexe Layouts können nur mit komplizierten Workarounds bearbeitet werden (Tip: nicht versuchen)

  • place

    • Stellt Widgets an absoluten oder relativen x-y Positionen

    • funktioniert gut für grafische Arrangements von Widgets

  • grid

    • legt Widgets in Spalten und Zeilen eines Gitters

    • funktioniert gut mit tischartigen Apps und strukturierten Layouts

Um mehr grafische Flexibilität zu ermöglichen, akzeptieren Widgets viele optionale Keywords, um ihren Vordergrund (fg) oder Hintergrund (bg) zu ändern. Darüber hinaus können Widgets mit der Methode tk.OBJECT.config(PARAMETER_TO_CONFIGURE=NEW_CONFIG) geändert werden.

In den folgenden Abschnitten finden Sie weitere Informationen zu den Geometriemanagern place und grid (die relevanten Funktionen von pack sind bereits oben dargestellt: pack() - das ist alles) und veranschaulichen Keyword-Argumente zusammen mit Widget-Methoden zur Änderung von Widgets.

Platz mit place und Objektfarben verwenden

Der einfachste Geometriemanager ist die pack-Methode, die auch ohne Keyword funktioniert (siehe die ersten Beispiele in diesem Abschnitt). Mit der Methode pack können Widgets relativ im Fenster platziert werden (relx und rely, wobei beides < 1) sein muss oder mit absoluten Positionen (x und y, wobei beides in die durch self.config(width=INT, height=INT) definierten Fensterabmessungen passen sollte). Der Achsenursprung (Nullpositionen von x und y) wird mit dem anchorkeyword bestimmt.

class PlacedApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.pack(expand=True, fill=tk.BOTH)
        self.config(width=628, height=100)
        self.master.title("A placed GUI")
        tk.Label(self, text="Vanilla", bg="goldenrod", fg="dark slate gray").place(anchor=tk.NW, relx=0.2, y=10)
        tk.Label(self, text="Green green tree", bg="OliveDrab1").place(anchor=tk.E, relx=0.8, rely=0.5)
        tk.Label(self, text="Blue sky", bg="DeepSkyBlue4", fg="floral white").place(anchor=tk.CENTER, x=300, rely=0.8)


if __name__ == '__main__':
    PlacedApp().mainloop()
python GUI tkinter using placed

Figure 7:Die GUI organisierte mit platzierten Widgets.

Objekte mit grid

In grid-ed GUIs kann die Widget-Ausrichtung mit dem sticky-Argument gesteuert werden, das Kardinalrichtungen verwendet (z.B. sticky=tk.Wausrichtet oder “sticks” ein Widget im Westen, d.h. linke Seite eines GUI). Die Argumente padx und pady Keywords ermöglichen die Implementierung von Pixelraum um Widgets.

from tkinter.messagebox import showinfo

class GriddedApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.pack(expand=True, fill=tk.BOTH)
        self.config(width=628, height=100)
        self.master.title("A grid GUI")
        tk.Label(self, text="Enter name: ", bg="bisque2", fg="gray21").grid(sticky=tk.W, row=0, column=0, padx=10)
        tk.Entry(self, bg="gray76", width=20).grid(sticky=tk.EW, row=0, column=1, padx=5)
        tk.Button(self, text="Show message", bg="pale turquoise", fg="red4", command=lambda: showinfo("Info", "Random message")).grid(row=0, column=2, padx=5)
        tk.Checkbutton(self, text="A Checkbutton over multiple columns").grid(sticky=tk.E, row=1, column=0, columnspan=3, pady=15)


if __name__ == '__main__':
    GriddedApp().mainloop()
python GUI tkinter structured as grid

Figure 8:Die GUI organisierte auf einem Gitter.

Widgets konfigurieren

Bei der Benutzeraktion (ein Ereignis) möchten wir möglicherweise zuvor definierte Widgets ändern. Zum Beispiel möchten wir den Text eines Etiketts oder das Layout eines Buttons ändern, um erfolgreiche oder gescheiterte Operationen anzuzeigen. Dazu können tkinter Objekte mit tk.OBJECT.config(PARAMETER_TO_CONFIGURE=NEW_CONFIG) modifiziert werden. Darüber hinaus können Objekte mit tk.OBJECT.destroy() gelöscht werden, obwohl dies keine elegante Methode für andere Widgets ist als Pop-up-Fenster (Kindrahmen des Master-Rahmens).

from tkinter.messagebox import showinfo, showerror

class ReConfigApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.config(width=628, height=100)
        self.pack()
        
        self.user_depth = tk.DoubleVar()
        self.kst = 40.0
        self.w = 5.0
        self.slope = 0.002
        
        self.master.title("A GUI that reconfigures its widgets")
        tk.Label(self, text="Enter flow depth (numeric, in meters): ", bg="powder blue", fg="medium blue").grid(sticky=tk.W, row=0, column=0, padx=10)
        tk.Entry(self, bg="alice blue", width=20, textvariable=self.user_depth).grid(sticky=tk.EW, row=0, column=1, padx=5)
        self.eval_button = tk.Button(self, text="Estimate flow velocity", bg="snow2", fg="dark violet", command=lambda: self.call_estimator())
        self.eval_button.grid(row=0, column=2, padx=5)
        
    def call_estimator(self):
        try:
            flow_depth = float(self.user_depth.get())
        except tk.TclError:
            return showerror("ERROR", "Non-numeric value entered.")
        self.eval_button.config(fg="green4", bg="DarkSeaGreen1")
        showinfo("Result", "The estimated flow velocity is: " + str(self.estimate_u(flow_depth)))
        
    def estimate_u(self, h):
        try:
            return self.kst * h**(2/3) * self.slope**0.5
        except ValueError:
            showerror("ERROR: Bad values defined.")
            return None
        except TypeError:
            showerror("ERROR: Bad data types defined.")
            return None
        

if __name__ == '__main__':
    ReConfigApp().mainloop()
python GUI tkinter re-configured

Figure 9:Die neu konfigurierte GUI.

Pop-up Windows

Standardnachrichten von tkinter.messagebox

Die tkinter.messagebox Bibliothek bietet Standard-Pop-up-Fenster wie:

  • showinfo(title=STR, message=STR), die eine Informationsbotschaft ausdruckt (siehe oben Beispiele).

  • showwarning(title=STR, message=STR), die eine Warnmeldung ausdruckt.

  • showerror(title=STR, message=STR), die eine Fehlermeldung ausdruckt (siehe oben Beispiel).

  • askyesno(title=STR, message=STR) that returns False or True depending on a user’s answers to a Yes-or-No question.

  • askretrycancel(title=STR, message=STR), die False oder True zurückgibt, oder re-attempts, um eine Veranstaltung (Funktion) in Abhängigkeit von den Antworten eines Benutzers auf eine Yes-or-No-or-Cancel Frage auszuführen.

  • askokcancel(title=STR, message=STR) that returns False or True depending on a user’s answers to an OK question.

Lesen Sie mehr über Standard-Pop-up-Fenster in der Python docs.

Benutzerdefinierte Pop-ups auf höchstem Niveau

Die Standardfenster können nicht den Anforderungen für jede Anwendung entsprechen, zum Beispiel, um Benutzer einzuladen, einen benutzerdefinierten Wert einzugeben. In diesem Fall hilft ein tk.Toplevel Objekt bei der Erstellung eines kundenspezifischen Pop-up-Fensters, und das folgende Beispiel zeigt, wie ein kundenspezifisches Top-Level Pop-up-Fenster innerhalb einer Methode aufgerufen werden kann. Mit dem tk.Toplevel Widget und den tk.Frame(master) Widgets produziert der Codeblock zwei Frames, in denen Buttons, Labels oder andere tkinterObjekte platziert werden können. Das erste Argument eines erstellten tkinterwidget-Objekts bestimmt, ob das Objekt im Master oder im Top-Level-Rahmen platziert wird. Beispielsweise erstellt tk.Entry(self).pack() einen Eintrag im Mastertk.Frame, und tk.Entry(pop_up).pack() erstellt einen Eintrag im Kind tk.Toplevel.

from tkinter.messagebox import showwarning

class PopApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.config(width=628, height=50)
        self.pack()
        
        self.master.title("Custom pop-up GUI")
        self.pop_button = tk.Button(self, text="Open pop-up window", bg="cadet blue", fg="white smoke", command=lambda: self.new_window())
        self.pop_button.pack()
        
    def destroy_buttons(self):
        self.pop_button.destroy()
        self.p_button1.destroy()
        self.p_button2.destroy()        
        showwarning("Congratulations", "This app is useless now. Don't press red-ish buttons ...")
        
    def new_window(self):
        pop_up = tk.Toplevel(master=self)
        # add two buttons to the new pop_up Toplevel object (window)
        self.p_button1 = tk.Button(pop_up, text="Destroy buttons (do not click here)", fg="DarkOrchid4",
                                   bg="HotPink1", command=lambda: self.destroy_buttons())
        self.p_button2 = tk.Button(pop_up, text="Close window", command=lambda: pop_up.quit())  
        self.p_button1.pack()
        self.p_button2.pack()


if __name__ == '__main__':
    PopApp().mainloop()
python tkinter popup window customized

Figure 11:Die GUI mit kundenspezifischem Popup-Fenster.

Dateidialog (Open ...)

Wenn das Argument einer benutzerdefinierten Funktion ein Datei- oder Dateiname ist, möchten wir höchstwahrscheinlich, dass der Benutzer den benötigten Dateityp auswählen kann. Die Bibliothek tkinter.filedialog bietet Methoden, um Benutzer allgemeine oder bestimmte Dateitypen wählen zu lassen. Spezifische Dateitypen können mit dem filetypes=("Name", "*.ending") (oder filetypes=("Name", "*.ending1;*.ending2;...") für mehrere Dateitypen) Keyword Argument definiert werden. Das folgende Beispiel veranschaulicht die Nutzung von tkinter.filedialog’s askopenfilename.

from tkinter.filedialog import askopenfilename
from tkinter.messagebox import showinfo

class OpenFileApp(tk.Frame):
    def __init__(self, master=None, **options):
        tk.Frame.__init__(self, master, **options)
        self.config(width=628, height=50)
        self.pack()
        
        self.master.title("GUI to open a file")
        
        self.pop_button = tk.Button(self, text="Open a text file", bg="light steel blue", fg="dark slate gray", command=lambda: self.open_file())
        self.pop_button.pack()
        
    def open_file(self):
        file_types = (("Text", "*.txt;*.csv;*.asc"),)  # equivalent to [("Text", "*.txt;*.csv;*.asc")]
        file_name = askopenfilename(initialdir=".", title="Select a text file", filetypes=file_types, parent=self)
        showinfo("File info", "You selected " + str(file_name))


if __name__ == '__main__':
    OpenFileApp().mainloop()
python tkinter with filedialog

Figure 12:Die GUI mit Filedialog, um eine Datei auszuwählen.

Quitten

Um eine GUI sauber zu beenden, verwenden Sie tk.Frame.quit() (d.h. in einer benutzerdefinierten Klasse, schreiben Sie self.quit() oder master.quit()). Das obige Beispiel der PopApp-Klasse enthält auch die destroy()-Methode, die dazu beiträgt, bestimmte Widgets zu entfernen.

tkinter bietet viele weitere Optionen wie die Implementierung von Tabs mit ttk.Notebook() (erfordert binden der Tab-Objekte), Tabellen (from tkintertable import TableCanvas, TableModel) oder interaktive grafische Objekte mit matplotib.

import matplotlib
matplotlib.use('TkAgg')
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure

Genießen Sie die Erstellung Ihrer benutzerdefinierten Apps!

Erfolgsprüfung lernen

Nehmen Sie den Lernerfolgstest für dieses Jupyter Notebook.