Logo des digitalen Schulbuchs inf-schule.de. Schriftzug in Zustandsübergangsdiagramm eines endlichen Automaten.

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.

Anwendungsfenster

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.

Anwendungsfenster

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.

Anwendungsfenster

Die Anordnung der GUI-Komponenten wird hier mit Hilfe von Rahmen festgelegt.

Test

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.

Test

Man erhält erhält hier also folgende Komponenten-Verschachtelung:

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.

Anwendungsfenster

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:

FrameLiften - Start

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.

FrameLiften - it

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.

X

Fehler melden

X

Suche