Der place-Manager
GUI-Komponenten platzieren
GUI-Komponenten lassen sich mit dem place-Manager pixelgenau im Anwendungsfenster platzieren. Betrachte hierzu die folgende grafische Benutzeroberfläche für einen einfachen Rechner.
Der Quelltext zur abgebildeten GUI ist hier aufgelistet.
Beachte, dass bei der Ereignisbehandlung derselbe Quellcode in ähnlicher Form mehrfach vorkommt. Solche Codeduplizierungen versucht man in der Regel zu vermeiden. Wir werden uns in Abschnitt Verarbeitung von Ereignissen mit diesem Problem auseinander setzen. Vorerst soll es nur um die Anordnung der GUI-Komponenten gehen.
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')
tkFenster.geometry('200x180')
# Label mit Aufschrift Zahl 1
labelZahl1 = Label(master=tkFenster, bg='#FFCFC9', text='Zahl 1')
labelZahl1.place(x=10, y=10, width=70, height=20)
# Entry für Zahl 1
entryZahl1 = Entry(master=tkFenster, bg='white')
entryZahl1.place(x=10, y=40, width=70, height=20)
# Label mit Aufschrift Zahl 2
labelZahl2 = Label(master=tkFenster, bg='#FFCFC9', text='Zahl 2')
labelZahl2.place(x=120, y=10, width=70, height=20)
# Entry für Zahl 2
entryZahl2 = Entry(master=tkFenster, bg='white', width='8')
entryZahl2.place(x=120, y=40, width=70, height=20)
# Button zum Addieren
buttonPlus = Button(master=tkFenster, text='+', width='2', command=buttonPlusClick)
buttonPlus.place(x=5, y=75, width=30, height=30)
# Button zum Subtrahieren
buttonMinus = Button(master=tkFenster, text='-', width='2', command=buttonMinusClick)
buttonMinus.place(x=45, y=75, width=30, height=30)
# Button zum Multiplizieren
buttonMal = Button(master=tkFenster, text='*', width='2', command=buttonMalClick)
buttonMal.place(x=85, y=75, width=30, height=30)
# Button zum Dividieren ohne Rest
buttonDurch = Button(master=tkFenster, text=':', width='2', command=buttonDurchClick)
buttonDurch.place(x=125, y=75, width=30, height=30)
# Button zum Rest bei der Division
buttonRest = Button(master=tkFenster, text='%', width='2', command=buttonRestClick)
buttonRest.place(x=165, y=75, width=30, height=30)
# Label mit Aufschrift Ergebnis
labelAufschriftErgebnis = Label(master=tkFenster, bg='#D5E88F', text='Ergebnis')
labelAufschriftErgebnis.place(x=65, y=120, width=70, height=20)
# Label für das Ergebnis
labelErgebnis = Label(master=tkFenster, bg='white', width='8', text='')
labelErgebnis.place(x=65, y=150, width=70, height=20)
# Aktivierung des Fensters
tkFenster.mainloop()
Im Quelltext sieht man, wie die einzelnen GUI-Komponenten hier platziert werden.
Mit Hilfe der place
-Methode werden jeder GUI-Komponente Platz und Ausmaße
zugeordnet. So legt z.B. die Anweisung
labelAufschriftErgebnis.place(x=65, y=120, width=70, height=20)
fest, dass die GUI-Komponente zum GUI-Objekt labelAufschriftErgebnis
mit der linken oberen Ecke an die Position x=65, y=120
in einem zum Fenster
gehörenden Koordinatensystem gesetzt wird. Zusätzlich wird die Breite und Höhe der
GUI-Komponente festgelegt.
Folgende Parameter können beim Platzieren der GUI-Komponenten benutzt werden.
Parameter | Bedeutung |
---|---|
x, y | Position der GUI-Komponente im zugehörigen Koordinatensystem. |
width, height | Breite und Höhe der GUI-Komponente. |
Beachte, dass es bei komplexeren Benutzeroberflächen recht mühsam ist, alle Koordinaten und Ausmaße der GUI-Komponenten zu bestimmen.
Rahmen benutzen
Zusätzlich eingeführte Rahmen helfen oft bei der Strukturierung einer grafischen Benutzeroberfläche. Wir verdeutlichen dies anhand der etwas veränderten GUI für den einfachen Rechner.
Die Anordnung der GUI-Komponenten wird hier mit Hilfe von Rahmen festgelegt.
Implementiert werden solche Rahmen durch Objekte der Klasse Frame
dargestellt.
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')
tkFenster.geometry('200x180')
# Rahmen
frameZahl1 = Frame(master=tkFenster, bg='#FFCFC9')
frameZahl1.place(x=5, y=5, width=80, height=60)
frameZahl2 = Frame(master=tkFenster, bg='#FFCFC9')
frameZahl2.place(x=115, y=5, width=80, height=60)
frameBerechnen = Frame(master=tkFenster, bg='#FBD975')
frameBerechnen.place(x=0, y=70, width=200, height=40)
frameErgebnis = Frame(master=tkFenster, bg='#D5E88F')
frameErgebnis.place(x=60, y=115, width=80, height=60)
# Label mit Aufschrift Zahl 1
labelZahl1 = Label(master=frameZahl1, bg='white', text='Zahl 1')
labelZahl1.place(x=5, y=5, width=70, height=20)
# Entry für Zahl 1
entryZahl1 = Entry(master=frameZahl1, bg='white')
entryZahl1.place(x=5, y=35, width=70, height=20)
# Label mit Aufschrift Zahl 2
labelZahl2 = Label(master=frameZahl2, bg='white', text='Zahl 2')
labelZahl2.place(x=5, y=5, width=70, height=20)
# Entry für Zahl 2
entryZahl2 = Entry(master=frameZahl2, bg='white', width='8')
entryZahl2.place(x=5, y=35, width=70, height=20)
# Button zum Addieren
buttonPlus = Button(master=frameBerechnen, text='+', width='2', command=buttonPlusClick)
buttonPlus.place(x=5, y=5, width=30, height=30)
# Button zum Subtrahieren
buttonMinus = Button(master=frameBerechnen, text='-', width='2', command=buttonMinusClick)
buttonMinus.place(x=45, y=5, width=30, height=30)
# Button zum Multiplizieren
buttonMal = Button(master=frameBerechnen, text='*', width='2', command=buttonMalClick)
buttonMal.place(x=85, y=5, width=30, height=30)
# Button zum Dividieren ohne Rest
buttonDurch = Button(master=frameBerechnen, text=':', width='2', command=buttonDurchClick)
buttonDurch.place(x=125, y=5, width=30, height=30)
# Button zum Rest bei der Division
buttonRest = Button(master=frameBerechnen, text='%', width='2', command=buttonRestClick)
buttonRest.place(x=165, y=5, width=30, height=30)
# Label mit Aufschrift Ergebnis
labelAufschriftErgebnis = Label(master=frameErgebnis, bg='white', text='Ergebnis')
labelAufschriftErgebnis.place(x=5, y=5, width=70, height=20)
# Label für das Ergebnis
labelErgebnis = Label(master=frameErgebnis, bg='white', width='8', text='')
labelErgebnis.place(x=5, y=35, width=70, height=20)
# Aktivierung des Fensters
tkFenster.mainloop()
Die Rahmen bilden eine Art "Container" für GUI-Komponenten. Mit dem master
-Attribut
wird die Zugehörigkeit zu einem solchen "Container" festgelegt.
Es ergibt sich eine Master-Slave-Hierarchie, die in der folgenden Abbildung exemplarisch
für einige GUI-Komponenten dargestellt ist.
Man erhält erhält hier also folgende Komponenten-Verschachtelung:
-
tkFenster
istmaster
vonframeErgebnis
. -
frameErgebnis
istmaster
vonlabelAufschriftErgebnis
.
Die Container-Objekte der Klassen Frame
legen genau wie Fenster-Objekte der Klasse Tk
Pixelkoordinatensysteme fest, mit deren Hilfe die umfassten Objekte genau platziert werden.
Die folgende Abbildung verdeutlicht exemplarisch diese Koordinatensysteme.
Aufgabe 1
Experimentiere mit den Rahmen. Verschiebe hierzu im Programm die Rahmen an eine andere Stelle auf dem Bildschirm. Verschiebe auch die Komponenten innerhalb eines Rahmens.
Rahmen übereinander legen
Platziert man in Python mehrere Rahmen an genau der gleichen Stelle, so liegen diese Rahmen übereinander
und nur der zuletzt erzeugte Rahmen ist tatsächlich zu sehen. Mit der lift
-Methode können Rahmen
in den Vordergrund gehoben werden. Das folgende Beispiel soll demonstrieren, wie diese lift
-Methode funktioniert.
from tkinter import *
# -----------------------------------
# Ereignisverarbeitung
# -----------------------------------
def Button_Click_Deutsch():
frameDeutsch.lift()
def Button_Click_Englisch():
frameEnglisch.lift()
def Button_Click_Italienisch():
frameItalienisch.lift()
def Button_Click_Spanisch():
frameSpanisch.lift()
def Button_Click_Reset():
frameStart.lift()
# -----------------------------------
# Erzeugen des Fensters
# -----------------------------------
tkFenster = Tk()
tkFenster.title('Frames liften')
tkFenster.geometry('400x225')
# -----------------------------------
# Erzeugen der Rahmen/Frames
# -----------------------------------
frameStart = Frame(master=tkFenster)
frameStart.place(x=0, y=20, width=400, height=180)
frameDeutsch = Frame(master=tkFenster, bg='red')
frameDeutsch.place(x=5, y=25, width=375, height=155)
frameEnglisch = Frame(master=tkFenster, bg='blue')
frameEnglisch.place(x=10, y=30, width=375, height=155)
frameItalienisch = Frame(master=tkFenster, bg='green')
frameItalienisch.place(x=15, y=35, width=375, height=155)
frameSpanisch = Frame(master=tkFenster, bg='orange')
frameSpanisch.place(x=20, y=40, width=375, height=155)
# -----------------------------------
# Frame - Start
# -----------------------------------
labelStart = Label(master = frameStart, text = 'Wähle eine Sprache!', font = ("Arial", 18))
labelStart.place(x=80, y=80)
frameStart.lift()
# -----------------------------------
# Frame - Deutsch
# -----------------------------------
labelDeutsch = Label(master = frameDeutsch, text = 'Informatik', font = ("Arial", 18))
labelDeutsch.place(x=120, y=60)
# -----------------------------------
# Frame - Englisch
# -----------------------------------
labelEnglisch = Label(master = frameEnglisch, text = 'Informatics', font = ("Arial", 18))
labelEnglisch.place(x=120, y=60)
# -----------------------------------
# Frame - Italienisch
# -----------------------------------
labelItalienisch = Label(master = frameItalienisch, text = 'Informatica', font = ("Arial", 18))
labelItalienisch.place(x=120, y=60)
# -----------------------------------
# Frame - Spanisch
# -----------------------------------
labelSpanisch = Label(master = frameSpanisch, text = 'Informática', font = ("Arial", 18))
labelSpanisch.place(x=120, y=60)
# -----------------------------------
# Erzeugen der Buttons
# -----------------------------------
buttonDeutsch = Button(master = tkFenster, text = 'Deutsch', fg = 'red', command = Button_Click_Deutsch)
buttonDeutsch.place(x=0, y=0, width=100, height=20)
buttonEnglisch = Button(master = tkFenster, text = 'Englisch', fg = 'blue', command = Button_Click_Englisch)
buttonEnglisch.place(x=100, y=0, width=100, height=20)
buttonItalienisch = Button(master = tkFenster, text = 'Italienisch', fg = 'green', command = Button_Click_Italienisch)
buttonItalienisch.place(x=200, y=0, width=100, height=20)
buttonSpanisch = Button(master = tkFenster, text = 'Spanisch', fg = 'orange', command = Button_Click_Spanisch)
buttonSpanisch.place(x=300, y=0, width=100, height=20)
buttonReset = Button(master = tkFenster, text = 'Zurücksetzen', command = Button_Click_Reset)
buttonReset.place(x=150 , y=200 , width=100, height=20)
# -----------------------------------
# Aktivierung des Fensters
# -----------------------------------
tkFenster.mainloop()
Dieses Programm erzeugt zunächst die folgende GUI:
Klick man auf einen der Buttons, wird die lift
-Methode für den entsprechenden
Rahmen ausgeführt und der Rahmen wird in den Vordergrund gehoben.
Aufgabe 2
Ändere das Programm aus dem Beispiel so ab, dass es nur noch einen Button gibt. Klickt man immer wieder auf den Button, so sollen die Rahmen in einer festgelegten Reihenfolge in den Vordergrund gelegt werden.