GUI v Tk snadno a rychle

7. 10. 2004
Doba čtení: 6 minut

Sdílet

Rozšíření Tk jazyka Tcl je více než výkoné. Díky němu jste schopni vytvořit kompletní GUI během okamžiku, přičemž vaše implementace bude přenositelná. V následujících článcích bych vás chtěl zasvětit do jeho základů.

V tomto a následujících článcích budu předpokládat, že máte přečtené články TCL základy, nebo jste jinak obeznámeni se základy jazyka Tcl. Tk je jen rozšíření, takže vám vřele doporučuji se podle toho zachovat.

Ke spuštění programů využívajících Tk samozřejmě také potřebujete interpreter. Tím interpreterem už ale není tclsh, nýbrž wish, což je klasický interpreter jazyka Tcl, který navíc načítá knihovny Tk. Jeho chování je tedy totožné s chováním tclsh.

Rozšíření Tk (Tool Kit) obohacuje jazyk Tcl o tzv. primitiva (angl. widget). Tato primitiva jsou do určité míry novými příkazy, ne však úplně identickými. Podporují jistý způsob zapouzdření, jaký známe z OOP modelu. Primitiva tedy obsahují metody, které na nich vykonají určité operace, dotazují se, resp. upravují vlastnosti či stav primitiva apod. Všechna primitiva jsou navíc uspořádána do jediné hierarchie, do které musíte zařadit i ta svá. Možná to někomu, kdo zatím programoval jen v procedurálních jazycích, připadá zbytečně složité, vězte ale, že tomu tak není. Zdejší příkazy by se daly charakterizovat asi takto:

příkaz cesta ?volby?

Část příkaz symbolizuje název příkazu. Volitelný argument volby umožňuje nastavit počáteční parametry nového primitiva. Povinný argument cesta je zjednodušeně řečeno pojmenování nového primitiva. Tento řetězec v sobě zahrnuje mimo samotný název také umístění primitiva v hierarchii. Některá primitiva jsou totiž schopna obsahovat další primitiva, čímž vytvářejí další úroveň. Pokud některé primitivum zanoříte, definujete to právě v jeho cestě. Zápis začíná znakem .(tečka), což je kořenová úroveň a každá následující úroveň se odděluje opět tečkou. Celé by se to dalo přirovnat k souborovému systému Unixu. Zde je kořenovým členem / (.), které může obsahovat jak soubory (primitiva), tak i adresáře (primitiva schopná obsahovat další primitiva, např. dialogové okno), přičemž každá úroveň je oddělena opět / (.). Aby té teorie nebylo moc, takhle by mohla vypadat část kódu:

label .zprava0 -text "Hello"
label .zprava1 -text "World"

Když to ale zkusíte, neuvidíte nic. Popisky sice existovat budou, ale nebudou vidět. Vy totiž musíte určit pro každé primitivum, kde a jak se zobrazí. Tuto činnost zajišťuje tzv. správce geometrie (geometry manager). Uvedu dva: pack a grid. První z nich je správce, který rozmisťuje primitiva relativně k jiným. V souvislosti s výše zmíněným příkladem byste jej mohli použít následovně:

pack .zprava0 -side bottom -padx 10
pack .zprava1 -side bottom -padx 10

Každý řádek znamená, že pack vloží primitivum ze strany bottom (česky spodek) vzhledem k předcházejícímu primitivu a udělá kolem něj horizontální mezeru o 10 bodech. Tento příklad je ovšem značně vyumělkovaný, v reálném použití by se celý napsal na jeden řádek místo čtyř:

pack [label .zprava -text "Hello\nWorld"] -padx 10

Druhý správce grid při práci využívá pomyslnou mřížku. Podle ní potom rozděluje vkládané prvky. V tom neohrabaném použití by to mohlo vypadat takto:

grid .zprava0 -column 0 -row 0 -padx 10
grid .zprava1 -column 0 -row 1 -padx 10

Argument -column určuje sloupec a argument -row řádek mřížky, do kterých se má primitivum vložit. Význam -padx je stejný.

Pokud se odvážíte nahlédnout do dokumentace, naleznete v ní obrovské množství různých voleb a parametrů, s nimiž byste měli být schopni dotáhnout do konce jakékoli rozvržení. Také si všimněte, že se vůbec nemusíte starat o velikosti jednotlivých primitiv, neboť správce rozvržení všechno spočítá za vás – a dokonce i za běhu, aniž byste se o to nějak přičinili.

Tcl/Tk je vystaven na tzv. událostním modelu. Během vykonávání aplikace jsou v určitých situacích generovány události, ke kterým jsou přidruženy obslužné rutiny pro jejich ošetření. Dojde-li k takovéto události, je automaticky zavolána obslužná rutina, která se patřičně zachová. Tento model se využívá v mnoha oblastech mnoha jazyků a nejspíš jste se s ním již někdy setkali.

Některá primitiva (jako třeba button – tlačítko) přímo obsahují argument -command, za nějž dosadíte kód, který se má provést při jeho akci. Ne všechna primitiva ale mohou provést nějakou akci a navíc událostí je celá řada. Proto v Tk je obsažen příkaz bind, pomocí něhož můžete přidružit obslužnou rutinu k události generované určitým primitivem. Použití je vícero, ale nejčastější by se dalo charakterizovat asi takto:

bind cesta událost příkaz

Primitivum cesta od této chvíle bude reagovat na událost událost vykonáním příkaz. Každý typ události má svoji znakovou reprezentaci, přičemž je možno deklarovat i kombinovanou událost. Zapisují se do < > (intervalů). Bereme-li v potaz výše uvedený zkrácený příklad, mohli bychom použít:

bind .zprava <Enter> {wm iconify .}
bind .zprava <Control-Enter> {puts "Slez ze me!"}

Když teď zamíříte kurzorem myši na popisek .zprava, okamžitě se hlavní okno minimalizuje. Abyste byli schopni „kroužit“ nad ním, musíte mít při vstupu na něj stisknutu modifikační klávesu Ctrl. Potom jen na konzoli vykřikne Slez ze me!, ale neminimalizuje se. Zde je vidět, jak jednoduché může být použití Tk pro tvorbu GUI. Implementací podobné podpory na tři řádky se může chlubit jen málo technologií.

Dále bych vás seznámil s některými základními primitivy. V Tk nemusíte znát hromady primitiv, abyste byli schopni vytvářet užitečné programy. Vystačíte si se znalostí jen několika a ta speciální potom jen dohledáváte, nebo dohledáváte detaily k těm již známým.

Jak jsem již uvedl výše, při vytváření primitiva je možno mu předat počáteční parametry. Pokud tak není učiněno při vytváření, použije se volba configure, která změní libovolnou hodnotu/vlastnost primitiva. Další volbou, kterou vlastní každé primitivum je volba cget. Tato volba naopak hodnoty čte.

cesta configure vlastnost hodnota ?vlastnost hodnota ...?
cesta cget vlastnost

Těmi nejužívanějšími objekty v každém GUI jsou bezesporu tlačítka. Klasické tlačítko je reprezentováno názvem button. Popisek tlačítka můžete nastavit parametrem -text a akci přidružíte parametrem -command.

proc setText {} {
  .tl configure -text "Stiskl jsi me"
  after 1000 {.tl configure -text "Stiskni me"}
}

button .tl -text "Stiskni me" -command setText
pack .tl

V tomto příkladu vytváříme tlačítko .tl s přednastaveným popiskem na Stiskni me, které má při akci provést procedurusetText. V této proceduře jsem použil volbu configure, pomocí níž jsem přenastavil popisek, počkal sekundu pomocí příkazu after a nakonec popisek vrátil do původní podoby. Jinými slovy, při stisku tlačítka se jeho popisek změní po dobu jedné sekundy a následně se vrátí do původní podoby.

Tk dává k dispozici mimo klasické tlačítko i zaškrtávací tlačítko checkbutton a přepínací tlačítko radiobutton. Jsou si navzájem trochu podobná – obě dovolují uživateli vybrat z několika možností. Zatímco u zaškrtávacích tlačítek je dovoleno vybrat možností více, mezi přepínacími tlačítky je dovoleno vybrat jen jedinou možnost. Obě podporují parametry -text a -command. Zaškrtávací tlačítkocheckbutton používá volbu -variable, za níž dosadíte název globální proměnné. Tato proměnná posléze bude odrážet stav zaškrtávacího tlačítka (0 nebo 1). Přepínací tlačítko radiobutton také obsahuje parametr -variable. Pro přepínací tlačítka, která hodláte stmelit, musíte použít stejnou globální proměnnou. Tím budou vědět, že patří k sobě. Důležitým parametrem je -value. Ten určuje, jakou hodnotu bude mít globální proměnná při výběru daného tlačítka. Názorně předvedu:

bitcoin_skoleni

checkbutton .cb -text "zaskrtavaci tl." -variable have \
    -command {puts $have}
radiobutton .rb0 -text "prepinaci tl. 1" -variable rv \
    -value "radio 1" -command {puts $rv}
radiobutton .rb1 -text "prepinaci tl. 2" -variable rv \
    -value "radio 2" -command {puts $rv}

grid .cb -column 0 -row 1
grid .rb0 -column 1 -row 0 -sticky "w"
grid .rb1 -column 1 -row 1 -sticky "w"

Tak to by prozatím mohlo stačit. Jak jste viděli, v Tk můžete vytvářet velmi rychle efektivní skripty pro podporu GUI, aniž by vám to dalo moc práce. Je to ideální jazyk, pokud potřebujete vytvořit jednoduchý program, který chcete mít v grafickém prostředí. Je hloupost vytvářet jednoduchý program v Céčku, neboť potom s největší pravděpodobností strávíte nejvíce času právě na GUI.

Také bych rád podotkl, že v době, kdy jsem psal tento článek, se v nabídce nakladatelství Computer Press objevila publikace „Průvodce programovacími jazyky TCL/TK“, nejspíše s dobrou hloubkou zasvěcení, neboť jejich katalog uvádí 420 stran. Sice jsem doposud neměl to štěstí, abych si ji alespoň prolistoval, nicméně určitě to bude dobrý zdroj informací (hlavně pro neangličtináře).

Autor článku