Tkinter


Rozvržení widgetů

Packed Suitcases, from Wikipedia, Public Domain, Sherlock_Holmes_Museum V této kapitole stručně popíšeme tři systémy rozvržení (layout managers) nebo správce geometrie, jak jsou rovněž někdy označováni: Správci geometrie se uplatňují prostřednictvím metod pack(), grid(), place() a plní různé funkce: Systémy pack a grid by se nikdy neměli kombinovat v jednom okně!

Umístění widgetů na obrazovce zahrnuje určení velikosti a pozice jednotlivých komponent. Byť jsou widgety nositeli prvotní informace o velikosti a přiřazení, poslední slovo o jejich umístění a velikosti mají správci geometrie.

Pack

Systém "pack" má jednoduchý, byť obtížně vysvětlitelný algoritmus. Organizuje widgety do bloků před jejich umístěním do nadřazeného okna; někdy je nutné vložit pomocný rámeček (frame). Místo přesného absolutního určení pozice widgetu lze pozici určit relativně vzhledem k jinému widgetu. O detaily se postará metoda pack().
Byť snadno použitelný, ve srovnání se správci "grid" a "place" jsou možnosti tohoto správce poněkud omezené. Pro jednoduché aplikace (umístění řady widgetů vedle sebe nebo nad sebou) je to určitě správce nejvhodnější.

Příklad:
from tkinter import *

root = Tk()

Label(root, text="Red Sun", bg="red", fg="white").pack()
Label(root, text="Green Grass", bg="green",
      fg="black").pack()
Label(root, text="Blue Sky", bg="blue", fg="white").pack()

mainloop()

Packing some labels

Parametr fill

V naší ukázce jsme "napakovali" tři widgety do rodičovského widgetu "root". Použili jsme pack() bez jakýchkoliv parametrů. Takže o uspořádání popisků musel "pack" rozhodnout sám. Jak vidno, rozhodl se umístit widgety popisků centricky jeden nad druhý. Navíc vidíme, že velikosti popiskových widgetů jsou dány délkou vložených textů. Chcete-li, aby byly widgety popisků stejně široké jako rodičovský widget, můsíte použít parametr fill=X:

from tkinter import *

root = Tk()

w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack(fill=X)
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(fill=X)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(fill=X)

mainloop()
Packing labels and filling horizontally

Výstelka

Správce pack() zná čtyři možnosti výstelky neboli odsazení: vnitřní, vnější, ve směru x a směru y:

padx - externí výstelka horizontálně
Packing labels with the option padx
from tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack(fill=X,padx=10)
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(fill=X,padx=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(fill=X,padx=10)
mainloop()

pady - externí výstelka vertikálně

Packing labels with the option padx
from tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack(fill=X,pady=10)
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(fill=X,pady=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(fill=X,pady=10)
mainloop()

ipadx - vnitřní výstelka horizontálně.

V následujícím příkladě změníme pouze popisek s textem "Green Grass" tak, aby byl lépe čitelný. Odstraníme také parametr fill.

Packing labels using ipadx
from Tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack()
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(ipadx=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack()
mainloop()


ipady - Vnitřní výstelka svisle

Poslední popisek předchozího příkladu změníme s ipady=10.

Packing labels using ipadx
from tkinter import *
root = Tk()
w = Label(root, text="Red Sun", bg="red", fg="white")
w.pack()
w = Label(root, text="Green Grass", bg="green", fg="black")
w.pack(ipadx=10)
w = Label(root, text="Blue Sky", bg="blue", fg="white")
w.pack(ipady=10)
mainloop()

Implicitní hodnota ve všech případech je 0.

Umístění widgetů vedle sebe


Chceme nyní umístit tři popisky vedle sebe a lehce zkrátit text:

Packing labels side by side

Příslušný kód vypadá takto:

from tkinter import *

root = Tk()

w = Label(root, text="red", bg="red", fg="white")
w.pack(padx=5, pady=10, side=LEFT)
w = Label(root, text="green", bg="green", fg="black")
w.pack(padx=5, pady=20, side=LEFT)
w = Label(root, text="blue", bg="blue", fg="white")
w.pack(padx=5, pady=20, side=LEFT)

mainloop()


Když v předchozím příkladě změníme LEFT na RIGHT, dostaneme barvy v obráceném pořadí:

Packing labels side by side right

Place

Systém "place" umožňuje explicitně zadat pozici a velikost okna a to buď absolutně nebo relativně k jinému oknu. Lze jej použít pro všechny standardní widgety.

Použijeme jej v následujícím příkladě, kde si hrajeme s barvami, když každému popisku přisoudíme jinou barvu, kterou určíme náhodně s použitím metody randrange() modulu random. Počítáme jas (brightness) každé barvy. Je-li jas menší než 120, nastavíme barvu popředí (fg) na White, jinak na Black a to proto aby byl text snáze čitelný.

import tkinter as tk
import random
    
root = tk.Tk()
# (width x height + x_offset + y_offset)
root.geometry("170x200+30+30") 
     
languages = ['Python','Perl','C++','Java','Tcl/Tk']
labels = range(5)
for i in range(5):
    ct = [random.randrange(256) for x in range(3)]
    brightness = int(round(0.299*ct[0] + 0.587*ct[1] +
                	   0.114*ct[2]))
    ct_hex = "%02x%02x%02x" % tuple(ct)
    bg_colour = '#' + "".join(ct_hex)
    l = tk.Label(root, 
                text=languages[i], 
                fg='White' if brightness < 120 
			   else 'Black', 
                bg=bg_colour)
   l.place(x = 20, y = 30 + i*30, width=120, height=25)
          
root.mainloop()


example place geometry manager

Grid

Správce "grid" je v mnoha případech nejlepší volbou. Je flexibilnější než "pack" a méně pracný než "place".

Systém grid umisťuje widgety do buněk dvojrozměrného rastru, který se skládá z řádků a sloupců. Pozice widgetu je daná číslem řádku a sloupce. Sousední buňky lze vhodně spojovat.

Zadání pozice widgetu je mnohdy postačující, neboť správce grid umí sám určit jeho nejvhodnější rozměr.

Přiklad s grid

from tkinter import *

colours = ['red','green','orange','white','yellow','blue']

r = 0
for c in colours:
    Label(text=c, relief=RIDGE, width=15)
	  .grid(row=r,column=0)
    Entry(bg=c, relief=SUNKEN,width=10).grid(row=r,column=1)
    r = r + 1

mainloop()
example with the grid geometry manager