Der pack-Manager

Experimente mit dem pack-Manager

Der pack-Manager (bzw. Packer) bestimmt die Anordnung von GUI-Komponenten automatisiert unter Berücksichtigung von Vorgaben im Programm.

Einige der vielen verschiedenen Gestaltungsmöglichkeiten mit dem pack-Manager sollen hier anhand einfacher GUIs aufgezeigt werden.

Beispiel 1: Aufruf der pack-Methode

Die pack-Methode wird hier ohne Parameter aufgerufen.

from tkinter import *
tkFenster = Tk()

label1 = Label(master=tkFenster, text="0", bg="red", fg="white")
label1.pack()
label2 = Label(master=tkFenster, text="1", bg="green", fg="black")
label2.pack()
label3 = Label(master=tkFenster, text="2", bg="blue", fg="white")
label3.pack()
label4 = Label(master=tkFenster, text="3", bg="yellow", fg="black")
label4.pack()

tkFenster.mainloop()

Das Programm erzeugt die folgende GUI:

Anwendungsfenster

Beachte, dass die Größe des Fensters hier vom pack-Manager bestimmt wird. Die einzelnen GUI-Komponenten werden mit dem Aufruf der pack-Methode in das Gesamtlayout übernommen und dabei untereinander angeordnet.

Aufgabe 1

Ändere die Reihenfolge der Aufrufe der pack-Methode. Welche Auswirkung hat dies?

Beispiel 2: Seitenvorgaben

Beachte die Ergänzungen im Aufruf der pack-Methode.

from tkinter import *
tkFenster = Tk()

label1 = Label(master=tkFenster, text="0", bg="red", fg="white")
label1.pack(side='left')
label2 = Label(master=tkFenster, text="1", bg="green", fg="black")
label2.pack(side='left')
label3 = Label(master=tkFenster, text="2", bg="blue", fg="white")
label3.pack(side='left')
label4 = Label(master=tkFenster, text="3", bg="yellow", fg="black")
label4.pack(side='left')

tkFenster.mainloop()

Das Programm erzeugt jetzt die folgende GUI:

Anwendungsfenster

Aufgabe 2

(a) Probiere auch folgende Varianten bei der Seitenfestlegung aus: side='right', side='top', side='bottom'.

(b) Welches Layout erhält man beim folgenden Programm?

from tkinter import *
tkFenster = Tk()

label1 = Label(master=tkFenster, text="0", bg="red", fg="white")
label1.pack(side='right')
label2 = Label(master=tkFenster, text="1", bg="green", fg="black")
label2.pack(side='left')
label3 = Label(master=tkFenster, text="2", bg="blue", fg="white")
label3.pack(side='right')
label4 = Label(master=tkFenster, text="3", bg="yellow", fg="black")
label4.pack(side='left')

tkFenster.mainloop()

(c) Experimentiere selbst mit den Seitenfestlegungen.

Beispiel 3: Breite und Höhe anpassen

Mit dem fill-Attribut kann man Höhe und Breite einer GUI-Komponente an den vorgegebenen Rahmen anpassen.

from tkinter import *
tkFenster = Tk()

label1 = Label(master=tkFenster, text="0", bg="red", fg="white")
label1.pack(side='top', fill='x')
label2 = Label(master=tkFenster, text="1", bg="green", fg="black")
label2.pack(side='right', fill='y')
label3 = Label(master=tkFenster, text="2", bg="blue", fg="white")
label3.pack(side='top', fill='both')
label4 = Label(master=tkFenster, text="3", bg="yellow", fg="black")
label4.pack(side='left')

tkFenster.mainloop()

Das Programm erzeugt die folgende GUI:

Anwendungsfenster

Beachte, dass die Breite des Fensters durch einen voreingestellten Wert bestimmt wird.

Aufgabe 3

(a) Welche Auswirkungen haben die Festlegungen fill='x', fill='y', fill='both'?

(b) Variiere manuell die Fenstergröße. Welche Auswirkungen hat dies auf die GUI?

(c) Führe selbst weitere Experimente durch.

Beispiel 4: Abstände zum Rand bzw. Nachbarn festlegen

Man kann auch einen Raum um eine GUI-Komponente festlegen.

from tkinter import *
tkFenster = Tk()

label1 = Label(master=tkFenster, text="0", bg="red", fg="white")
label1.pack(side='top', fill='x', padx='5')
label2 = Label(master=tkFenster, text="1", bg="green", fg="black")
label2.pack(side='top', fill='x', pady='5')
label3 = Label(master=tkFenster, text="2", bg="blue", fg="white")
label3.pack(side='top', fill='x')
label4 = Label(master=tkFenster, text="3", bg="yellow", fg="black")
label4.pack(side='top', fill='x', padx='5', pady='10')

tkFenster.mainloop()

Das Programm erzeugt die folgende GUI:

Anwendungsfenster

Aufgabe 4

Führe selbst weitere Experimente durch.

Beispiel 5: Rahmen nutzen

Zur weiteren Strukturierung einer grafischen Benutzeroberfläche benutzt man Rahmen.

from tkinter import *
tkFenster = Tk()

rahmen1 = Frame(master=tkFenster, bg='magenta')
rahmen1.pack(side='top', padx='5', pady='5')
rahmen2 = Frame(master=rahmen1, bg='cyan')
rahmen2.pack(side='left', padx='5', pady='5')
rahmen3 = Frame(master=rahmen1, bg='cyan')
rahmen3.pack(side='left', padx='5', pady='5')
rahmen4 = Frame(master=tkFenster, bg='magenta')
rahmen4.pack(side='top', padx='5', pady='5')
label1 = Label(master=rahmen2, text="0", bg="red", fg="white")
label1.pack(side='top', padx='5', pady='5')
label2 = Label(master=rahmen2, text="1", bg="green", fg="black")
label2.pack(side='top', padx='5', pady='5')
label3 = Label(master=rahmen3, text="2", bg="blue", fg="white")
label3.pack(side='left', padx='5', pady='5')
label4 = Label(master=rahmen3, text="3", bg="yellow", fg="black")
label4.pack(side='left', padx='5', pady='5')
label5 = Label(master=rahmen4, text="4", bg="white", fg="black")
label5.pack(side='left', padx='5', pady='5')
label6 = Label(master=rahmen4, text="5", bg="black", fg="white")
label6.pack(side='left', padx='5', pady='5')

tkFenster.mainloop()

Das Programm erzeugt die folgende GUI:

Anwendungsfenster

Rahmen werden durch Objekte der Klasse Frame implementiert.

Rahmen bilden "Container" für GUI-Komponenten. Mit dem master-Attribut wird die Zugehörigkeit zu einem solchen "Container" festgelegt. Hierdurch ergibt sich eine sog. Master-Slave-Hierarchie.

Anwendungsfenster

Aufgabe 5

Führe selbst weitere Experimente durch.

Beispiel 6: Eine komplexe grafische Benutzeroberfläche

Ziel ist es, die folgende grafische Benutzeroberfläche mit dem pack-Manager zu erzeugen.

Anwendungsfenster

Der folgende (noch unvollständige) Quelltext soll als Grundlage dienen.

from tkinter import *

def buttonPlusClick():
    # Übernahme der Daten
    zahl1 = int(entryZahl1.get())
    zahl2 = int(entryZahl2.get())
    # Verarbeitung der Daten
    ergebnis = zahl1 + zahl2
    # Anzeige der Daten
    labelErgebnis.config(text=str(ergebnis))

def buttonMinusClick():
    # Übernahme der Daten
    zahl1 = int(entryZahl1.get())
    zahl2 = int(entryZahl2.get())
    # Verarbeitung der Daten
    ergebnis = zahl1 - zahl2
    # Anzeige der Daten
    labelErgebnis.config(text=str(ergebnis))

def buttonMalClick():
    # Übernahme der Daten
    zahl1 = int(entryZahl1.get())
    zahl2 = int(entryZahl2.get())
    # Verarbeitung der Daten
    ergebnis = zahl1 * zahl2
    # Anzeige der Daten
    labelErgebnis.config(text=str(ergebnis))

def buttonDurchClick():
    # Übernahme der Daten
    zahl1 = int(entryZahl1.get())
    zahl2 = int(entryZahl2.get())
    # Verarbeitung der Daten
    ergebnis = zahl1 // zahl2
    # Anzeige der Daten
    labelErgebnis.config(text=str(ergebnis))

def buttonRestClick():
    # Übernahme der Daten
    zahl1 = int(entryZahl1.get())
    zahl2 = int(entryZahl2.get())
    # Verarbeitung der Daten
    ergebnis = zahl1 % zahl2
    # Anzeige der Daten
    labelErgebnis.config(text=str(ergebnis))

# Fenster
tkFenster = Tk()
tkFenster.title('Rechner')
# Frames
frameEingaben = Frame(master=...)
frameZahl1 = Frame(master=..., bg='#FFCFC9')
frameZahl2 = Frame(master=..., bg='#FFCFC9')
frameBerechnen = Frame(master=..., bg='#FBD975')
frameAusgaben = Frame(master=...)
frameErgebnis = Frame(master=..., bg='#D5E88F')
#frameEingaben.pack(...)
#frameBerechnen.pack(...)
#frameAusgaben.pack(...)
#frameErgebnis.pack(...)
#frameZahl1.pack(...)
#frameZahl2.pack(...)
# Label mit Aufschrift Zahl 1
labelZahl1 = Label(master=..., bg='white', text='Zahl 1')
#labelZahl1.pack(...)
# Entry für Zahl 1
entryZahl1 = Entry(master=..., bg='white', width='8')
#entryZahl1.pack(...)
# Label mit Aufschrift Zahl 2
labelZahl2 = Label(master=..., bg='white', text='Zahl 2')
#labelZahl2.pack(...)
# Entry für Zahl 2
entryZahl2 = Entry(master=..., bg='white', width='8')
#entryZahl2.pack(...)
# Button zum Addieren
buttonPlus = Button(master=..., text='+', width='2', command=buttonPlusClick)
#buttonPlus.pack(...)
# Button zum Subtrahieren
buttonMinus = Button(master=..., text='-', width='2',command=buttonMinusClick)
#buttonMinus.pack(...)
# Button zum Multiplizieren
buttonMal = Button(master=..., text='*', width='2', command=buttonMalClick)
#buttonMal.pack(...)
# Button zum Dividieren ohne Rest
buttonDurch = Button(master=..., text=':', width='2', command=buttonDurchClick)
#buttonDurch.pack(...)
# Button zum Rest bei der Division
buttonRest = Button(master=..., text='%', width='2', command=buttonRestClick)
#buttonRest.pack(...)
# Label mit Aufschrift Ergebnis
labelAufschriftErgebnis = Label(master=..., bg='white', text='Ergebnis')
#labelAufschriftErgebnis.pack(...)
# Label für das Ergebnis
labelErgebnis = Label(master=..., bg='white', width='8', text='')
#labelErgebnis.pack(...)
# Aktivierung des Fensters
tkFenster.mainloop()

Aufgabe 6

(a) Entwickle zunächst die Master-Slave-Struktur zu den GUI-Komponenten. Stelle diese Struktur mit einem Baumdiagramm dar und implementiere sie im Programm.

(b) Ergänze anschließend die Attribute zu den Aufrufen der pack-Methoden.

Zur Kontrolle: Hier findest du eine Lösung.

Zusammenfassung

Die Grobstruktur des Layouts wird durch die Master-Slave-Struktur der GUI-Komponenten festgelegt.

Der Packer ordnet die Slave-Komponenten jeweils innerhalb der zugehörigen Master-Komponenten an. Folgende Parameter können dabei gesetzt werden.

Parameter Bedeutung
side Seite der Master-Komponente, an die die GUI-Komponente gesetzt wird. Mögliche Werte: 'left', 'right', 'top', 'bottom'.
padx, pady Leerer Platz rechts und links bzw. ober- und unterhalb der GUI-Komponente
fill Die GUI-Komponente wird so vergrößert, dass sie den gesamten zur Verfügung stehenden Platz ausfüllt. Mögliche Werte: 'x', 'y', 'both'.
anchor siehe Handbuch
expand siehe Handbuch
X

Fehler melden

X

Suche