Obsah
1. Použití nabídek (menu) v knihovně Tkinter
4. Demonstrační příklad – vytvoření menubaru
5. Menubar v kombinaci s dalšími widgety
6. Popup menu (kontextové menu)
7. Demonstrační příklad – vytvoření kontextového menu a navázání jeho zobrazení na tlačítko myši
9. Demonstrační příklad – základní roletové menu
11. Změna barev jednotlivých položek menu
12. Podtržení znaků v položkách menu pro jejich rychlý výběr
13. Přidání obrázků (ikon) k položkám menu
14. Repositář s demonstračními příklady
1. Použití nabídek (menu) v knihovně Tkinter
Nabídky (menu) patří mezi nedílnou součást prakticky každého složitějšího programu s grafickým uživatelským rozhraním. Systém menu zobrazuje uživateli GUI aplikace jednu nebo více zobrazitelných nabídek, které je možné vybrat, nastavit nebo přepnout; na rozdíl od dialogů však menu na ploše obrazovky zabírá jen minimální místo či dokonce žádné místo v případě kontextových menu. Bývá dobrým zvykem, že menu ve své struktuře obsahuje všechny příkazy a parametry provozované aplikace (ne všechny příkazy musí být samozřejmě po celou dobu běhu aplikace dostupné, někdy mohou být „zašedlé“).
Obrázek 1: Velmi jednoduchý textový procesor nazvaný Typewriter, který byl naprogramován pro mikropočítače ZX Spectrum, používá asi nejjednodušší systém menu vůbec (ostatně podle takových nabídek vlastně menu dostala svůj název).
Dnes se bohužel i u profesionálních aplikací stává, že je toto pravidlo často porušováno a některé příkazy zůstávají skryty pouze v dialozích nebo konfiguračních souborech. Mezi velké výhody menu patří to, že si uživatel nemusí pamatovat způsob zadávání parametrů (například pomocí klíčových slov nebo formulářů) – vše je snadno dosažitelné právě ze struktury menu. Také pro programátory je tvorba menu mnohdy jednodušší než návrh dialogových boxů (což ostatně uvidíme v dalších kapitolách). Na druhou stranu může systém menu zdržovat v práci zkušenější uživatele. Z tohoto důvodu je vhodné menu vhodným způsobem spojit s dalšími prvky grafického uživatelského rozhraní (tlačítky, výběrovými boxy a především tzv. horkými klávesami).
Obrázek 2: Klasická roletová menu se používala už v počítačovém dávnověku, například i v Microsoft Windows 1.0 spuštěné na emulátoru počítače PC XT s grafickou kartou CGA.
2. Typy nabídek/menu
V některých systémech GUI je menu složeno z jednodušších objektů (widgetů). Z toho také vyplývá, že se zde menu chová jako kontejner schopný pojmout další widgety. Existují však i GUI systémy, v nichž je menu považováno za jeden dynamicky se měnící widget, který je rozdělen do jednotlivých objektů – položek menu (to má výhodu v tom, že se pro menu alokuje méně systémových zdrojů; to však dnes již nebývá kritickým parametrem jako v dobách, kdy se například každému widgetu přiřazovalo jen šestnáctibitové číslo, které navíc muselo být pro celý systém unikátní).
Obrázek 3: Grafické uživatelské rozhraní grafického editoru DEGAS Elite s toplevel menu i s takzvaným screen menu.
Příkazy je možné z menu vyvolat pomocí tlačítek (push-button/button). S využitím tlačítek se přímo spouští nějaká naprogramovaná akce. Dále je možné v menu používat zaškrtávací/výběrová tlačítka (check-button/checkbutton) a přepínací tlačítka (radio-button/radiobutton). V případě, že je menu hierarchicky strukturováno, je k dispozici ještě tlačítko, které slouží k přechodu na nižší úroveň. Některé programy, například původní vývojová prostředí firmy Borland, používaly pouze jednoúrovňové menu, v dalších programech jsou menu mnohdy složitě strukturovaná a uživatelsky konfigurovatelná (GIMP apod.).
V průběhu vývoje grafických uživatelských rozhraní se ustálily čtyři hlavní typy menu:
- roletové menu (pull down)
- vynořující se menu (pop up/popup) – také nazývané kontextové menu
- výběrové menu (option)
- kaskádové menu (cascading)
V navazujících kapitolách si jednotlivé typy menu popíšeme, spolu s ukázkami jejich podpory v knihovně Tkinter.
3. Toplevel menu (menubar)
Některé aplikace ze systému menu používají pouze jednoduchou lištu, na které jsou statická tlačítka popř. se položky menu dynamicky mění. Tento způsob však ztratil svůj půvab ve chvíli, kdy množství funkcí dostupných z menu rapidně vzrostlo na desítky a někdy i stovky příkazů. Příkladem aplikací využívajících pouze lištu menu je například Lotus 1–2–3 nebo z ještě starších aplikací textový editor Cheops Writer dostupný pro osmibitové domácí mikropočítače Atari. Opakem menu zobrazovaného pouze na liště je takzvané screen menu používané například u starších verzí AutoCADu – toto menu se později jako velká „novinka“ objevilo i u Microsoft Office. V knihovně Tkinter se menu s jedinou lištou (toplevel menu) vytváří velmi snadno, jak je ostatně patrné z prvního demonstračního příkladu popsaného v navazující kapitole.
Obrázek 4: Textový procesor Cheops'Writer: dvouřádkové hlavní menu (toplevel menu) textového procesoru navržené ve stylu Lotus 1–2–3.
4. Demonstrační příklad – vytvoření menubaru
Dnešní první demonstrační příklad je velmi jednoduchý, protože je v něm ukázán způsob vytvoření „toplevel“ menu (neboli menubaru) obsahujícího pouze dvě příkazová tlačítka. Po stisku prvního tlačítka se zavolá uživatelsky definovaná funkce test, po stisku tlačítka druhého pak metoda root.quit(), která ukončí běh aplikace:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) menubar.add_command(label="Test", command=test) menubar.add_command(label="Quit", command=root.quit) root.config(menu=menubar) root.mainloop()
Obrázek 5: První demonstrační příklad.
5. Menubar v kombinaci s dalšími widgety
V dalším příkladu je ukázáno, že menubar je možné bez problému kombinovat s dalšími widgety. Samotný menubar je přitom jakoby vyjmut z mřížky, do níž se vkládají ostatní widgety tvořící GUI aplikace, takže widgety se mohou vkládat i do prvního řádku mřížky, který ve skutečnosti leží až pod menubarem:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) menubar.add_command(label="Test", command=test) menubar.add_command(label="Quit", command=root.quit) root.config(menu=menubar) style = ttk.Style() style.theme_use("alt") style.configure('Red.TButton', background='#ff8080') radio_var = tkinter.StringVar() radio_var.set("Python") langs = ("Assembler", "Basic", "Brainfuck", "C", "Python") f1 = ttk.LabelFrame(root, text="Languages") f2 = ttk.LabelFrame(root, text="Commands") radio_buttons = (ttk.Radiobutton(f1, text=lang, value=lang, variable=radio_var) for lang in langs) showButton = ttk.Button(f2, text="Show var", command=lambda: print(radio_var.get())) quitButton = ttk.Button(f2, text="Exit", style='Red.TButton', command=root.quit) for i, radio_button in enumerate(radio_buttons): radio_button.grid(column=1, row=i, sticky="w") showButton.grid(column=1, row=1, sticky="we", padx=6, pady=6) quitButton.grid(column=1, row=2, sticky="we", padx=6, pady=6) f1.grid(column=1, row=1, sticky="ne", padx=6, pady=6) f2.grid(column=2, row=1, sticky="ne", padx=6, pady=6) root.mainloop()
Obrázek 6: Druhý demonstrační příklad.
6. Popup menu (kontextové menu)
Vynořující se menu (pop up/popup), která jsou někdy nazývána také kontextová menu, jsou charakteristická tím, že se mohou zobrazit (vynořit) v kterémkoli místě okna aplikace (netypický zástupce vynořujícího se menu byl použit například ve známém textovém editoru T602, zde se však menu vynořovalo vždy na stejném místě). Často se podle místa také mění příkazy dostupné z menu. Toto menu je výhodné v tom, že spoří místo v okně a navíc se při ovládání aplikace myší nemusí při vyvolání menu dojíždět až na lištu, jak tomu je v případě roletových menu. Rovněž dynamická (kontextová) změna příkazů v menu je velmi výhodná, protože uživatel dostane k dispozici pouze ty příkazy, které mají pro vybraný objekt smysl. Jediná nevýhoda tohoto typu menu spočívá v tom, že uživatel musí o existenci menu předem vědět nebo experimentovat.
V knihovně Tkinter se s kontextovými menu pracuje poměrně jednoduše (význam parametru tearoff si vysvětlíme v dalším textu):
popup = tkinter.Menu(root, tearoff=0) popup.add_command(label="Open") popup.add_command(label="Save") popup.add_separator() popup.add_command(label="Exit", command=root.quit)
Nesmíme ovšem zapomenout na navázání nějaké události k vyvolání (zobrazení) tohoto typu menu. Typicky se pro vyvolání tohoto menu používá pravé tlačítko myši, jak je ostatně naznačeno v následujícím úryvku kódu (připomeňme si, že tlačítka myši jsou v knihovně Tkinter číslována trošku zmateně, takže pravé tlačítko má číslo 3):
root.bind("<Button-3>", on_popup)
Výše uvedený zápis zavolá funkci on_popup ve chvíli, kdy je na ploše hlavního okna stisknuto pravé tlačítko myši. Samotná funkce on_popup vypadá následovně:
def on_popup(event): popup.post(event.x_root-5, event.y_root-5)
Při umístění menu pomocí metody popup.post() je možné použít speciální atributy x_root a y_root objektu event, které udávají absolutní pozici kurzoru myši.
Poznámka: od pozice kurzoru odečítám hodnotu 5 pixelů, protože v takovém případě bude kurzor automaticky umístěn na první položku menu (resp. přesněji řečeno bude první položka menu posunuta tak, aby byla pod kurzorem myši).
7. Demonstrační příklad – vytvoření kontextového menu a navázání jeho zobrazení na tlačítko myši
Všechny důležité funkce nutné pro vytvoření kontextového menu jsme si již popsali v předchozí kapitole, takže se nyní podívejme na to, jak je možné kontextové menu přidat do aplikace s jediným (prozatím prázdným) oknem a jak se zobrazení tohoto menu naváže na pravé tlačítko myši:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() popup = tkinter.Menu(root, tearoff=0) popup.add_command(label="Open") popup.add_command(label="Save") popup.add_separator() popup.add_command(label="Exit", command=root.quit) def on_popup(event): popup.post(event.x_root-5, event.y_root-5) root.bind("<Button-3>", on_popup) root.mainloop()
Obrázek 7: Kontextové menu ve třetím demonstračním příkladu.
8. Roletové menu (pull down)
Roletové menu (pull down) patří mezi základní typy menu a je proto dostupné prakticky ze všech aplikací využívajících grafické uživatelské rozhraní. Z celého menu je bez jeho aktivace viditelná pouze nejvyšší úroveň, která se nachází na takzvané liště. Standardně bývá lišta umístěna v horní části okna aplikace, i když samozřejmě existují různé výjimky. Mezi výhody tohoto typu menu patří skutečnost, že uživatel vždy vidí nejvyšší úroveň příkazů a nemusí tedy složitě pátrat nebo slepě zkoušet, ve kterém místě se menu aktivuje (to je případ mnohých multimediálních přehrávačů, u kterých autoři preferují „originalitu“ namísto použitelnosti :-). Další výhoda roletového menu spočívá ve stálé viditelnosti klíčů (horkých kláves) pro příkazy na základní úrovni (pokud tedy není viditelnost klíčů zakázána, což se kupodivu také poměrně často děje).
Obrázek 8: Roletové menu zobrazené čtvrtým příkladem.
V knihovně Tkinter je roletové menu vytvořeno jednoduše přidáním objektu typu Menu do toplevel menu (což již známe) metodou add_cascade:
menubar = tkinter.Menu(root) filemenu = tkinter.Menu(menubar) editmenu = tkinter.Menu(menubar) helpmenu = tkinter.Menu(menubar) menubar.add_cascade(label="File", menu=filemenu) menubar.add_cascade(label="Edit", menu=editmenu) menubar.add_cascade(label="Help", menu=helpmenu)
Obrázek 9: Roletové menu bez „odtrhovací“ části.
Do jednotlivých roletových menu se přidávají položky metodami add_command, add_cascade, add_checkbutton či add_radiobutton. Taktéž lze přidat oddělovač metodou add_cascade.
Obrázek 10: Roletové menu bez „odtrhovací“ části (klasický styl Windows XP).
9. Demonstrační příklad – základní roletové menu
V následujícím demonstračním příkladu jsou vytvořena tři roletová menu, která jsou pod jmény File, Edit a Help přidána do toplevel menu. Prozatím nepoužíváme žádnou speciální konfiguraci, takže jsou menu zobrazena s použitím výchozího stylu, bez horkých klíčů, ikon atd.:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) filemenu = tkinter.Menu(menubar) filemenu.add_command(label="Open") filemenu.add_command(label="Save") filemenu.add_separator() filemenu.add_command(label="Exit", command=root.quit) menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(menubar) editmenu.add_command(label="Undo") editmenu.add_separator() editmenu.add_command(label="Cut") editmenu.add_command(label="Copy") editmenu.add_command(label="Paste") editmenu.add_command(label="Delete") editmenu.add_separator() editmenu.add_command(label="Select All") menubar.add_cascade(label="Edit", menu=editmenu) helpmenu = tkinter.Menu(menubar) helpmenu.add_command(label="About", command=test) menubar.add_cascade(label="Help", menu=helpmenu) root.config(menu=menubar) root.mainloop()
10. Zákaz „odtrhovacího“ menu
Pravděpodobně jste si v předchozích demonstračních příkladech povšimli, že roletová menu byla „odtrhovací“, tj. výběrem čárkované čáry zobrazené ve vrchní části menu se menu může odtrhnout od svého okna a vytvořit tak okno samostatné. To je velmi výhodné, protože velkou část grafického uživatelského rozhraní je možné nahradit právě těmito typy menu a podle preferencí uživatele mohou být příkazy buď stále viditelné, nebo skryté v menu. Ze známých aplikací využívá tuto možnost například Gvim (pouze na některých GUI systémech), rastrový grafický editor GIMP a taktéž další rastrový grafický editor mtPaint.
Na druhou stranu nejsou uživatelé na podobné chování zvyklí, takže mohou požadovat „obyčejná menu“. Toho lze snadno dosáhnout. Buď se globálně (pro dané okno či pro celou hierarchii oken) nastaví konfigurační volba *tearOff na False:
root.option_add('*tearOff', False)
Nebo se při vytváření každého menu explicitně nastaví parametr tearOff na nulu:
filemenu = tkinter.Menu(menubar, tearoff=0) helpmenu = tkinter.Menu(menubar, tearoff=0) ... ... ...
Obrázek 11: Menu bez odtrhovací části.
V dalším příkladu je „odtrhování“ všech menu zakázáno globálně prvním zmíněným způsobem:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) root.option_add('*tearOff', False) filemenu = tkinter.Menu(menubar) filemenu.add_command(label="Open") filemenu.add_command(label="Save") filemenu.add_separator() filemenu.add_command(label="Exit", command=root.quit) menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(menubar) editmenu.add_command(label="Undo") editmenu.add_separator() editmenu.add_command(label="Cut") editmenu.add_command(label="Copy") editmenu.add_command(label="Paste") editmenu.add_command(label="Delete") editmenu.add_separator() editmenu.add_command(label="Select All") menubar.add_cascade(label="Edit", menu=editmenu) helpmenu = tkinter.Menu(menubar) helpmenu.add_command(label="About", command=test) menubar.add_cascade(label="Help", menu=helpmenu) root.config(menu=menubar) root.mainloop()
V příkladu druhém je menu File a Help „normální“, zatímco menu Edit je odtrhovací:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Open") filemenu.add_command(label="Save") filemenu.add_separator() filemenu.add_command(label="Exit", command=root.quit) menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(menubar) editmenu.add_command(label="Undo") editmenu.add_separator() editmenu.add_command(label="Cut") editmenu.add_command(label="Copy") editmenu.add_command(label="Paste") editmenu.add_command(label="Delete") editmenu.add_separator() editmenu.add_command(label="Select All") menubar.add_cascade(label="Edit", menu=editmenu) helpmenu = tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="About", command=test) menubar.add_cascade(label="Help", menu=helpmenu) root.config(menu=menubar) root.mainloop()
Poznámka: povšimněte si použití metody add_separator pro vizuální oddělení jednotlivých položek menu.
11. Změna barev jednotlivých položek menu
Podobně jako u většiny standardních widgetů lze i u položek menu měnit barvy textu či barvy pozadí. Na dalším demonstračním příkladu je ukázáno, jakým způsobem je možné vytvořit různobarevné položky. Položky však nejsou vytvářeny otrocky jedna po druhé, ale je použita n-tice nazvaná colors, která se zpracovává s využitím generátorové notace seznamu:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Open") filemenu.add_command(label="Save") filemenu.add_separator() filemenu.add_command(label="Exit", command=root.quit) menubar.add_cascade(label="File", menu=filemenu) editmenu = tkinter.Menu(menubar, tearoff=0) editmenu.add_command(label="Undo") editmenu.add_separator() editmenu.add_command(label="Cut") editmenu.add_command(label="Copy") editmenu.add_command(label="Paste") editmenu.add_command(label="Delete") editmenu.add_separator() editmenu.add_command(label="Select All") menubar.add_cascade(label="Edit", menu=editmenu) colors = ("white", "yellow", "orange", "red", "magenta", "blue", "cyan", "green") colormenu = tkinter.Menu(menubar, tearoff=0) for color in colors: colormenu.add_command(label=color, background=color) menubar.add_cascade(label="Colors", menu=colormenu) helpmenu = tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="About", command=test) menubar.add_cascade(label="Help", menu=helpmenu) root.config(menu=menubar) root.mainloop()
Obrázek 12: Výběr barev v minoritním OS.
Obrázek 13: Výběr barev v Linuxu.
Obrázek 14: Opět výběr barev v Linuxu.
12. Podtržení znaků v položkách menu pro jejich rychlý výběr
Jednotlivé položky menu je možné modifikovat pomocí několika příkazů. Pravděpodobně nejpoužívanější modifikací je přiřazení horkých klíčů jednotlivým položkám. To se provádí pomocí volby underline, za kterou následuje index znaku, který má být podtržen. První znak má index rovný nule. V některých GUI systémech je horký klíč specifikován přímo v textu jednotlivých položek pomocí speciálního znaku (například ampersandu). Tuto funkcionalitu je do knihovny Tkinter také možné doplnit pomocí jednoduché procedury, která bude mít jako své parametry identifikátor menu a řetězec se speciálním znakem.
Poznámka: horké klíče (hotkeys) se odlišují od klávesových zkratek, protože je jejich použití pouze lokální v rámci jediného menu. Pro větší zmatky se však tento termín někdy používá i v kontextu globálně použitelné klávesové zkratky.
Obrázek 15: Menu obsahuje položky s horkými klíči.
Použití indexu je samozřejmě univerzálnější, takže se podívejme, jak je realizováno:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Open", underline=0) filemenu.add_command(label="Save", underline=0) filemenu.add_separator() filemenu.add_command(label="Exit", underline=1, command=root.quit) menubar.add_cascade(label="File", menu=filemenu, underline=0) editmenu = tkinter.Menu(menubar, tearoff=0) editmenu.add_command(label="Undo", underline=0) editmenu.add_separator() editmenu.add_command(label="Cut", underline=2) editmenu.add_command(label="Copy", underline=0) editmenu.add_command(label="Paste", underline=0) editmenu.add_command(label="Delete", underline=2) editmenu.add_separator() editmenu.add_command(label="Select All", underline=7) menubar.add_cascade(label="Edit", menu=editmenu, underline=0) colors = ("white", "yellow", "orange", "red", "magenta", "blue", "cyan", "green") colormenu = tkinter.Menu(menubar, tearoff=0) for color in colors: colormenu.add_command(label=color, background=color) menubar.add_cascade(label="Colors", menu=colormenu, underline=0) helpmenu = tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="About", command=test, underline=0) menubar.add_cascade(label="Help", menu=helpmenu, underline=0) root.config(menu=menubar) root.mainloop()
13. Přidání obrázků (ikon) k položkám menu
K jednotlivým položkám menu je možné přidat i ikony, tedy rastrové obrázky. Obrázky je možné vytvořit programově, mnohem častěji se však nahrávají z externích souborů. V následujícím demonstračním příkladu je ukázáno, jakým způsobem je možné rastrové obrázky nahrát ze souboru. Základem je použití konstruktoru:
image_object = tkinter.PhotoImage(file="jméno_souboru_s_ikonou")
Tento konstruktor dokáže načíst obrázek v některém z podporovaných formátů, mezi něž patří především GIF (nikoli však již PNG). U obrázků je nutné si dát pozor na to, aby objekt nebyl automaticky odstraněn správcem paměti, který nedokáže detekovat existenci reference v knihovně Tk. Z tohoto důvodu budou všechny obrázky (prozatím) načteny do globálních proměnných:
open_image = tkinter.PhotoImage(file="icons/document-open.gif") save_image = tkinter.PhotoImage(file="icons/document-save.gif") exit_image = tkinter.PhotoImage(file="icons/application-exit.gif") undo_image = tkinter.PhotoImage(file="icons/edit-undo.gif") cut_image = tkinter.PhotoImage(file="icons/edit-cut.gif") copy_image = tkinter.PhotoImage(file="icons/edit-copy.gif") paste_image = tkinter.PhotoImage(file="icons/edit-paste.gif") delete_image = tkinter.PhotoImage(file="icons/edit-delete.gif") select_all_image = tkinter.PhotoImage(file="icons/edit-select-all.gif")
Dále je možné přiřadit obrázek k položce menu. Parametr compound je důležitý, jinak bude obrázek zobrazen namísto nápisu, zatímco my potřebujeme mít zobrazen jak obrázek, tak i nápis současně:
filemenu.add_command(label="Open", underline=0, image=open_image, compound="left")
Obrázek 16: Menu s ikonami.
Poznámka: pokud máte ikony uložené ve formátu PNG, použijte pro konverzi knihovnu PIL (Python Imaging Library).
Úplný zdrojový kód vypadá následovně:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) open_image = tkinter.PhotoImage(file="icons/document-open.gif") save_image = tkinter.PhotoImage(file="icons/document-save.gif") exit_image = tkinter.PhotoImage(file="icons/application-exit.gif") undo_image = tkinter.PhotoImage(file="icons/edit-undo.gif") cut_image = tkinter.PhotoImage(file="icons/edit-cut.gif") copy_image = tkinter.PhotoImage(file="icons/edit-copy.gif") paste_image = tkinter.PhotoImage(file="icons/edit-paste.gif") delete_image = tkinter.PhotoImage(file="icons/edit-delete.gif") select_all_image = tkinter.PhotoImage(file="icons/edit-select-all.gif") filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Open", underline=0, image=open_image, compound="left") filemenu.add_command(label="Save", underline=0, image=save_image, compound="left") filemenu.add_separator() filemenu.add_command(label="Exit", underline=1, image=exit_image, compound="left", command=root.quit) menubar.add_cascade(label="File", menu=filemenu, underline=0) editmenu = tkinter.Menu(menubar, tearoff=0) editmenu.add_command(label="Undo", underline=0, image=undo_image, compound="left") editmenu.add_separator() editmenu.add_command(label="Cut", underline=2, image=cut_image, compound="left") editmenu.add_command(label="Copy", underline=0, image=copy_image, compound="left") editmenu.add_command(label="Paste", underline=0, image=paste_image, compound="left") editmenu.add_command(label="Delete", underline=2, image=delete_image, compound="left") editmenu.add_separator() editmenu.add_command(label="Select All", underline=7, image=select_all_image, compound="left") menubar.add_cascade(label="Edit", menu=editmenu, underline=0) colors = ("white", "yellow", "orange", "red", "magenta", "blue", "cyan", "green") colormenu = tkinter.Menu(menubar, tearoff=0) for color in colors: colormenu.add_command(label=color, background=color) menubar.add_cascade(label="Colors", menu=colormenu, underline=0) helpmenu = tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="About", command=test, underline=0) menubar.add_cascade(label="Help", menu=helpmenu, underline=0) root.config(menu=menubar) root.mainloop()
Program si samozřejmě můžeme značně zjednodušit, například tak, že se obrázky načtou v jediné smyčce do slovníku:
image_names = [ "document-open", "document-save", "application-exit", "edit-undo", "edit-cut", "edit-copy", "edit-paste", "edit-delete", "edit-select-all"] images = {} for image_name in image_names: images[image_name] = tkinter.PhotoImage(file="icons/%s.gif" % image_name)
Následně je možné si obrázky jednoduše ze slovníku „vytáhnout“:
filemenu.add_command(label="Open", underline=0, image=images["document-open"], compound="left")
Úplný zdrojový kód vypadá takto:
#!/usr/bin/env python import tkinter from tkinter import ttk def test(): print("Test!") root = tkinter.Tk() menubar = tkinter.Menu(root) image_names = [ "document-open", "document-save", "application-exit", "edit-undo", "edit-cut", "edit-copy", "edit-paste", "edit-delete", "edit-select-all"] images = {} for image_name in image_names: images[image_name] = tkinter.PhotoImage(file="icons/%s.gif" % image_name) filemenu = tkinter.Menu(menubar, tearoff=0) filemenu.add_command(label="Open", underline=0, image=images["document-open"], compound="left") filemenu.add_command(label="Save", underline=0, image=images["document-save"], compound="left") filemenu.add_separator() filemenu.add_command(label="Exit", underline=1, image=images["application-exit"], compound="left", command=root.quit) menubar.add_cascade(label="File", menu=filemenu, underline=0) editmenu = tkinter.Menu(menubar, tearoff=0) editmenu.add_command(label="Undo", underline=0, image=images["edit-undo"], compound="left") editmenu.add_separator() editmenu.add_command(label="Cut", underline=2, image=images["edit-cut"], compound="left") editmenu.add_command(label="Copy", underline=0, image=images["edit-copy"], compound="left") editmenu.add_command(label="Paste", underline=0, image=images["edit-paste"], compound="left") editmenu.add_command(label="Delete", underline=2, image=images["edit-delete"], compound="left") editmenu.add_separator() editmenu.add_command(label="Select All", underline=7, image=images["edit-select-all"], compound="left") menubar.add_cascade(label="Edit", menu=editmenu, underline=0) colors = ("white", "yellow", "orange", "red", "magenta", "blue", "cyan", "green") colormenu = tkinter.Menu(menubar, tearoff=0) for color in colors: colormenu.add_command(label=color, background=color) menubar.add_cascade(label="Colors", menu=colormenu, underline=0) helpmenu = tkinter.Menu(menubar, tearoff=0) helpmenu.add_command(label="About", command=test, underline=0) menubar.add_cascade(label="Help", menu=helpmenu, underline=0) root.config(menu=menubar) root.mainloop()
Obrázek 17: Menu s ikonami.
14. Repositář s demonstračními příklady
Zdrojové kódy všech dnes popsaných demonstračních příkladů naleznete pod následujícími odkazy:
Použité ikony naleznete na adrese https://github.com/tisnik/presentations/tree/master/Python_GUI/Tkinter/icons i s příslušnou licencí k použití.
15. Odkazy na Internetu
- Ovládací prvek (Wikipedia)
https://cs.wikipedia.org/wiki/Ovl%C3%A1dac%C3%AD_prvek_%28po%C4%8D%C3%ADta%C4%8D%29 - Rezervovaná klíčová slova v Pythonu
https://docs.python.org/3/reference/lexical_analysis.html#keywords - TkDocs: Styles and Themes
http://www.tkdocs.com/tutorial/styles.html - Drawing in Tkinter
http://zetcode.com/gui/tkinter/drawing/ - Changing ttk widget text color (StackOverflow)
https://stackoverflow.com/questions/16240477/changing-ttk-widget-text-color - Hra Breakout napísaná v Tkinteri
https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/ - The Hitchhiker's Guide to Pyhton: GUI Applications
http://docs.python-guide.org/en/latest/scenarios/gui/ - 7 Top Python GUI Frameworks for 2017
http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/ - GUI Programming in Python
https://wiki.python.org/moin/GuiProgramming - Cameron Laird's personal notes on Python GUIs
http://phaseit.net/claird/comp.lang.python/python_GUI.html - Python GUI development
http://pythoncentral.io/introduction-python-gui-development/ - Graphic User Interface FAQ
https://docs.python.org/2/faq/gui.html#graphic-user-interface-faq - TkInter
https://wiki.python.org/moin/TkInter - Tkinter 8.5 reference: a GUI for Python
http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html - TkInter (Wikipedia)
https://en.wikipedia.org/wiki/Tkinter - appJar
http://appjar.info/ - appJar (Wikipedia)
https://en.wikipedia.org/wiki/AppJar - appJar na Pythonhosted
http://pythonhosted.org/appJar/ - Stránky projektu PyGTK
http://www.pygtk.org/ - PyGTK (Wikipedia)
https://cs.wikipedia.org/wiki/PyGTK - Stránky projektu PyGObject
https://wiki.gnome.org/Projects/PyGObject - Stránky projektu Kivy
https://kivy.org/#home - Stránky projektu PyQt
https://riverbankcomputing.com/software/pyqt/intro - PyQt (Wikipedia)
https://cs.wikipedia.org/wiki/PyGTK - Stránky projektu PySide
https://wiki.qt.io/PySide - PySide (Wikipedia)
https://en.wikipedia.org/wiki/PySide - Stránky projektu Kivy
https://kivy.org/#home - Kivy (framework, Wikipedia)
https://en.wikipedia.org/wiki/Kivy_(framework) - QML Applications
http://doc.qt.io/qt-5/qmlapplications.html - KDE
https://www.kde.org/ - Qt
https://www.qt.io/ - GNOME
https://en.wikipedia.org/wiki/GNOME - Category:Software that uses PyGTK
https://en.wikipedia.org/wiki/Category:Software_that_uses_PyGTK - Category:Software that uses PyGObject
https://en.wikipedia.org/wiki/Category:Software_that_uses_PyGObject - Category:Software that uses wxWidgets
https://en.wikipedia.org/wiki/Category:Software_that_uses_wxWidgets - GIO
https://developer.gnome.org/gio/stable/ - GStreamer
https://gstreamer.freedesktop.org/ - GStreamer (Wikipedia)
https://en.wikipedia.org/wiki/GStreamer - Wax Gui Toolkit
https://wiki.python.org/moin/Wax - Python Imaging Library (PIL)
http://infohost.nmt.edu/tcc/help/pubs/pil/ - Why Pyjamas Isn’t a Good Framework for Web Apps (blogpost z roku 2012)
http://blog.pyjeon.com/2012/07/29/why-pyjamas-isnt-a-good-framework-for-web-apps/