Master-Detailansicht mit Python und Tkinter

Master-Detail-Ansichten werden häufig in GUI-Anwendungen verwendet, um zusammengehörige Daten hierarchisch anzuzeigen. Wir zeigen dazu zwei Implementierungen in Tkinter mit Python.

In unserem ersten Ansatz verwenden wir tk.Listbox zur Darstellung einer Liste von Items und ein tk.Label Element für die Detailansicht eines gewählten Items. Natürlich kann statt des Label-Elements auch eine komplexe UI verwendet werden. In dem Beispiel geht es nur um die Grundlegende Funktionsweise zwischen der Listen- und Detaildarstellung:

import tkinter as tk

# Array mit Beispieldaten
items = [
    {'name': 'JBerries 1', 'beschreibung': 'Das sind Details zu JBerries 1'},
    {'name': 'JBerries 2', 'beschreibung': 'Das sind Details zu JBerries 1'},
    {'name': 'JBerries 3', 'beschreibung': 'Das sind Details zu JBerries 1'},
]

root = tk.Tk()

# Listbox Element
listbox = tk.Listbox(root)
listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

# Beispieldaten in die UI einfügen
for item in items:
    listbox.insert(tk.END, item['name'])

# Details Label
detail_frame = tk.Frame(root)
detail_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

# Callback um die Detailansicht aufzurufen
def on_select(event):
    # Index des selektierten Items
    index = event.widget.curselection()[0]

    # Zu dem Idex das Element aus der Liste auswählen
    item = items[index]

    # Detailansicht aktualisieren
    name_label.configure(text=item['name'])
    details_label.configure(text=item['beschreibung'])

# Binden des Callbacks an das ListboxSelect-Event
listbox.bind('<<ListboxSelect>>', on_select)

# Detailansicht
name_label = tk.Label(detail_frame, font=('Arial', 20))
name_label.pack(side=tk.TOP, pady=10)

details_label = tk.Label(detail_frame, font=('Arial', 12))
details_label.pack(side=tk.TOP, padx=10)

root.mainloop()

Im ersten Schritt wird die Listenansicht mit den Beispieldaten aufgebaut. Um die Detaildarstellung anzuzeigen, benutzen wir einen on_select Listner: Aus dem event.widget.curselection Event bekommen wir den Index des selektierten Items und können damit das zugehörige Objekt aus dem Array holen. Anschliessend müssen wir nur noch das Label über details_label.configure(text=item['beschreibung']) aktualisieren.

In zweiten Ansatz verwenden wir ttk.Notebook :

root = tk.Tk()
root.title("Master/Details mit ttk.Notebook")

# Notebook (tabs container)
notebook = ttk.Notebook(root)

style_tab = ttk.Style()
style_tab.layout('TNotebook.Tab', [])

# Tabs für Übersicht bzw. Detailansicht
tab_overview = ttk.Frame(notebook)
tab_details = ttk.Frame(notebook)

command_details = lambda: notebook.select(tab_details)
tk.Label(tab_overview, text="Übersicht").pack()
tk.Button(tab_overview, text="Zur Detailansicht", command=command_details).pack()

command_overview = lambda: notebook.select(tab_overview)
tk.Label(tab_details, text="Details").pack()
tk.Button(tab_details, text="Zurück zur Übersicht", command=command_overview).pack()

notebook.add(tab_overview, text="")
notebook.add(tab_details, text="")
notebook.pack()

root.mainloop()

Eigentlich verwendet man ttk.Notebook um Tabs anzuzeigen. Der Trick hier ist, dass wir nur zwei Tabs benutzen und zwischen diesen für die Übersicht bzw. Detailsdarstellung umschalten. Dabei ändern wir mit style_tab.layout('TNotebook.Tab', []) das Styling der Tabs des ttk.Notebook so, dass die eigentlichen Tabs gar nicht sichtbar sind.