Zu Tkinter habe ich bereits einige Artikel veröffentlicht. Bei einem dieser Beiträge ging es um die Verwendung des Grid-Layout-Managers. Der Code zu jenem Projekt sah folgendermaßen aus:
#!/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()
Sobald dieses Skript ausgeführt wird, erscheint folgendes Fenster:
Es sind vier Widgets zu sehen: Zwei Eingabefelder, ein Button und ein Label. Erstellt werden sie in der Klasse MainWindow
über diesen Code:
# 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"
)
Da dieses Programm nur vier Widgets hat, ist der Code noch relativ übersichtlich. Das mag sich aber schnell ändern, wenn noch mehr Widgets hinzukommen. Dann bietet es sich an, die Widgets in eine separate Datei bzw. Klasse auszulagern. Und genau darum geht es in diesem Blogbeitrag. Nachfolgend möchte ich den Code dieses kleinen Programms dementsprechend ändern.
Dazu erstelle ich eine neue Datei, die die Bezeichnung app_widgets.py
erhält. Diese Datei hat die Klasse class CustomWidgets
zum Inhalt, die den Code für das Erstellen der Widgets (Entry, Button, Label) erhalten soll.
from tkinter import ttk
class CustomWidgets:
def __init__(self, parent, calculate_callback):
# Entry fields
self.first_input_field = ttk.Entry(parent)
self.second_input_field = ttk.Entry(parent)
# Button
self.calculate_button = ttk.Button(
parent, text="Calculate", command=calculate_callback
)
# Label
self.result_label = ttk.Label(parent, text="Result label")
def place_widgets(self):
self.first_input_field.grid(column=0, row=0)
self.second_input_field.grid(column=1, row=0)
self.calculate_button.grid(column=0, row=1, sticky="nsew")
self.result_label.grid(column=0, row=2, sticky="nsew")
Der Code, mit dem die Widgets erstellt werden, ist im Wesentlichen identisch mit dem ursprünglichen Code. Es ist wichtig zu beachten, dass die Widgets Bestandteil eines Frame-Widgets sind:
# All widgets will be part of this frame.
self.content = ttk.Frame(self.window, padding=(10, 10, 10, 10))
Daher enthält die Init-Funktion den entsprechenden Parameter parent
:
class CustomWidgets:
def __init__(self, parent, calculate_callback):
Und damit nach einem Klick auf den Button auch der dafür hinterlegte Code ausgeführt werden kann, ist außerdem der Parameter calculate_callback
vorhanden.
Zur Datei, die die Klasse MainWindow
enthält, muss noch eine Import-Anweisung hinzugefügt werden:
from app_widgets import CustomWidgets
Dadurch ist es nun möglich, die Widget-Klasse zu initialisieren:
self.widgets = CustomWidgets(self.content, self.calculate)
self.widgets.place_widgets()
Der komplette Code dieser Datei sieht nun wie folgt aus:
import tkinter as tk
from tkinter import ttk
from app_widgets import CustomWidgets
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))
self.content.grid(column=0, row=0, sticky="nsew")
# Initialize custom widgets
self.widgets = CustomWidgets(self.content, self.calculate)
self.widgets.place_widgets()
def calculate(self):
pass
def mainloop(self):
self.window.mainloop()
if __name__ == "__main__":
app_instance = MainWindow()
app_instance.mainloop()