Tlačítko vedle tlačítka. Navazuji na přerušený seriál o programování oken v Tkinter, které bylo v lekcích 11 a 12. V těchto dvou lekcích jsme se seznámili se základy okenního programování. Vysvětlili jsme si, že, narozdíl od Delphi či Visual Basicu, má Python několik modulů, jak tvořit okna. Tkinter je jedním z nich.
Tlačítko vedle tlačítka
Úvod
Tkinter se vyznačuje tím, že je přímočarý, víceméně jednoduchý jak na naučení, tak na možnosti. Tím, že všechny udělátka, widgety, jsou generovány dynamicky, se může zdát složitějším. Na jednu stranu to je nevýhoda - tam, kde se v Delphi začíná s programováním, tam jsme v Tkinter uprostřed, protože se musí naprogramovat i vlastní rozmístnění udělátek. Na druhou stranu je to výhoda - naučíte se lépe programovat, získáte více programátorských technik, které v budoucnu pomohou. Nevýhoda může být také v tom, že je vývoj aplikace je pomalejší (více programování, méně klikání). Ale je to zase zábavnější, alespoň z mého hlediska.
Rozmýšlení především
To, že program funguje, je polovinou úspěchu. Druhou polovinou je, aby mu rozuměli i ostatní, aby byl srozumitelný a přehledný. Aby ho ostatní mohli nejen použít, ale i zdokonalit nebo případně využít ve svých programech. Stejně, jako to děláte vy s programy a moduly ostatních. Těmi ostatními budete vy sami - tak za jeden rok se na své výtvory podívejte a pochopíte o čem teď mluvím. Je to hezké, když je kód přehledně napsaný a vy se tak můžete něčemu přiučit, že jo? Skutečně - polovina času programátora spočívá v programování a druhá polovina ve zkrášlování a ve vylepšování. Pro druhé jako pro sebe.
- Uděláme takovou mřížku čtverečků, takové pole, takovou základnu pro mnoho tzv. plošinových her - piškvorky, puzzle, sudoku, had a co já vím, co ještě. Prostě vše, co se hraje na ploše a má základ v nějakém chození po políčkách nebo v pevném umístnění políček vůbec. Abych nezapomněl - taky dáma nebo snad i šachy?
- Nebudeme používat příliš mnoho if - Příliš mnoho if bývá zdrojem mnoha problému a mnoho lidí odrazuje. Svědčí to o neznalosti lepších technik, lepších datových struktur. Budeme používat hodně seznamy a slovníky.
- Příliš mnoho podmínek v if - Vždy se děsím, když vidím if s==2 and b==3 and c <10 and… Pro to platí vše, co bylo řečeno v předchozím bodu.
- Názvy proměnných - Často chceme ušetřit čas a používáme jména jako x, a, s, l, a2… Co ušetříme na psaní, ztratíme při hledání chyb. Nesmí se tento požadavek brát dogmaticky - např. x, y jsou vhodná jména pro souřadnice, ale to bývá většinou výjimka. Používejme příhodná a příznačná jména. Používejme editory, které zamezují překlepům (PSPad - Ctrl + J, IDLE - Shift + Alt + /).
- Dokumentační řetězce - Na konci práce si dejme práci s vložením dokumentačního řetězce na začátek programu a na začátek každé funkce.
- Komentáře - K ožehavým místům našeho programu připojíme malý komentář.
- Funkce - Funkce jsou prostě skvělé. Zpřehlední váš kód výrazným způsobem a usnadní pozdější život (pokud tedy s nimi umíte pracovat). Teprve s funkcemi se z malého bezvýznamného skriptu může stát program s velkým P. ;-)
- 2× měř, jednou řež - Přemýšlejte. Pokud již máte rozhled, rozmýšlejte, kterou strategii zvolit na vyřešení problému. Jsou lepší a horší způsoby (algoritmy), nejlepší i nejhorší. Sem spadá i to, že se budu učit i to, co na první pohled nesouvisí s mým konkrétním problémem, že si projdu některé tutoriály od začátku do konce, že se budu snažit vše pochopit a nebudu to považovat za ztrátu času. Získám tak lepší přehled a základnu pro řešení mých pozdějších problémů.
První tlačítko
Rozhodli jsme se tedy pro Tkinter. Mohli jsme i něco jiného, ale to je naše (moje) rozhodnutí. Dále jsem se rozhodl, že jednotlivá políčka budou Tlačítka (Buttony). Klidně to mohou být Štítky (Label) - komu by nevyhovovalo promačkávání tlačítka. Myslím, že bude stačit přepsat slovo Button na Label. V tom je jedna z předností programového generování rozmístnění plochy. :-)
Uděláme si třeba pole 9×9, ale budeme myslet na to, aby jednoduchým trikem si to kdokoliv mohl změnit na 3×3 nebo 100×100. Snad i 30×10, ale to si nejsem zatím jistý. Začneme od jednoduchého po složitější, přesně tak, jak to říkal J. A. Komenský. Vytvoříme si jedno tlačítko, pak 4, pak 9 × 9 =81.
from Tkinter import *
hlavni = Tk()
tlacitko = Button(text="1")
tlacitko.pack()
hlavni.mainloop()
Všechny příkazy byly vysvětleny v lekcích 11 a 12, nebudu se jimi tedy dále zabývat. Co mě zaráží, je to, že tlačítko není čtvercové. To ihned napravíme. Šířka je zdánlivě 2× větší než výška. Když tlačítko obsahuje text, je šířka dána poměrně podle velikosti textu. No a třeba text „1“ je dvakrát vyšší než široký, tak proto musím šířku 2× udělat větší, aby byla stejně velká jako výška. Trochu zamotané, ale co se dá dělat:
velikost = 2
tlacitko = Button(text = "1", width = velikost*2, height = velikost)
.pack a .grid
Button tlačítko vytváří, pack ho zobrazuje. Metodě pack se také říká Správce zobrazení/rozmístnění. Je vhodná na jednoduché rozmístnění. Na složitější a přesnější je lépe používat jiného Správce - grid. U grid musíme přesně říci, na kterém pomyslném řádku a sloupci udělátko (tlačítko) leží. Začíná se na nule. V našem případě je tam jen jedna řádka a jeden sloupec - 0 a 0.
tlacitko.grid(row=0, column=0)
2×2
Chtějme vytvořit pole 4 tlačítek. Naprostá ošklivost by bylo tohle:
tlacitko1 = Button(text="1", width=velikost*2, height=velikost)
tlacitko1.grid(row=0, column=0)
tlacitko2 = Button(text="1", width=velikost*2, height=velikost)
tlacitko2.grid(row=0, column=1)
tlacitko3 = Button(text="1", width=velikost*2, height=velikost)
tlacitko3.grid(row=1, column=0)
tlacitko4 = Button(text="1", width=velikost*2, height=velikost)
tlacitko4.grid(row=1, column=1)
Tudy cesta nevede! Představte si tímto způsobem vytvářet 81 tlačítek! Kdo se v tom bude chtít pak vyznat? Raději se naučme něco nového.
Samozřejmě musíme použít cyklus - for bude nejlepší. Dále si musíme jednotlivá tlačítka pamatovat - budeme je dávat do seznamu. A taky musíme nějak vyřešit počítání řádků a sloupců.
seznamTlacitek = []
pocetRadku = 4
pocetSloupcu = 2
for poradi in range(pocetRadku*pocetSloupcu):
tlacitko = Button(text=str(poradi), width=velikost*2, height=velikost)
radek = ????
sloupec = ?????
tlacitko.grid(row=radek, column=sloupec)
seznamTlacitek.append(tlacitko)
Jak vypočítat z pořadového čísla tlačítka řádek a sloupec? Na to vám ukáži jeden malý trik. Celočíselné dělení a zbytek po dělení. Zamyslete se nad tím, zkuste si to s konkrétními čísly, ať to pochopíte. Bude se vám to ještě hodit.
radek = poradi / pocetSloupcu
sloupec = poradi % pocetSloupcu
Instance
Button je třída tlačítek a tlacitko je jeho potomek, instance Buttonu. Je to krásně vidět, když zavřeme okno s tlačítky a necháme si Python prompt a zadáme:
>>> print seznamTlacitek
[<Tkinter.Button instance at 0x009E1170>, <Tkinter. Button instance at
0x009E1260>, <Tkinter.Button instance at 0x009E1288>, <Tkinter.Button
instance at 0x009E12D8>]
<Tkinter.Button instance at 0x009E1170> - třeba zde se jedná o instanci třídy Button, která leží na adrese 0x009E1170. Adresa je u každého tlačítka jiná, podle toho se dají rozpoznat.
Původně jsme měli v programu instanci (proměnnou) pojmenovanou tlacitko, nyní tedy budeme k těmto instancím (proměnným) přistupovat takto (v těchto případech tedy není jedno, jestli print použiji nebo ne):
>>> seznamTlacitek[0]
<Tkinter.Button instance at 0x009E1170> # to je instance
>>> print seznamTlacitek[0]
.10359152 # to je vnitřní jedinečné "jméno" instance
>>> seznamTlacitek[1]
<Tkinter.Button instance at 0x009E1260>
9×9
Pole tlačítek 9×9 získáme snad již jednoduše:
pocetRadku = 9
pocetSloupcu = 9
Pokračování příště. Ukážeme si, jak udělat, když kliknu na tlačítko, aby se něco stalo. Nebo když na něj dvojkliknu nebo kliknu pravým tlačítkem myši nebo Enterem apod.
Úkol
Pošlete mi funkční program s dokumentačním řetězcem a případně komentáři. Použijte ještě další parametry Button, kromě width a height, hlavně relief, abyste si vyzkoušeli vzhled tlačítka, případně barvy pozadí. Všechny možné parametry k Button najdete zde. Počet tlačítek <= 400.