Rozdział 16 · Tworzenie fajnych aplikacji z Tkinter
tk i ttk: klasyczne i tematyczne widżety
Zaczynając od tej sekcji, w nowych przykładach wolimy ttk, gdzie istnieje tematyczny odpowiednik — ale najpierw przyjrzyjmy się, jak widżety wyglądają razem.
Tkinter Prezentacja Widgetów
Zanim rozłożymy szczegóły każdego widżetu osobno (sekcje 16.13–16.22), oto jak wyglądają Spójrzcie razem, w jednym prawdziwym oknie:
Później w tym rozdziale każdy z tych widżetów otrzyma osobną sekcję z własną stany i przykłady kodeksów.
tk i ttk to dwa zestawy widgetów
| tk | ttk | |
|---|---|---|
| Co to jest | klasyczne widgety Tkinter | tematycznie (themed) osadzone na Tk |
| Import | import tkinter as tk | from tkinter import ttk |
| Wygląd | Stały styl klasyczny | może dostosować się do tematu/platformy |
| Stylizacja | fg=/bg= | przez ttk.Style() |
tk_vs_ttk.py
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
ttk.Label(root, text=„Nowoczesna ttk.Label”).pack()
ttk.Button(root, text="ttk.Button").pack()
ttk.Entry(root).pack()
W przypadku nowego kodu istnieje ttk, gdzie jest analogia
Od tej sekcji, w nowych przykładach, preferujemy
ttk.Label, ttk.Button, ttk.Entry inne tematyczne widgety, gdzie istnieje tematyczny odpowiednik. Ale ttk nie zastępuje cały Tk w całości — widżety takie jak tk.Text, tk.Canvas oraz tk.Menu pozostają klasyczne, bo nie mają tematycznego odpowiednika.ttk nie gwarantuje „bardziej nowoczesnego”
Motyw ttk zależy od systemu operacyjnego i zainstalowanych motywów Tk. Na niektórych platformach/motywach różnica między tk a ttk jest niemal niewidoczna wizualnie (jak na powyższym zrzucie ekranu) – powiedz "tematyczny" zamiast "nowoczesny" czy "ładniejszy".
Nie używaj fg/bg na widżetach ttk jak na klasycznych
Classic
tkwidżety rozumieją fg=/bg= bezpośrednio. Widgety ttk są stylizowane inaczej — poprzez obiekt ttk.Style() (następna sekcja). Nie przenosz dosłownie nawyków klasycznych Tk na ttk.from tkinter import * — nie w stylu produkcyjnym
Import: gwiazdka → jawne nazwy
Nie polecam
from tkinter import *
root = Tk()
Button(root, text=„Guzik”) # skąd Button pochodzi, nie jest oczywiste
Polecam
import tkinter as tk
from tkinter import ttk
root = tk.Tk()
ttk.Button(root, text=„Guzik”) # źródło nazwy jest od razu widoczne
Co używać dzisiaj:
from tkinter import * działa, ale utrudnia czytanie kodu: nie jest jasne, do którego modułu należy każda nazwa, a łatwo przypadkowo nakładać się na wbudowane nazwy Python. W przykładach kursów, począwszy od tego rozdziału, pojawiają się tylko jawne importy.ttk.Style() — stylizacja widgetów tematycznych
ttk_style.py
style = ttk.Style()
print(style.theme_use()) #active temat, np. "clam" lub "default"
style.configure(
"Accent.TButton",
font=("TkDefaultFont", 11, "bold"),
padding=8,
)
button = ttk.Button(
root,
text=„Ratuj”,
style="Accent.TButton",
)
ttk.Style() nie jest CSS
style.configure(...) akceptuje tylko opcje, które dany widżet i aktywny motyw Tk obsługują, nie jest uniwersalnym językiem stylów CSS-, gdzie można zmienić dowolną właściwość dowolnego elementu. Styl nazwany ("Accent.TButton") jest stosowane przez style= przy samym widżecie.Cartesian Purple
#5B24F9
#5B24F9
Cartesian Pink
#DB2777
#DB2777
Success Green
#059669
#059669
Warning Amber
#B45309
#B45309
Kolor – najpierw widziany, potem numeryczny
Zanim napiszesz
#5B24F9 w kodzie, spójrz na rzeczywisty wzór kolorystyczny powyżej — łatwiej jest zapamiętać i odróżniać podobne odcienie niż na podstawie samych kodów szesnastkowych.Canvas — rysowanie dowolnych kształtów
canvas_basics.py
canvas = tk.Canvas(root, width=260, height=170, background="white")
canvas.pack(padx=10, pady=10)
canvas.create_line(10, 10, 240, 10, fill="#5B24F9", width=2)
rect_id = canvas.create_rectangle(10, 30, 90, 90, outline="#DB2777", width=2)
canvas.create_oval(130, 30, 210, 90, outline="#059669", width=2)
canvas.create_text(130, 130, text=„(0,0) - Lewy górny róg”)
Oś Y rośnie w dół, a nie w górę
Pochodzenie
(0, 0) jest w lewym górnym rogu Canvas. x rozrasta się w prawo, oraz y rośnie na ziemię — jest to przeciwieństwem zwykłego systemu współrzędnych matematycznych, w którym y rośnie w górę. Tak działa ekranowy system współrzędnych w większości bibliotek graficznych, nie tylko Tkinter.create_* zwraca identyfikator elementu
rect_id = canvas.create_rectangle(...) — Canvas przechowuje wyrysowane elementy i zwraca identyfikator, dzięki któremu możesz później zmienić lub usunąć ten konkretny element (canvas.itemconfig(rect_id, ...), canvas.delete(rect_id)) — przydatne w przyszłych interfejsach gier.Canvas nie jest drugim Turtle
Canvas jest zwykłym Tkinter widżetem do rysowania dowolnych kształtów w oknie aplikacji, a nie osobnego modułu z własnym światem współrzędnych, takiego jak turtle (rozdziały 6-7). To krótkie wprowadzenie, a nie pełny kurs Canvas.PhotoImage — obrazy w widżetach
photoimage.py
image = tk.PhotoImage(file="icon.png")
label = ttk.Label(root, image=image)
label.pack()
Debug Lab 2: Obraz znika, mimo że kod jest „poprawny”
photoimage_propadaet.py
def build_ui():
image = tk.PhotoImage(file="icon.png") # funkcje zmienna lokalne
label = ttk.Label(root, image=image)
label.pack()
build_ui()
# Окно открывается, но картинка не отображается —
# на месте изображения пусто.
Po ukończeniu build_ui() lokalna nazwa image znika. Jeśli na obiekcie PhotoImage nie pozostaje już żadnych odwołań Pythona, obiekt może zostać zwolniony — widżet przechowuje odniesienie do niego tylko w Tcl, a nie w samym Pythonie. Dlatego aplikacja powinna przechowywać odniesienie do PhotoImage tyle czasu, ile obraz powinien być wyświetlany.
Poprawiony kod
photoimage_fixed.py
class App:
def __init__(self, root):
self.logo_image = tk.PhotoImage(file="icon.png") # przechowywane w self —
self.logo_label = ttk.Label(root, image=self.logo_image) # żyje tak długo, jak self
self.logo_label.pack()
Praktyka: zbieramy formularz z tk i ttk
Moduł tkinter otwiera natywne okno Python — wykonaj lokalnie w VS Code, PyCharm lub Jupyter
Praktyka kursuje lokalnie