Layout-Manager / Geometrie-Manager


Einführung

Packed Suitcases, from Wikipedia, Public Domain, Sherlock_Holmes_Museum In diesem Kapitel unseres online Python-Tkinter-Tutorials führen wir die Layout-Manager - auch als Geometrie-Manager bekannt - ein. Tkinter besitzt drei verschiedene Layout-Manager: Die drei Layout-Manager pack, grid und place dürfen nie im gleichen Master-Fenster gemischt werden!

Geometrie-Manager dienen verschiedenen Zwecken. Sie Die Anordnung von Widgets auf dem Bildschirm beinhaltet auch die Position und die Größe zu bestimmen. Widgets können aber auch dem Geometrie-Manager Angaben zu Größe und Position geben, aber dies sind gewissermaßen nur Wunschvorstellungen, da der Geometrie-Manager immer "das letzte Wort" hat, was die Poistionierung und die Größendarstellung betrifft.

Pack

Pack ist der am einfachsten zu benutzende der drei Geometrie-Manager von Tk und Tkinter. Statt dass man präzise erklären muss, wo ein Widget auf dem Bildschirm erscheinen soll, werden die Widgets relativ zueinander positioniert. Die Details werden von Pack automatisch bestimmt, also genaue Koordinaten, Größen und so weiter. Aber obwohl die pack-Methode einfacher zu benutzen ist, ist dieser Layout-Manager in seinen Möglichkeiten im Vergleich zu der grid- und der place-Methode eingeschränkt. Für einfache Anwendungen ist dieser Manager aber meistens die beste Wahl. Beispielsweise eine einfache Applikation, bei der man nur ein paar Widgets übereinander oder nebeneinander positioniert.

Beispiel:
from Tkinter import *

root = Tk()

Label(root, text="Red Sun", bg="red", fg="white").pack()
Label(root, text="Green Grass", bg="green", fg="black").pack()
Label(root, text="Blue Sky", bg="blue", fg="white").pack()

mainloop()

Packing some labels

fill-Option

In unserem Beispiel haben wir drei Labels in unser Hauptwidget (parent widget) "root". Wir haben die Methode pack() ohne weitere Optionen genutzt. Deshalb musste die pack-Methode alle Entscheidungen hinsichtlich dem Arrangement der Labels treffen. Wie man sieht, hat sie sich entschlossen die Label-Widgets übereinander und zentriert zu platzieren. Weiterhin sieht man, dass die Größe von den Labels durch ihren darzustellenden Text bestimmt ist. Will man die Widgets so breit wie das Elternfenster (parent window) haben, so muss man die Option fill=X setzen:

from Tkinter import *

root = Tk()

w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack(fill=X)
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(fill=X)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(fill=X)

mainloop()
Packing labels and filling horizontally

Padding

Der pack()-Manager kennt vier padding-Optionen, d.h. internes und externes Padding und Padding in x und y-Richtung:

padx Externes Padding, horizontal

Packing labels with the option padx

Der Code für das obige Fenster lautet:
from Tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack(fill=X,padx=10)
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(fill=X,padx=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(fill=X,padx=10)
mainloop()
pady Externes Padding, vertikal

Packing labels with the option padx

Der Code für das obiges Fenster sieht wie folgt aus:
from Tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack(fill=X,pady=10)
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(fill=X,pady=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(fill=X,pady=10)
mainloop()
ipadx Internal Padding, horizontal.

Im folgenden Beispiel ändern wir nur das Label mit dem Text "Green Grass", sodass das Ergebnis besser verstanden werden kann. Zur Vereinfachung haben wir auch die fill-Option aus dem Code entfernt.

Packing labels using ipadx

from Tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack()
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(ipadx=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack()
mainloop()
ipady Internes Padding, vertical

Wir ändern im letzten Label unseres vorigen Programmen dien Wert von ipady, d.h. ipady=10.

Packing labels using ipadx

from Tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack()
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(ipadx=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(ipady=10)
mainloop()
Der Default-Wert in allen Fällen ist 0.

Widgets nebeneinander platzieren

Wir wollen nun die drei Labels nebeneinander platzieren und kürzen unseren Text geringfügig:

Packing labels side by side

Der dazugehörige Code sieht wie folgt aus:

from Tkinter import *

root = Tk()

w = Label(root, text="red", bg="red", fg="white")
w.pack(padx=5, pady=10, side=LEFT)
w = Label(root, text="green", bg="green", fg="black")
w.pack(padx=5, pady=20, side=LEFT)
w = Label(root, text="blue", bg="blue", fg="white")
w.pack(padx=5, pady=20, side=LEFT)

mainloop()


Wenn wir LEFT zu RIGHT im vorigen Beispiel ändern, erhalten wir die Farben in umgekehrter Reihenfolge:

Labels nebeneinander paltzieren

Place-Geometrie-Manager

Der Place-Geometrie-Manager erlaubt das explizite Setzen der Position und der Größe eines Fenster, entweder in absoluten Werten oder relativ zu anderen Widgets. Der Place-Manager can über die place-Methode benutzt werden. Er kann auf alle Standard-Widgets angewendet werden.

Im folgenden Beispiel benutzen wir den Place-Geometrie-Manager. Wir spielen mit Farben in diesem Beispiel, d.h. wir ordnen jedem Label eine andere Farbe zu, die wir zufällig mit der randrange-Methode aus dem random-Modul erzeugen. Wir berechnen den Grauwert (die Helligkeit, brightness) von jeder Farbe. Falls die Helligkeit kleiner als 120 ist, setzen wir die Vordergrundfarbe (fg) des Labels auf weiß andernfalls auf schwarz. Dadurch lässt sich der Text leichter lesen.

import Tkinter as tk
import random
    
root = tk.Tk()
# width x height + x_offset + y_offset:
root.geometry("170x200+30+30") 
     
languages = ['Python','Perl','C++','Java','Tcl/Tk']
labels = range(5)
for i in range(5):
   ct = [random.randrange(256) for x in range(3)]
   brightness = int(round(0.299*ct[0] + 0.587*ct[1] + 0.114*ct[2]))
   ct_hex = "%02x%02x%02x" % tuple(ct)
   bg_colour = '#' + "".join(ct_hex)
   l = tk.Label(root, 
                text=languages[i], 
                fg='White' if brightness < 120 else 'Black', 
                bg=bg_colour)
   l.place(x = 20, y = 30 + i*30, width=120, height=25)
          
root.mainloop()


example place geometry manager

Grid-Manager

Der erste Geometrie-Manager von Tk war der pack-Manager gewesen. Der Algorithmus des pack-Managers ist nicht leicht zu verstehen und es kann schwierig sein ein existierendes Design zu ändern. Der Grid-Manager wurde im Jahr 1996 als Alternative zu pack eingeführt. Obwohl der grid-Manager leichter zu erlernen und anzuwenden ist und darüber hinaus auch noch meistens ein schöneres Layout liefert, benutzen viele Entwickler weiterhin den pack-Manager.

Grid ist in vielen Fällen die beste Wahl im allgemeinen Fall. Während pack einem meistens nicht genügt Freiheit gibt Details im Layout zu ändern, gibt einem place die vollständige Kontrolle über die Positionierung eines jeden Elementes, aber place ist insgesamt viel komplizierter als pack und grid.

Der Grid-Geometrie-Manager platziert die Widgets in einer 2-dimensionalen Tabelle, die in Reihen und Spalten angeordnet ist. Die Position eines Widgets wird durch einen row und einen column-Wert bestimmt. Widgets mit der selben column-Zahl und verschiedenen row-Zahlen werden übereinander angeordnet. Entsprechend werden Widgets mit der selben row-Zahl und verschiedenen column-Zahlen in der selben Zeile platziert, d.h. sie stehen nebeneinander, also recht und links voneinander.

Mit der grid-Methode übergibt man den row- und den column-Wert, wo das Widget platziert werden soll. Die Größe braucht nicht definiert zu werden, da der Grid-Manager automatisch die besten Ausdehnungen für die benutzten Widgets berechnet.

Beispiel mit grid

from Tkinter import *

colours = ['red','green','orange','white','yellow','blue']

r = 0
for c in colours:
    Label(text=c, relief=RIDGE,width=15).grid(row=r,column=0)
    Entry(bg=c, relief=SUNKEN,width=10).grid(row=r,column=1)
    r = r + 1

mainloop()
example with the grid geometry manager