Layout pack
Überblick
Der Layout-Manager „pack“ arbeitet ähnlich des GridBagLayouts. Nur werden die Elemente beim Einfügen positioniert.
Parameter der pack-Methode:
Parameter | Werte | Erläuterung |
after | Widget | Das Element wird nach dem Wigdet-Element gepackt. |
anchor | "n", "ne", "e", "se", "s", "sw", "w", "nw","center" | Anchor à la GridbagLayout. Damit können Elemente, die nicht "gezoomt" werden, zum Beispiel nach links/oben positioniert werden. |
before | Widget | Das Element wird vor dem Wigdet-Element gepackt. |
expand | True / False |
wx bzw. wy à la GridbagLayout. Dieser Wert sollte nur beim Wert fill="y" oder fill="both" gesetzt werden. Label, Entry, Checkbox, Buttons brauch kein expand. |
fill | "x", "y", "both", "none" | fill-Attribut à la GridbagLayout. Wenn man das Fenster vergrößert, wird das UI-Element mitvergrößert. |
in | Widget | Das Element wird in das Wigdet-Element gepackt. Meist ein LabelFrame. Diese Eigenschaft wird meistens über den Konstruktor gesetzt. |
ipadx | int | innerer Rand in Pixel |
ipady | int | innerer Rand in Pixel |
padx | int | äußerer Rand in Pixel |
pady | int | äußerer Rand in Pixel |
side | "left", "right", "top", "bottom" | Layout à la DockPanel von WPF. |
Erstes Tkinter-Beispiel
01:# coding=utf8 02: import tkinter 03: 04: class MyApp(tkinter.Frame): 05: 06: def __init__(self, master=None): 07: tkinter.Frame.__init__(self, master) 08: self.pack() 09: self.setGUI() 10: 11: def setGUI(self): 12: self.nameEntry = tkinter.Entry(self) 13: self.nameEntry.pack() 14: 15: self.inputui = tkinter.StringVar() 16: self.inputui.set("Ihr Name...") 17: self.nameEntry["textvariable"] = self.inputui 18: 19: self.bnOk = tkinter.Button(self) 20: self.bnOk["text"] = "Ok" 21: self.bnOk["command"] = self.quit 22: self.bnOk.pack(side="right") 23: 24: self.bnAction = tkinter.Button(self) 25: self.bnAction["text"] = "Action" 26: self.bnAction["command"] = self.onAction 27: self.bnAction.pack(side="right") 28: 29: def onAction(self): 30: s = self.inputui.get() 31: self.inputui.set( "Text: "+s ) # 1. Aufruf-Möglichkeit root = tkinter.Tk() app = MyApp(root) app.mainloop() # 2. Aufruf-Möglichkeit root = tkinter.Tk() root.title("Mein Fenster") root.geometry("250x100") app = MyApp(root) app.mainloop()
Erläuterung des Beispiels
- 01: Sinnvoll bei der Verwendung der deutschen Umlauten
- 02: Einfügen des Moduls tkinter
- 04: Die Klasse braucht die Oberklasse Frame (à la JFrame)
- 06: Konstruktur
- 07: Aufruf des Konstrukturs der Oberfläche. Damit ist das Fenster sichtbar.
- 07: Das Fenster hat aber nur die Mindestgröße (1. Aufruf)
- Samples1-a.png
- 07: Mit dem Aufruf des Fensters in der zweiten Variante hat das Fenster nun eine feste Größe.
- Samples1-b.png
- 11: Aufbau der internen Struktur
- 12: Erzeugen einer Textbox.
- 13: Einfügen in den Layout-Manager.
- 15: Um auf das Entry zugreifen zu können, benötigt man einen Mittler (StringVar)
- 16: mit "set" setzt man einen Wert. Aber noch nicht im Textfeld.
- 17: Hier wird die Verknüpfung "Variable" zum Textfeld gesetzt (Hashtable-Prinzip).
- 19: Erzeugen eines Schalters
- 20: Setzen eines Textes.
- 21: ActionListener definieren. Wenn angeklickt, wird die interne Methode "quit" aufgerufen.
- 22: Einfügen in den Layout-Manager mit der Ausrichtung "rechts".
- 24: Erzeugen eines Schalters (bnAction)
- 25: Setzen eines Textes.
- 26: ActionListener definieren. Wenn angeklickt, wird die Methode "onAction" aufgerufen.
- 27: Einfügen in den Layout-Manager mit der Ausrichtung "rechts".
- 29: onClick-Methoden des zweiten Schalters
- 30: Holen des Inhaltes des Textfeldes
- 31: Setzen des Inhaltes
- Quellcode: Sample1.py
- Samples1-c.png (1. Aufruf)
- Samples1-d.png (2. Aufruf)
Empfehlung
Im Bild Samples1-e.png sieht man, dass das Textfeld nicht komplett im Fenster positioniert ist.
Der Layout-Manager ist mit gelben Hintergrund dargestellt.
Auch eine Vergrößerung des Fensters bewirkt nichts.
Abhilfe:
Der Aufruf des pack-Layouts im Konstruktur wird erweitert.
self.pack(expand=True, fill="both", padx="5", pady="5")
Ergebnis:
Samples1-f.png
Nun müssen natürlich auch die UI-Elemente angepasst werden:
mit
self.nameEntry.pack(fill="x", padx="5", pady="5")
wird das Textfeld komplett im Fenster ausgefüllt.
Ein Vergrößern vergrößert auch das Textfeld!
Bild Samples1-g.png
Optimale Lösung
Damit man es einfacher hat sollte man UI-Elemente mit dem Frame-Element zusammenfügen.
Ein "Frame-Element" ist nichts anderes als ein "JPanel" bzw. ein DockPanel.
1) Im Konstruktur verwendet man immer
self.pack(expand=True, fill="both", padx="5", pady="5")
2) Jede "Zeile" im Fenster fügt man in einem Frane ein
inputframe = tkinter.Frame(
self
) # frame wird eingefügt in self
inputframe.background = "red" #"#FF0000"
inputframe.pack(fill="x", side="top" )
self.label1 = tkinter.Label(i
nputframe
) # label wird eingefügt in frame
self.label1["text"] = "Eingabe"
self.label1.config(foreground = "blue" )
self.label1.config(background = "#FFFF00")
self.label1.pack(side="left")
self.inputui = tkinter.Entry(
inputframe
) # Entry wird eingefügt in frame
self.inputui.pack(fill="x",padx="5",pady="5")
Ergebnis:
Bild Samples1-h.png
Bei Vergrößerung:
Bild Samples1-i.png
3) Jeder "Frame" mit fill="both" sollte erst am Schluss eingefügt werden
Der Sinn liegt im DockPanel-Prinzip von WPF.
Beispiel:
Fügt man eine Zeile mit einer Entry ein.
Fügt man eine Zeile mit einer Listbox ein (fill="both")
Fügt man einen Button ein.
Durch die Listbox hat der Schalter keinen Platz mehr.
Erst ab einer bestimmten Größe ist er wieder sichtbar.
Editor mit Frames und Scrollbars

Editor
In der oberen Abbildung sieht man die drei Frames:
- rot: Eingabezeile
- grün: Texteditor
- blau: "Schalterleiste"
Quellcode des Editors
# coding=utf8 import tkinter from tkinter import messagebox class MyApp(tkinter.Frame): def __init__(self, master=None): tkinter.Frame.__init__(self, master) self.pack(expand=True, fill="both") # dialog zoomt self.setGUI() def setGUI(self): # pack ist wie das DockPanel in WPF # erst muessen die "normalen" UI-Elemente eintgetragen werden # am Schluss werden die UI-Elemente eingetragen, die fill="both" haben inputframe = tkinter.Frame(self) # „JPanel“ fuer die Eingabe inputframe.config(background = "red") #"#FF0000" inputframe.pack(fill="x", side="top" ) # ohne expand, da fill=“x“ self.label1 = tkinter.Label(inputframe, fg="blue", bg="#FFFF00") self.label1["text"] = "Eingabe" self.label1.pack(side="left") self.inputui = tkinter.Entry(inputframe) self.inputui.pack(expand=True,fill="x",padx="5",pady="5") self.var_name = tkinter.StringVar() self.var_name.set("Ihr Name...") self.inputui["textvariable"] = self.var_name buttonframe = tkinter.Frame(self) # „JPanel“ fuer die Eingabe buttonframe.config(background = "blue") #"#FF0000" # ohne expand, da fill=“x“ buttonframe.pack(fill="x", side="bottom" ) self.bnEsc = tkinter.Button(buttonframe) self.bnEsc["text"] = "Beenden" self.bnEsc["command"] = self.quit self.bnEsc.pack(padx="5", side="right") self.bnAction = tkinter.Button(buttonframe) self.bnAction["text"] = "Action" self.bnAction["command"] = self.onAction self.bnAction.pack(side="right") # nun ein Editor mit fill=both editorframe = tkinter.Frame(self) # „JPanel“ fuer den Editor editorframe.config(background = "green") #"#FF0000" editorframe.pack(expand=True,fill="both", side="top" ) sbx = tkinter.Scrollbar(editorframe, orient="horizontal") sbx.pack(fill="x", side="bottom") sby = tkinter.Scrollbar(editorframe) sby.pack(fill="y", side="right") self.editor = tkinter.Text(editorframe) self.editor.config(wrap="none") # wrap="word" word char self.editor.pack(expand=True, fill="both", padx="5",pady="5") self.editor["xscrollcommand"] = sbx.set sbx["command"] = self.editor.xview self.editor["yscrollcommand"] = sby.set sby["command"] = self.editor.yview def onAction(self): str = self.var_name.get() messagebox.showinfo( "Hello Python", str) self.editor.insert("end",str+"\r\n") root = tkinter.Tk() root.title("Sample2.py (Editor)") root.geometry("450x400") app = MyApp(root) app.mainloop()