Im vorherigen Blogbeitrag zum Thema Tkinter ging es um die Verwendung einer Klasse. Hier nochmal der Code zum dort gezeigten Beispiel:
#!/usr/bin/env python3
import tkinter as tk
class MainWindow():
def __init__(self):
self.window = tk.Tk()
self.window.title("Main Window")
# Set width and height of the window
window_width = 500
window_height = 300
# Get the screen dimension
screen_width = self.window.winfo_screenwidth()
screen_height = self.window.winfo_screenheight()
# Find the center point
center_x = int(screen_width / 2 - window_width / 2)
center_y = int(screen_height / 2 - window_height / 2)
# Set the position of the window to the center of the screen
self.window.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
# Window is not resizable
self.window.resizable(False, False)
def mainloop(self):
self.window.mainloop()
if __name__ == "__main__":
app_instance = MainWindow()
app_instance.mainloop()
Widgets hinzufügen
Dieses Beispiel wird nunmehr um Widgets erweitert. Anstatt die Widgets direkt zum Programmfensters hinzuzufügen, soll hier aber ein Frame-Widget verwendet werden. Alle übrigen Widgets sollen dann Bestandteil dieses Frames sein:
self.content = ttk.Frame(self.window, padding=(10, 10, 10, 10))
Dabei wird mit padding
für ausreichend Abstand zu den Kanten des Programmfensters gesorgt.
Nacheinander folgen jetzt zwei Entry-, ein Button- und ein Label-Widget:
# Entry
self.first_input_field = ttk.Entry(self.content)
self.second_input_field = ttk.Entry(self.content)
# Button
self.calculate_button = ttk.Button(self.content, text="Calculate", command=self.calculate)
# Label
self.result_label = ttk.Label(self.content)
Mit
command=self.calculate
wird definiert, welche Funktion nach einem Klick auf den Button ausgeführt werden soll. Damit der bisherige Code ausgeführt werden kann, ohne dass eine Fehlermeldung erscheint, wird jetzt noch zusätzlich diese Funktion hinzugefügt. Hinsichtlich des Funktionskörpers belassen wir es aber bei einem pass
.
def calculate():
pass
Grid Layout verwenden
Wird dieses einfache Programm ausgeführt, erscheint (weiterhin) ein leeres Fenster ohne Widgets. Das hängt damit zusammen, dass in einem zweiten Schritt mithilfe eines Layout-Managers (auch als Geometrie-Manager bezeichnet) die Widgets zum Fenster (bzw. zum Frame) hinzugefügt bzw. angeordnet werden müssen. In den bisherigen in diesem Blog vorgestellten Tkinter-Tutorials wurde hierfür pack verwendet. Dieser ist so populär, dass er bis heute in zahlreichen Tutorials zu finden ist, obwohl es einen neueren Layout-Manager gibt. Denn im Jahre 1996 wurde Grid eingeführt, den ich in diesem Beispiel verwenden möchte.
Grid funktioniert dergestalt, dass den Widgets Spalten und Zeilen zugeordnet werden. Widgets, die derselben Spalte zugeordnet werden, sind vertikal angeordnet. Widgets, die derselben Zeile zugeordnet werden, sind horizontal angeordnet.
In diesem Programm sollen an oberster Stelle, also in der ersten Zeile, die beiden Eingabefelder (Entry Widgets) stehen. In der Zeile darunter soll sich der Button befinden und in einer Zeile darunter wiederum das Label-Widget. Das mag zwar nicht sonderlich schön aussehen, sollte aber das Prinzip verdeutlichen.
In Code gegossen sieht dies wie folgt aus:
# Grid Layout manager
# Frame and entries
self.content.grid(column=0, row=0, sticky="nsew")
self.first_input_field.grid(column=0, row=0, sticky="nsew")
self.second_input_field.grid(column=1, row=0, sticky="nsew")
# Button
self.calculate_button.grid(column=0, row=1, sticky="nsew")
# Label
self.result_label.grid(column=0, row=2, sticky="nsew")
Über column
und row
wird festgelegt, in welcher Spalte und in welcher Zeile ein Widget platziert werden soll. Darüber hinaus lässt sich auch festlegen, dass sich ein Widget über mehrere Spalten und Zeilen erstrecken soll. Dies wird mit columnspan=
und rowspan=
erreicht.
Des Weiteren kann ein Widget mit sticky
innerhalb einer Zelle ausgerichtet werden. Dabei steht „nsew“ für die vier Himmelsrichtungen. Würde man nur „w“ (= west) angeben, dann würde das Widget auf der linken Seite angeheftet werden (und Freiraum auf der echten Seite lassen). Die Angabe von „nsew“ führt also zu einer gleichmäßigen Anordnung, denn das Widget wird in alle Himmelsrichtungen gestreckt und füllt so den gesamten zur Verfügung stehenden Platz aus.
Damit steht nun das Layout für dieses einfache Programm. Zugegeben, es sieht nicht besonders schön aus, aber das Prinzip sollte deutlich geworden sein. Am besten ist es, wenn man etwas experimentiert, um sich mit dem Grid-Layout-Manger vertraut zumachen. Zum Abschluss nochmal der komplette Code zu diesem Beispiel:
#!/usr/bin/env python3
import tkinter as tk
from tkinter import ttk
class MainWindow:
def __init__(self):
self.window = tk.Tk()
self.window.title("Main Window")
# Set width and height of the window
window_width = 400
window_height = 100
# Get the screen dimension
screen_width = self.window.winfo_screenwidth()
screen_height = self.window.winfo_screenheight()
# Find the center point
center_x = int(screen_width / 2 - window_width / 2)
center_y = int(screen_height / 2 - window_height / 2)
# Set the position of the window to the center of the screen
self.window.geometry(f"{window_width}x{window_height}+{center_x}+{center_y}")
# Window is not resizable
self.window.resizable(False, False)
# All widgets will be part of this frame.
self.content = ttk.Frame(self.window, padding=(10, 10, 10, 10))
# Entry
self.first_input_field = ttk.Entry(self.content)
self.second_input_field = ttk.Entry(self.content)
# Button
self.calculate_button = ttk.Button(
self.content,
text="Calculate",
command=self.calculate
)
# Label
self.result_label = ttk.Label(
self.content,
text="Result label"
)
# Layout manager
# Add frame and entries
self.content.grid(column=0, row=0, sticky="nsew")
self.first_input_field.grid(column=0, row=0)
self.second_input_field.grid(column=1, row=0)
# Add button
self.calculate_button.grid(column=0, row=1, sticky="nsew")
# Add label
self.result_label.grid(column=0, row=2, sticky="nsew")
def calculate():
pass
def mainloop(self):
self.window.mainloop()
if __name__ == "__main__":
app_instance = MainWindow()
app_instance.mainloop()