|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Der Layout-Manager „pack“ arbeitet ähnlich des GridBagLayouts. Nur werden die Elemente beim Einfügen positioniert.
|
|
|
|
|
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
|
|
|
|
|
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()
|
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
In der oberen Abbildung sieht man die drei Frames: - rot: Eingabezeile - grün: Texteditor - blau: "Schalterleiste"
|
|
|
|
|
|
# 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()
|
|
|
tkinter
Layout grid
|
|
|
|
|