Hlavní navigace

Interaktivní tvorba grafického uživatelského rozhraní s využitím nástroje Pygubu (2)

1. 4. 2021
Doba čtení: 39 minut

Sdílet

 Autor: Alejandro Autalan, Pygubu
Ve druhém článku o nástroji Pygubu určeného pro návrh grafického uživatelského rozhraní v Pythonu založeného na knihovně Tkinter si ukážeme některé další možnosti nabízené Tkinterem. Tyto možnosti jsou pochopitelně podporovány i v Pygubu.

Obsah

1. Interaktivní tvorba grafického uživatelského rozhraní s využitím nástroje Pygubu (2)

2. Krátké připomenutí: příklady popsané minule

3. Widgety v knihovně Tkinter

4. Kontejnery

5. Správce geometrie pack

6. Správce geometrie grid

7. Základní typy widgetů v knihovně Tk/Tkinter

8. Vlastnosti widgetů

9. „Odtrhávací“ menu

10. Realizace aplikace s „odtrhávacím“ menu

11. Klávesové zkratky navázané na jednotlivé položky menu

12. Realizace aplikace se specifikovanými klávesovými zkratkami

13. Registrace handleru události po stisku klávesové zkratky

14. Změna tématu zobrazení za běhu aplikace

15. Návrh aplikace s podobným chováním v nástroji Pygubu

16. Implementace handlerů zavolaných po stisku tlačítek na GUI

17. Standardní dialogová okna s otázkou (Ok/Cancel, Yes/No, Ok/Retry)

18. Příklad zobrazující všechna čtyři standardní dialogová okna

19. Repositář s demonstračními příklady

20. Odkazy na Internetu

1. Interaktivní tvorba grafického uživatelského rozhraní s využitím nástroje Pygubu (2)

V úvodním článku o projektu Pygubu jsme si řekli základní informace o možnostech poskytovaných tímto užitečným nástrojem. Ukázali jsme si taktéž trojici jednoduchých demonstračních příkladů a na závěr jsme se zmínili o některých alternativních projektech, především o RAD (Rapid Application Development) nástrojích Lazarus, Gambas a Qt Creator. Dnes si ukážeme některé další možnosti, které jsou nabízeny knihovnou Tkinter a podporovány v Pygubu. Většina dále popisovaných vlastností bude ukázána i na demonstračních příkladech, podobně jako tomu bylo i minule.

Obrázek 1: Dnes pro porovnání použijeme nejnovější verzi Pygubu designeru: 0.10.9, jejíž rozhraní je odlišné od předchozích verzí. Navíc byly přidány i některé užitečné vlastnosti, například podpora pro specifikaci klávesových zkratek u položek menu.

Poznámka: možná se může zdát, že podrobnější popis možností Tkinteru není při návrhu grafického uživatelského rozhraní důležitý, protože všechny operace přece provede Pygubu automaticky za vývojáře. Ve skutečnosti tomu tak není, a to zejména kvůli tomu, že Tkinter je velmi flexibilní a dynamicky se chovající knihovnou, která se v mnoha ohledech odlišuje například od „čistého“ GTK. Navíc Pygubu používá terminologii Tkinteru, kterou je tedy taktéž dobré znát.

Obrázek 2: Grafické uživatelské rozhraní Pygubu designeru verze 0.10.9.

2. Krátké připomenutí: příklady popsané minule

Připomeňme si, že v předchozím článku jsme si ukázali trojici (velmi jednoduchých až triviálních) demonstračních příkladů. Odkazy na tyto příklady naleznete v devatenácté kapitole.

Obrázek 3: Pro porovnání – takto vypadá Pygubu designer verze 0.9.

V prvním demonstračním příkladu byla do okna aplikace (což je prvek grafického uživatelského rozhraní nazvaný frame) vložena trojice ovládacích prvků GUI (takzvaných widgetů, o nichž se podrobněji zmíníme v dalším textu). Přitom byly jednotlivé ovládací prvky umístěny v rámci pravidelné mřížky (grid), která je sice neviditelná, ovšem umožňuje „pozicovat“ jednotlivé prvky v GUI nezávisle na rozlišení obrazovky a současně i nezávisle na zvolené velikosti okna. Toto řešení představuje poměrně zásadní odklon od staršího tradičního pohledu na GUI, v němž byly prvky umisťovány absolutně, tedy zadáním souřadnic vztažených k nějakému významnému bodu okna (typicky k levému hornímu rohu pracovní plochy okna – titulkový pruh ležel nad touto pracovní plochou), a například změna měřítka celého GUI v rámci nastavení operačního systému nebyla ve všech aplikacích korektně reflektována.

Obrázek 4: Rámec (okno aplikace) s dvojicí dalších prvků jsou základem prvního příkladu.

Ve druhém demonstračním příkladu jsme do hlavního (a současně i jediného) okna aplikace vložili menu. Na panelu menu byly zobrazeny dvě položky (File a Edit), po jejichž výběru se rozbalila skutečná menu s dalšími položkami, přičemž každá položka byla reprezentována jak textovým popisem, tak i ikonou uloženou v souboru typu PNG (ovšem podporovány jsou i další formáty, a to díky využití knihovny PIL/Pilow; samotná knihovna Tkinter/Tk ze známějších formátů podporuje pouze formát GIF). U textového popisku je možné zvolit index znaku, který bude podtržený a který lze využít pro rychlý výběr dané položky (to mj. znamená, že by daný znak měl být v rámci všech ostatních vybraných znaků v menu unikátní). Mezi jednotlivými položkami menu je možné vložit takzvaný separátor, což je pouze vizuální oddělovač, který nedokáže reagovat na operace prováděné uživatelem.

Obrázek 5: Návrh vzhledu hlavního menu aplikace.

Ve třetím a současně i posledním demonstračním příkladu bylo provedeno propojení mezi ovládacími prvky grafického uživatelského rozhraní na jedné straně s pythonovským kódem na straně druhé. Co to ovšem znamená v praxi? Pygubu nepracuje stejným způsobem jako plnohodnotné RAD, nedokáže tedy propojit návrh GUI s programovým kódem. Ovšem umožňuje specifikovat takzvanou callback funkci (ve skutečnosti však spíše callback metodu), která se má zavolat ve chvíli, kdy je nějaký prvek grafického uživatelského rozhraní vybrán. V Pygubu je nutné zapsat jméno příslušné metody, přičemž vazba mezi tímto jménem a konkrétní metodou implementovanou v Pythonu je provedena až v čase běhu aplikace (tedy v runtime). To je poměrně významný posun oproti některým tradičním RAD, v nichž se tato vazba vytváří již v čase návrhu aplikace (můžeme tedy říci, že v compile time). Zde je nutné poznamenat, že oba přístupy mají své přednosti, ale i zápory (kontrola aplikace při jejím návrhu versus mnohem větší flexibilita).

Obrázek 6: Třetí demonstrační příklad po spuštění.

3. Widgety v knihovně Tkinter

Základem prakticky všech v současnosti používaných grafických uživatelských rozhraní jsou takzvané widgety, které jsou někdy poněkud nepřesně označovány také jako komponenty. Z pohledu uživatele aplikací s grafickým uživatelským rozhraním se jedná o grafické prvky zobrazené na obrazovce, které mají předem známé chování a předvídatelnou funkci. V mnoha případech je chování widgetů standardizováno či alespoň doporučováno – viz například doporučení pro (dnes již notně zastaralý) Motif, Microsoft Windows, Mac OS a v neposlední řadě také doporučení pro GNOME a KDE.

Obrázek 7: Základní sada widgetů nabízená v rámci Ttk.

Velká část widgetů se snaží svým vzhledem do jisté míry reflektovat objekty z reálného světa (tlačítka, „teploměry“, přepínače programů, objekty známé z papírových formulářů apod.). Z pohledu programátora (a zejména programátora používajícího programovací jazyk Python) je naproti tomu widget objektem, kterému lze nastavit určitý stav a který reaguje na události, které při své práci generuje uživatel (přesouvání objektů na obrazovce, stlačování obrazů tlačítek pomocí myši či stylusu, psaní textu, gesta na dotykové obrazovce atd.).

Obrázek 8: Widgety přidané v rámci projektu Pygubu (nejedná se tedy o widgety ze standardní sady).

Mnoho widgetů nalezneme přímo v knihovně Tk, další pak v její rozšířené variantě Ttk a projekt Pygubu navíc umožňuje vytvářet a přidávat další typy widgetů plně integrovatelných do vyvíjených aplikací.

4. Kontejnery

Samotné widgety nejsou na obrazovce prakticky nikdy zcela osamocené, ostatně většina knihoven pro GUI by samostatný widget ani nedokázala zobrazit. Ve skutečnosti se téměř vždy nachází v nějakém okně, dialogu či dalším nadřazeném widgetu. Programátoři grafických uživatelských rozhraní se často setkají s pojmem kontejner. Jedná se o komponentu, na kterou lze vkládat různé widgety a mnohdy i další kontejnery. Obecně tak interně vzniká stromová datová struktura jejíž kořen je představován plochou na obrazovce, na které jsou umístěna okna aplikací (dnes je ovšem i samotná plocha obrazovky součástí větší virtuální plochy zobrazované obecně na více monitorech). V těchto oknech se dále nachází kontejnery a widgety. V mnoha grafických uživatelských rozhraních přitom mohou být vybrané widgety (zdaleka ne však všechny) současně i kontejnery. Kontejnery kromě jiného řeší i rozmístění widgetů na své ploše.

Obrázek 9: Základní sada kontejnerů knihovny Tk.

Způsobů pro rozmisťování widgetů do kontejnerů existuje více. Základní dělení je na kontejnery, kde jsou widgety umisťovány absolutně (do této kategorie patří WinAPI, MFC, OWL a VCL) a naopak kontejnery, které widgety většinou umisťují podle své velikosti a vzájemných vztahů (zde se nachází javovské AWT, Swing, GTK, Qt, námi používané Tk/Tkinter a mnoho dalších). V toolkitu Tk a tím pádem i v Tkinteru se mohou widgety umisťovat několika různými způsoby (pack, place a grid).

5. Správce geometrie pack

Nejprve si ukážeme použití správce geometrie nazvaného pack, který, jak již jeho jméno naznačuje, zarovnává jednotlivé widgety vedle sebe, a to buď ve směru horizontálním, či vertikálním. V prvních verzích knihovny Tk se jednalo o jediného dostupného správce, ale od verze 4.x (a ta vyšla již v počítačovém dávnověku) se objevují i další dva typy správců. Tento manažer umožňuje vkládat komponenty do kontejneru (typicky do okna) tak, že se zadává jejich relativní umístění (horizontální či vertikální zarovnání):

button1.pack()
button2.pack()
button3.pack()
button4.pack()

Obrázek 10: Widgety jsou umístěny pod sebou, což je implicitní chování manažeru geometrie „pack“.

Pro jednodušší dialogy může být tento správce použitelnější jednodušeji, než správce „grid“ (není nutné počítat řádky a sloupce).

Obrázek 11: Nastavení parametrů souvisejících se správcem rozvržení „pack“ v Pygubu.

6. Správce geometrie grid

Správce geometrie pack zmíněný v předchozí kapitole je sice velmi flexibilní (zejména při hierarchickém vkládání jednotlivých manažerů na sebe), v některých případech je však rozmisťování widgetů pomocí tohoto manažeru problematické nebo přinejmenším zdlouhavé. Z tohoto důvodu byl později vytvořen další správce geometrie, který je celkem trefně nazvaný grid. S využitím tohoto správce se widgety umisťují do pomyslné mřížky, přičemž rozměr mřížky se, spolu s počtem sloupců a řádků, flexibilně mění podle tvarových charakteristik vkládaných widgetů. Navíc je možné specifikovat, ke kterým okrajům jednotlivých buněk budou widgety „přilepeny“ – pokud jsou například přilepeny na západním i východním okraji, bude daný widget reagovat na změnu velikost dialogu a tím i změnu rozměrů mřížky.

Obrázek 12: Nejprimitivnější způsob použití správce rozvržení grid.

Poznámka: jméno manažeru grid sice může připomínat například GridLayout z Javy, ovšem Tkinterovská varianta je mnohem jednodušeji použitelná a současně i více flexibilní.

Obrázek 13: Nastavení parametrů souvisejících se správcem rozvržení „grid“ v Pygubu.

7. Základní typy widgetů v knihovně Tk/Tkinter

V průběhu mnoha let se množina widgetů používaných v různých grafických uživatelských rozhraních postupně rozšiřovala, ostatně postačí se podívat na obrázky z prvních grafických rozhraní navržených ve společnosti Xerox a porovnat je s moderním desktopem. Současně však také docházelo ke sjednocování vzhledu jednotlivých widgetů i jejich chování na různých platformách. Vzhled samozřejmě není na všech platformách přesně stejný, to však pro uživatele většinou nemusí představovat významnější praktický problém, na rozdíl od odlišného chování celého prostředí i jednotlivých widgetů.

xerox-gui

Obrázek 14: Ukázka grafického uživatelského rozhraní počítačového systému Xerox 8010 Star Information System.

V toolkitu Tk je k dispozici poměrně velké množství widgetů, podobně jako v dalších moderních toolkitech. Navíc dnes widgety existují ve dvou podobách – starší (původní) a novější (Ttk neboli „themed Tk“), které lépe odpovídají požadavkům uživatelů současných desktopových prostředí a jejichž vzhled a chování se může od původních widgetů odlišovat. V následující tabulce je uveden seznam základních typů widgetů. Pro mnoho aplikací je níže uvedená skupina widgetů dostačující, avšak v případě, že aplikace potřebuje vytvořit nový widget, je to samozřejmě možné, protože knihovna Tk je navržena tak, že ji lze poměrně jednoduchým způsobem rozšiřovat. V následující tabulce si také můžete všimnout toho, že některé widgety jsou pojmenovány odlišným způsobem od dnes používané terminologie. Vychází to z faktu, že Tcl/Tk je mnohem starší než většina dnešních GUI toolkitů.

Jméno widgetu Význam a funkce
label widget, který zobrazuje v okně či dialogu měnitelný text
button graficky zobrazené tlačítko, které implicitně reaguje na levé tlačítko myši
checkbutton dvoustavový přepínač, který implicitně reaguje na levé tlačítko myši
radiobutton widget, jichž může být sdruženo větší množství, vždy pouze jeden je vybraný
scale dnes nazýván pojmem slider atd., jedná se o widget s posuvnou částí a přidruženým textem, kde se zobrazuje hodnota v závislosti na poloze posuvné části
entry widget, do kterého je možné zapisovat text, k tomu má přidruženo mnoho klávesových zkratek (jde o kombinaci staršího a novějšího standardu)
spinbox widget určený pro zadávání číselných hodnot kombinací klávesnice a myši (i s kontrolou mezí)
menu vertikální menu, které se skládá z více položek
menubutton používá se spolu s menu pro vytváření jednotlivých položek
listbox widget, jež nabízí na výběr libovolné množství řádků s textem
scrollbar podobné widgetu scale s tím rozdílem, že zobrazuje posuvné šipky a naopak nezobrazuje přidruženou číselnou hodnotu
frame jeden z několika nabízených kontejnerů; tento má tvar obdélníka (může být také neviditelný nebo může mít 3D rámeček)
toplevel další z kontejnerů, tento se chová jako samostatné okno či dialog
bitmap bitmapa, tj. rastrový obrázek
photo/photoimage rastrový obrázek, jež může být načten z externího souboru v mnoha různých formátech
canvas widget, na který lze programově vkládat další grafické komponenty (úsečky, oblouky, kružnice, polyčáry, text atd.)

8. Vlastnosti widgetů

Ke každému widgetu je možné nastavit mnoho různých vlastností, které mění buď jeho vizuální vzhled na obrazovce počítače nebo jeho chování, tj. způsob reakce widgetu na akce uživatele. Mezi tyto akce počítáme například kliknutí tlačítkem myši, použití klávesových zkratek (hot keys), přesunutí widgetu atd. Některé vlastnosti jsou všem widgetům společné, další vlastnosti jsou však jedinečné pro jeden či pouze několik typů widgetů. Je to ostatně logické, některé widgety mají speciální chování. Vlastnosti lze nastavovat již při vytváření widgetů, na druhou stranu je také možné vlastnosti měnit až při běhu aplikace. Způsob nastavení vlastností si ukážeme na demonstračních příkladech. V následující tabulce jsou uvedeny vlastnosti, které jsou společné prakticky všem widgetům (kromě speciálních widgetů typu „položka menu“, které mají vlastnosti omezeny, stejně tak jako jejich reakce na uživatelovu činnost). Pozor! – při použití Ttk se nastavování vizuálních vlastností musí provádět přes styly, což si samozřejmě taktéž ukážeme:

Jméno vlastnosti Popis vlastnosti
background barva pozadí widgetu v případě, že widget není aktivní (vybraný)
foreground barva popředí widgetu (například zobrazeného textu) v případě, že widget není aktivní (vybraný)
borderwidth šířka okraje widgetu, která je zadaná v pixelech
activebackground barva pozadí widgetu v případě, že je widget vybrán (typicky kurzorem myši)
activeforeground barva popředí widgetu v případě, že je widget vybrán
disabledforeground barva popředí widgetu v případě, že je ovládání widgetu zakázáno
relief způsob prostorového zobrazení widgetu
compound způsob umístění bitmapy či obrázku na widgetu
bitmap bitmapa, která má být ve widgetu zobrazena
image obrázek, který má být ve widgetu zobrazen (více o bitmapách a obrázcích bude uvedeno v dalších dílech)
font jméno fontu, který je použit pro text uvnitř widgetu (font lze specifikovat platformově nezávislým způsobem)
text text, který má být ve widgetu (tlačítko, položka menu atd.) zobrazen
cursor jméno kurzoru myši, který bude použit v případě, že se kurzor nachází nad widgetem
textvariable jméno proměnné, která je nastavována podle uživatelových manipulací s widgetem (StringVar v Tkinteru)
justify zarovnání textu ve widgetu v případě, že se zobrazuje více řádků
anchor způsob umístění textu či obrázku ve widgetu

Vlastnosti se nastavují dvěma způsoby – u původních widgetů přímo nastavením vlastnosti (například background=„red“) u „themed Tk“ pak změnou takzvaných stylů, což je sice nepatrně složitější, ovšem mnohem flexibilnější způsob. V Pygubu se vlastnosti nastavují v příslušném dialogu:

Obrázek 15: Nastavení stylu widgetu přímo v prostředí Pygubu designeru.

9. „Odtrhávací“ menu

Jednou ze zajímavých vlastností menu poskytovaných knihovnou Tkinter je schopnost vytvořit taková rozbalovací menu, která lze „odtrhnout“ od pruhu s menu a začít je používat jako samostatné panely. To je potenciálně velmi užitečná vlastnost, protože uživateli dovoluje, aby byly nejčastěji používané příkazy stále viditelné a přitom umístěné přesně na tom místě, kde to uživateli vyhovuje (aplikace se tedy uživateli nesnaží vnutit jedno konkrétní rozvržení ovládacích prvků – resp. ne do takové míry, jak je to běžné jinde).

Obrázek 16: „Odtržená“ menu grafického editoru mtPaint.

Poznámka: podobný koncept ovšem nalezneme i u některých aplikací postavených na knihovnou GTK. Příkladem může být gvim, tj. varianta textového editoru Vim upravená do podoby aplikace s grafickým uživatelským rozhraním, popř. grafický editor mtPaint. Ovšem tyto aplikace jsou založeny na Gtk, přičemž v Gtk+ 3.4 byla tato možnost zakázána (mám vlastní teorii proč, ovšem ta se do dnešního článku nehodí).

Vytvoření „odtrhávacích“ menu je ve skutečnosti velmi snadné, protože se jedná o vlastnost menu, kterou je možné specifikovat přímo v Pygubu:

Obrázek 17: Nastavení vlastnosti „tearoff“ je platné vždy pro celé menu.

10. Realizace aplikace s „odtrhávacím“ menu

V praxi postačuje vlastnost tearoff nastavit na pravdivostní hodnotu true (skutečně je psána s malým počátečním písmenem) pouze u jediné položky hlavního menu, protože se jedná o globálně sdílený atribut. V praxi může vygenerovaný soubor s návrhem GUI aplikace vypadat následovně:

<?xml version='1.0' encoding='utf-8'?>
<interface>
  <object class="tk.Menu" id="MainMenu">
    <child>
      <object class="tk.Menuitem.Submenu" id="FileMenu">
        <property name="font">TkDefaultFont</property>
        <property name="label" translatable="yes">File</property>
        <property name="relief">raised</property>
        <property name="state">normal</property>
        <property name="tearoff">true</property>
        <property name="underline">0</property>
        <child>
          <object class="tk.Menuitem.Command" id="Command_New">
            <property name="command_#e tento mana#er
umo##uje vkládat komponenty do kontejneru (typicky do okna) tak, #e se zadává
jejich relativní umíst#ní (horizontální #i vertikální zarovnání)id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">document-new.png</property>
            <property name="label" translatable="yes">New</property>
            <property name="state">normal</property>
            <property name="underline">0</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Open">
            <property name="command_id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">document-open.png</property>
            <property name="label" translatable="yes">Open</property>
            <property name="underline">0</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Separator" id="Separator_1" />
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Quit">
            <property name="command">on_command_quit_selected</property>
            <property name="command_id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">application-exit.png</property>
            <property name="label" translatable="yes">Quit</property>
            <property name="underline">0</property>
          </object>
        </child>
      </object>
    </child>
    <child>
      <object class="tk.Menuitem.Submenu" id="EditMenu">
        <property name="label" translatable="yes">Edit</property>
        <property name="underline">0</property>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Cut">
            <property name="command_id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">edit-cut.png</property>
            <property name="label" translatable="yes">Cut</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Copy">
            <property name="command_id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">edit-copy.png</property>
            <property name="label" translatable="yes">Copy</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Paste">
            <property name="command_id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">edit-paste.png</property>
            <property name="label" translatable="yes">Paste</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Separator" id="Separator_2" />
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Delete">
            <property name="command_id_arg">false</property>
            <property name="compound">left</property>
            <property name="image">edit-delete.png</property>
            <property name="label" translatable="yes">Delete</property>
            <property name="state">disabled</property>
          </object>
        </child>
      </object>
    </child>
  </object>
  <object class="ttk.Frame" id="MainWindow">
    <property name="height">200</property>
    <property name="width">200</property>
    <layout>
      <property name="column">0</property>
      <property name="propagate">True</property>
      <property name="row">0</property>
    </layout>
    <child>
      <object class="ttk.Button" id="Button_Hello">
        <property name="command">on_button_clicked</property>
        <property name="compound">top</property>
        <property name="state">normal</property>
        <property name="text" translatable="yes">Quit</property>
        <property name="underline">0</property>
        <layout>
          <property name="column">0</property>
          <property name="propagate">True</property>
          <property name="row">0</property>
        </layout>
      </object>
    </child>
  </object>
</interface>

Vlastní zdrojový kód aplikace se přitom nijak nezmění, až na přejmenování třídy představující celou aplikaci:

"""Pygubu and Tkinter: main menu in main window, callback functions, tearoff menu (working example)."""
 
# Example4.py
 
import tkinter as tk
from tkinter import messagebox
import pygubu
 
 
class Example4App(pygubu.TkApplication):
    """Class representing a Tkinter based application."""
 
    def _create_ui(self):
        """Construct and initializes all UI-related data structures."""
        # step #1: Create a builder
        self.builder = builder = pygubu.Builder()
 
        # step #2: Load an ui file
        builder.add_from_file('example4.ui')
 
        # step #2B: Specify path to images and other resources
        builder.add_resource_path(".")
 
        # step #3: Create the mainwindow
        self.mainwindow = builder.get_object('MainWindow', self.master)
 
        # step #4: Set main menu
        self.mainmenu = menu = builder.get_object('MainMenu', self.master)
        self.set_menu(menu)
 
        # step $5: Configure callbacks
        builder.connect_callbacks(self)
 
    def on_button_clicked(self):
        """Define handler for Quit button."""
        tk.messagebox.showinfo('Message', 'You clicked on Quit button')
        root.destroy()
 
    def on_command_quit_selected(self):
        """Define handler for Quit command."""
        tk.messagebox.showinfo('Message', 'You selected Quit command')
        root.destroy()
 
 
if __name__ == '__main__':
    # needed to have a menu
    root = tk.Tk()
 
    # run the application
    app = Example4App(root)
    app.run()

Obrázek 18: „Odtržená“ menu v testovací aplikaci.

11. Klávesové zkratky navázané na jednotlivé položky menu

Poslední vlastnost menu, kterou si dnes popíšeme, je zobrazení a navázání klávesových akcelerátorů (například Ctrl+C) k určité položce menu.

Nastavení klávesových akcelerátorů (což je další typ horkých klíčů) se musí provést ve dvou krocích. Nejprve je nutné akcelerátor specifikovat u každé položky menu s využitím volby accelerator, například:

filemenu.add_command(label="Open", underline=0, accelerator="Ctrl+O",
                     command=lambda: print("Open"))

Knihovna Tkinter nás nijak neomezuje v tom, jaký text je u volby accelerator zapsán; samozřejmě je však vhodné, když popis souvisí se skutečně nastaveným akcelerátorem. Příklad si můžeme nepatrně upravit tak, že u každé položky (kde to má význam) uvedeme popis příslušné klávesové zkratky:

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
 
root = tkinter.Tk()
 
menubar = tkinter.Menu(root)
 
filemenu = tkinter.Menu(menubar, tearoff=0)
filemenu.add_command(label="Open", underline=0, accelerator="Ctrl+O",
                     command=lambda: print("Open"))
filemenu.add_command(label="Save", underline=0, accelerator="Ctrl+S",
                     command=lambda: print("Save"))
filemenu.add_separator()
filemenu.add_command(label="Exit", underline=1, accelerator="Ctrl+Q",
                     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, accelerator="Ctrl+U",
                     command=lambda: print("Undo"))
editmenu.add_separator()
editmenu.add_command(label="Cut", underline=2, accelerator="Ctrl+X",
                     command=lambda: print("Cut"))
editmenu.add_command(label="Copy", underline=0, accelerator="Ctrl+C",
                     command=lambda: print("Copy"))
editmenu.add_command(label="Paste", underline=0, accelerator="Ctrl+V",
                     command=lambda: print("Paste"))
editmenu.add_command(label="Delete", underline=2,
                     command=lambda: print("Delete"))
editmenu.add_separator()
editmenu.add_command(label="Select All", underline=7, accelerator="Ctrl+A",
                     command=lambda: print("Select All"))
menubar.add_cascade(label="Edit", menu=editmenu, underline=0)
 
helpmenu = tkinter.Menu(menubar, tearoff=0)
helpmenu.add_command(label="About", underline=0, accelerator="F1",
                     command=lambda: print("About"))
menubar.add_cascade(label="Help", menu=helpmenu, underline=0)
 
root.config(menu=menubar)
 
root.mainloop()

Obrázek 19: Screenshot demonstračního příkladu s klávesovými akcelerátory.

12. Realizace aplikace se specifikovanými klávesovými zkratkami

Z hlediska návrhu grafického uživatelského rozhraní aplikace je nastavení klávesových zkratek jednoduché – postačuje totiž zapsat klávesovou zkratku do políčka accelerator. Tento text nebude při spuštění dále upravován, takže je možné použít například národní variantu popisu kláves Ctrl, Alt atd.:

Obrázek 20: Nastavení klávesových zkratek, které se mají zobrazit u jednotlivých položek menu.

Při exportu návrhu GUI bude ve výsledném XML souboru s koncovkou .ui doplněna vlastnost accelerator:

<?xml version='1.0' encoding='utf-8'?>
<interface version="1.1">
  <object class="tk.Menu" id="MainMenu">
    <child>
      <object class="tk.Menuitem.Submenu" id="FileMenu">
        <property name="font">TkDefaultFont</property>
        <property name="label" translatable="yes">File</property>
        <property name="relief">raised</property>
        <property name="state">normal</property>
        <property name="tearoff">true</property>
        <property name="underline">0</property>
        <child>
          <object class="tk.Menuitem.Command" id="Command_New">
            <property name="accelerator">Ctrl+N</property>
            <property name="compound">left</property>
            <property name="image">document-new.png</property>
            <property name="label" translatable="yes">New</property>
            <property name="state">normal</property>
            <property name="underline">0</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Open">
            <property name="accelerator">Ctrl+O</property>
            <property name="compound">left</property>
            <property name="image">document-open.png</property>
            <property name="label" translatable="yes">Open</property>
            <property name="underline">0</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Separator" id="Separator_1" />
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Quit">
            <property name="accelerator">Ctrl+Q</property>
            <property args="" cbtype="simple" name="command" type="command">on_command_quit_selected</property>
            <property name="compound">left</property>
            <property name="image">application-exit.png</property>
            <property name="label" translatable="yes">Quit</property>
            <property name="underline">0</property>
          </object>
        </child>
      </object>
    </child>
    <child>
      <object class="tk.Menuitem.Submenu" id="EditMenu">
        <property name="label" translatable="yes">Edit</property>
        <property name="underline">0</property>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Cut">
            <property name="accelerator">Ctrl+X</property>
            <property name="compound">left</property>
            <property name="image">edit-cut.png</property>
            <property name="label" translatable="yes">Cut</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Copy">
            <property name="accelerator">Ctrl+C</property>
            <property name="compound">left</property>
            <property name="image">edit-copy.png</property>
            <property name="label" translatable="yes">Copy</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Paste">
            <property name="accelerator">Ctrl+P</property>
            <property name="compound">left</property>
            <property name="image">edit-paste.png</property>
            <property name="label" translatable="yes">Paste</property>
          </object>
        </child>
        <child>
          <object class="tk.Menuitem.Separator" id="Separator_2" />
        </child>
        <child>
          <object class="tk.Menuitem.Command" id="Command_Delete">
            <property name="accelerator">Delete</property>
            <property name="compound">left</property>
            <property name="image">edit-delete.png</property>
            <property name="label" translatable="yes">Delete</property>
            <property name="state">disabled</property>
          </object>
        </child>
      </object>
    </child>
  </object>
  <object class="ttk.Frame" id="MainWindow">
    <property name="height">200</property>
    <property name="width">200</property>
    <layout manager="grid">
      <property name="column">0</property>
      <property name="propagate">True</property>
      <property name="row">0</property>
    </layout>
    <child>
      <object class="ttk.Button" id="Button_Hello">
        <property args="" cbtype="simple" name="command" type="command">on_button_clicked</property>
        <property name="compound">top</property>
        <property name="state">normal</property>
        <property name="text" translatable="yes">Quit</property>
        <property name="underline">0</property>
        <layout manager="grid">
          <property name="column">0</property>
          <property name="propagate">True</property>
          <property name="row">0</property>
        </layout>
      </object>
    </child>
  </object>
</interface>

První varianta skriptu, který tento návrh GUI bude používat:

"""Pygubu and Tkinter: main menu in main window, callback functions, tearoff menu (working example)."""
 
# Example5.py
 
import tkinter as tk
from tkinter import messagebox
import pygubu
 
 
class Example5App(pygubu.TkApplication):
    """Class representing a Tkinter based application."""
 
    def _create_ui(self):
        """Construct and initializes all UI-related data structures."""
        # step #1: Create a builder
        self.builder = builder = pygubu.Builder()
 
        # step #2: Load an ui file
        builder.add_from_file('example5.ui')
 
        # step #2B: Specify path to images and other resources
        builder.add_resource_path(".")
 
        # step #3: Create the mainwindow
        self.mainwindow = builder.get_object('MainWindow', self.master)
 
        # step #4: Set main menu
        self.mainmenu = menu = builder.get_object('MainMenu', self.master)
        self.set_menu(menu)
 
        # step $5: Configure callbacks
        builder.connect_callbacks(self)
 
    def on_button_clicked(self):
        """Define handler for Quit button."""
        tk.messagebox.showinfo('Message', 'You clicked on Quit button')
        root.destroy()
 
    def on_command_quit_selected(self):
        """Define handler for Quit command."""
        tk.messagebox.showinfo('Message', 'You selected Quit command')
        root.destroy()
 
 
if __name__ == '__main__':
    # needed to have a menu
    root = tk.Tk()
 
    # run the application
    app = Example5App(root)
    app.run()

13. Registrace handleru události po stisku klávesové zkratky

Specifikace zkratky v návrhu menu však není dostačující, protože je ještě nutné akcelerátor na položku menu (resp. přesněji řečeno na nějaký příkaz) navázat. K tomu se používá nám již známý příkaz bind. Pro označení modifikátorů kláves se používají prefixy Control- a Meta-. Také si všimněte, že se rozlišují velikosti písmen stlačených kláves, takže je rozdíl mezi zápisem Control-x a Control-X (druhá možnost nemusí na některých systémech vůbec fungovat a i kdyby fungovala, není příliš často používaná):

root.bind('<Control-o>', lambda event: cmd_open())
root.bind('<Control-s>', lambda event: cmd_save())
root.bind('<Control-u>', lambda event: cmd_undo())
root.bind('<F1>', lambda event: cmd_help())
...
...
...
atd. i pro další položky menu

V našem konkrétním případě navážeme stisk klávesy Ctrl+Q s metodou on_command_quit_selected:

root.bind('<Control-q>', lambda event: self.on_command_quit_selected())

Modifikovaný zdrojový kód příkladu bude vypadat následovně:

"""Pygubu and Tkinter: main menu in main window, callback functions, tearoff menu (working example)."""
 
# Example5.py
 
import tkinter as tk
from tkinter import messagebox
import pygubu
 
 
class Example5App(pygubu.TkApplication):
    """Class representing a Tkinter based application."""
 
    def _create_ui(self):
        """Construct and initializes all UI-related data structures."""
        # step #1: Create a builder
        self.builder = builder = pygubu.Builder()
 
        # step #2: Load an ui file
        builder.add_from_file('example5.ui')
 
        # step #2B: Specify path to images and other resources
        builder.add_resource_path(".")
 
        # step #3: Create the mainwindow
        self.mainwindow = builder.get_object('MainWindow', self.master)
 
        # step #4: Set main menu
        self.mainmenu = menu = builder.get_object('MainMenu', self.master)
        self.set_menu(menu)
 
        # step $5: Configure callbacks
        builder.connect_callbacks(self)
 
        root.bind('<Control-q>', lambda event: self.on_command_quit_selected())
 
    def on_button_clicked(self):
        """Define handler for Quit button."""
        tk.messagebox.showinfo('Message', 'You clicked on Quit button')
        root.destroy()
 
    def on_command_quit_selected(self):
        """Define handler for Quit command."""
        tk.messagebox.showinfo('Message', 'You selected Quit command')
        root.destroy()
 
 
if __name__ == '__main__':
    # needed to have a menu
    root = tk.Tk()
 
    # run the application
    app = Example5App(root)
    app.run()

14. Změna tématu zobrazení za běhu aplikace

Téma je možné vybrat i změnit prakticky kdykoli za běhu programu, což skutečně funguje (například ve Swingu je to problematičtější). Podívejme se však na to, co se stane, když si pomocí čtyř tlačítek necháme přepínat čtyři základní témata „clam“, „alt“, „default“ a „classic“ a současně bude nastaven styl Red.TButton. Téma přepneme jednoduše zavoláním:

style.theme_use("jméno_tématu"))

kde style je objekt získaný konstruktorem:

style = ttk.Style()

Příklad změny tématu po stisku tlačítka:

button1 = ttk.Button(root, text="clam",
                     command=lambda: style.theme_use("clam"))

Úplný demonstrační příklad se změnou témat za běhu vypadá následovně (příklad je založen na Tkinteru):

#!/usr/bin/env python
 
import tkinter
from tkinter import ttk
 
import sys
 
 
def exit():
    sys.exit(0)
 
 
root = tkinter.Tk()
 
style = ttk.Style()
 
style.configure('Red.TButton', background='#ff8080')
 
button1 = ttk.Button(root, text="clam",
                     command=lambda: style.theme_use("clam"))
button2 = ttk.Button(root, text="alt",
                     command=lambda: style.theme_use("alt"))
button3 = ttk.Button(root, text="default",
                     command=lambda: style.theme_use("default"))
button4 = ttk.Button(root, text="classic",
                     command=lambda: style.theme_use("classic"))
 
quitButton = ttk.Button(root, text="Exit", style='Red.TButton',
                        command=exit)
 
button1.grid(column=1, row=1, sticky="we")
button2.grid(column=2, row=1, sticky="we")
button3.grid(column=1, row=2, sticky="we")
button4.grid(column=2, row=2, sticky="we")
 
quitButton.grid(column=2, row=5, sticky="we")
 
label = tkinter.Label(root, text='Hello world')
entry = tkinter.Entry(root)
checkbutton = tkinter.Checkbutton(text='Do you like Tkinter?')
 
checkbutton.grid(column=1, row=3, columnspan=2, sticky="w")
label.grid(column=1, row=4)
entry.grid(column=2, row=4)
 
root.mainloop()

Obrázek 21: Demonstrační příklad po výběru tématu „default“.

15. Návrh aplikace s podobným chováním v nástroji Pygubu

V nástroji Pygubu může návrh aplikace s podobným chováním, jako výše uvedená aplikace (naprogramovaná čistě v Tkinteru) vypadat následovně:

Obrázek 22: Návrh grafického uživatelského rozhraní aplikace v nástroji Pygubu.

Povšimněte si, že každému tlačítku je přiřazena nějaká metoda zavolaná ve chvíli, kdy je tlačítko vybráno uživatelem – viz zvýrazněné řádky:

<?xml version='1.0' encoding='utf-8'?>
<interface version="1.1">
  <object class="ttk.Frame" id="MainWindow">
    <property name="height">200</property>
    <property name="width">200</property>
    <layout manager="pack">
      <property name="propagate">True</property>
      <property name="side">top</property>
    </layout>
    <child>
      <object class="ttk.Button" id="clam">
        <property cbtype="simple" name="command" type="command">on_button_clam_click</property>
        <property name="text" translatable="yes">clam</property>
        <layout manager="grid">
          <property name="column">0</property>
          <property name="propagate">True</property>
          <property name="row">0</property>
          <property name="sticky">ew</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Button" id="alt">
        <property cbtype="simple" name="command" type="command">on_button_alt_click</property>
        <property name="text" translatable="yes">alt</property>
        <layout manager="grid">
          <property name="column">1</property>
          <property name="propagate">True</property>
          <property name="row">0</property>
          <property name="sticky">ew</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Button" id="default">
        <property cbtype="simple" name="command" type="command">on_button_default_click</property>
        <property name="text" translatable="yes">default</property>
        <layout manager="grid">
          <property name="column">0</property>
          <property name="propagate">True</property>
          <property name="row">1</property>
          <property name="sticky">ew</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Button" id="classic">
        <property cbtype="simple" name="command" type="command">on_button_classic_click</property>
        <property name="text" translatable="yes">classic</property>
        <layout manager="grid">
          <property name="column">1</property>
          <property name="propagate">True</property>
          <property name="row">1</property>
          <property name="sticky">ew</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Checkbutton" id="question">
        <property name="text" translatable="yes">Do you like Tkinter?</property>
        <layout manager="grid">
          <property name="column">0</property>
          <property name="propagate">True</property>
          <property name="row">2</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Label" id="hello_world_label">
        <property name="text" translatable="yes">Hello world</property>
        <layout manager="grid">
          <property name="column">0</property>
          <property name="propagate">True</property>
          <property name="row">3</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Entry" id="entry1">
        <layout manager="grid">
          <property name="column">1</property>
          <property name="propagate">True</property>
          <property name="row">3</property>
          <property name="sticky">ew</property>
        </layout>
      </object>
    </child>
    <child>
      <object class="ttk.Button" id="exit">
        <property cbtype="simple" name="command" type="command">on_button_exit_click</property>
        <property name="style">Red.TButton</property>
        <property name="text" translatable="yes">Exit</property>
        <layout manager="grid">
          <property name="column">1</property>
          <property name="propagate">True</property>
          <property name="row">4</property>
          <property name="sticky">ew</property>
        </layout>
      </object>
    </child>
  </object>
</interface>

16. Implementace handlerů zavolaných po stisku tlačítek na GUI

Handlery, tedy metody třídy Example6App, musí mít shodný název se jmény uvedenými v návrhu grafického uživatelského rozhraní. Jedná se skutečně o běžné metody, které akceptují parametr self (tedy referenci na instanci třídy) a volají metody objektu style, který je globálně viditelný (je vytvořen v bloku za definicí třídy):

"""Pygubu and Tkinter: changing style."""
 
# Example6.py
 
import tkinter as tk
from tkinter import ttk
import pygubu
 
 
class Example6App(pygubu.TkApplication):
    """Class representing a Tkinter based application."""
 
    def _create_ui(self):
        """Construct and initializes all UI-related data structures."""
        # step #1: Create a builder
        self.builder = builder = pygubu.Builder()
 
        # step #2: Load an ui file
        builder.add_from_file('example6.ui')
 
        # step #2B: Specify path to images and other resources
        builder.add_resource_path(".")
 
        # step #3: Create the mainwindow
        self.mainwindow = builder.get_object('MainWindow', self.master)
 
        # step $4: Configure callbacks
        builder.connect_callbacks(self)
 
        root.bind('<Control-q>', lambda event: self.on_button_exit_click())
 
    def on_button_clam_click(self):
        style.theme_use("clam")
 
    def on_button_alt_click(self):
        style.theme_use("alt")
 
    def on_button_default_click(self):
        style.theme_use("default")
 
    def on_button_classic_click(self):
        style.theme_use("classic")
 
    def on_button_exit_click(self):
        root.destroy()
 
 
if __name__ == '__main__':
    # needed to have a menu
    root = tk.Tk()
 
    # style
    style = ttk.Style()
 
    # run the application
    app = Example6App(root)
    app.run()

Obrázek 23: Výsledná aplikace po svém spuštění.

17. Standardní dialogová okna s otázkou (Ok/Cancel, Yes/No, Ok/Retry)

Knihovna Tkinter obsahuje i několik standardních dialogových oken, v nichž se po uživateli vyžaduje reagovat na položenou otázku, popř. na nějaký stav aplikace (nepodařený tisk atd.) stiskem jednoho z nabízených tlačítek. Tato dialogová okna jsou opět vyvolána funkcemi, které nalezneme v modulu tkinter.messagebox:

Funkce Ikona Zobrazená tlačítka
askokcancel() OK+Cancel
askretrycancel() Retry+Cancel
askyesno() Yes+No
askquestion() ve výchozím nastavení Yes+No

Obrázek 24: Dialog  otázkou vytvořený funkcí messagebox.askokcancel().

Tato dialogová okno v nástroji Pygubu nenalezneme, protože je nutné je v aplikaci zavolat programově.

18. Příklad zobrazující všechna čtyři standardní dialogová okna

Předchozí demonstrační příklad (s výběrem stylů) můžeme velmi snadno upravit takovým způsobem, aby byla čtyři tlačítka použita pro zobrazení standardních dialogových oken. Tlačítka přejmenujeme, změníme jejich text a taktéž jména callback funkcí (resp. přesněji řečeno metod):

Obrázek 24: Návrh GUI aplikace.

Samotný skript volá přímo výše zmíněné funkce pro zobrazení standardních dialogových oken (podtržená část kódu):

"""Pygubu and Tkinter: changing style."""
 
# Example7.py
 
import tkinter as tk
from tkinter import ttk
from tkinter import messagebox
import pygubu
 
 
class Example7App(pygubu.TkApplication):
    """Class representing a Tkinter based application."""
 
    def _create_ui(self):
        """Construct and initializes all UI-related data structures."""
        # step #1: Create a builder
        self.builder = builder = pygubu.Builder()
 
        # step #2: Load an ui file
        builder.add_from_file('example7.ui')
 
        # step #2B: Specify path to images and other resources
        builder.add_resource_path(".")
 
        # step #3: Create the mainwindow
        self.mainwindow = builder.get_object('MainWindow', self.master)
 
        # step $4: Configure callbacks
        builder.connect_callbacks(self)
 
        root.bind('<Control-q>', lambda event: self.on_button_exit_click())
 
    def on_button_ok_cancel_click(self):
        messagebox.askokcancel("askokcancel()", "askokcancel()")
 
    def on_button_yes_no_click(self):
        messagebox.askyesno("askyesno()", "askyesno()")
 
    def on_button_retry_cancel_click(self):
        messagebox.askretrycancel("askretrycancel()", "askretrycancel()")
 
    def on_button_question_click(self):
        messagebox.askquestion("askquestion()", "askquestion()")
 
    def on_button_exit_click(self):
        root.destroy()
 
 
if __name__ == '__main__':
    # needed to have a menu
    root = tk.Tk()
 
    # style
    style = ttk.Style()
 
    # run the application
    app = Example7App(root)
    app.run()

19. Repositář s demonstračními příklady

Zdrojové kódy všech minule i dnes popsaných demonstračních příkladů určených pro Python 3 a nejnovější stabilní verzi knihovny Pygubu (a pochopitelně i pro Pygubu designer) byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/most-popular-python-libs. V případě, že nebudete chtít klonovat celý repositář (ten je ovšem stále velmi malý, dnes má velikost zhruba několik desítek kilobajtů), můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

# Jméno souboru Stručný popis souboru Cesta
    Ovládací prvky vložené do hlavního okna aplikace  
1 example1.ui soubor s návrhem GUI prvního demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example1.ui
2 example1.py implementace prvního demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example1.py
       
    Menu, jehož jednotlivé položky obsahují i ikony  
3 example2.ui soubor s návrhem GUI druhého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example2.ui
4 example2A.py implementace třetího demonstračního příkladu (bez menu) https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example2A.py
5 example2B.py implementace třetího demonstračního příkladu (nespecifikován adresář s ikonami) https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example2B.py
6 example2C.py implementace třetího demonstračního příkladu (korektní varianta) https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example2C.py
       
    Menu, jehož položky volají zvolené metody  
7 example3.ui soubor s návrhem GUI třetího demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example3.ui
8 example3.py implementace třetího demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example3.py
       
    „Odtrhávací“ menu  
9 example4.ui soubor s návrhem GUI čtvrtého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example4.ui
10 example4.py implementace čtvrtého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example4.py
       
    Klávesové zkratky přiřazené položkám menu  
11 example5.ui soubor s návrhem GUI pátého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example5.ui
12 example5.py implementace pátého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example5.py
13 example5B.py implementace pátého demonstračního příkladu s reakcemi na stisk kláves https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example5B.py
       
    Změna tématu zobrazení za běhu aplikace  
14 example6.ui soubor s návrhem GUI šestého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example6.ui
15 example6.py implementace šestého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example6.py
       
    Standardní dialogová okna  
16 example7.ui soubor s návrhem GUI sedmého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example7.ui
17 example7.py implementace sedmého demonstračního příkladu https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/example7.py

Ve druhém a třetím demonstračním příkladu jsou navíc použity i ikony v menu. Tyto ikony jsou uloženy samostatně ve formátu PNG a měly by být umístěny do stejného adresáře, ze kterého se spouští aplikace:

# Jméno souboru Stručný popis souboru Cesta
1 application-exit.png ikona pro položku menu sloužící k ukončení aplikace https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/application-exit.png
2 document-new.png ikona pro položku menu File→New https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/document-new.png
3 document-open.png ikona pro položku menu File→Open https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/document-open.png
4 edit-copy.png ikona pro položku menu Edit→Copy https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/edit-copy.png
5 edit-cut.png ikona pro položku menu Edit→Cut https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/edit-cut.png
6 edit-paste.png ikona pro položku menu Edit→Paste https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/edit-paste.png
7 edit-delete.png ikona pro položku menu Edit→Delete https://github.com/tisnik/most-popular-python-libs/blob/master/pygubu/edit-delete.png

20. Odkazy na Internetu

  1. Seriál Grafické uživatelské rozhraní v Pythonu
    https://www.root.cz/serialy/graficke-uzivatelske-rozhrani-v-pythonu/
  2. Pygubu na PyPi
    https://pypi.org/project/pygubu/
  3. Repositář projektu Pygubu
    https://github.com/alejan­droautalan/pygubu
  4. pygubu-designer na PyPi
    https://pypi.org/project/pygubu-designer/
  5. Repositář projektu pygubu-designer
    https://github.com/alejan­droautalan/pygubu-designer
  6. Pygubu Wiki
    https://github.com/alejan­droautalan/pygubu/wiki
  7. How to install Tkinter in Python?
    https://www.tutorialspoint.com/how-to-install-tkinter-in-python
  8. Stránky projektu Glade
    https://glade.gnome.org/
  9. Hra Breakout napísaná v Tkinteri
    https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/
  10. Brython aneb použití jazyka Python ve skriptech přímo v prohlížeči
    https://www.root.cz/clanky/brython-aneb-pouziti-jazyka-python-ve-skriptech-primo-v-prohlizeci/
  11. The Hitchhiker's Guide to Pyhton: GUI Applications
    http://docs.python-guide.org/en/latest/scenarios/gui/
  12. 7 Top Python GUI Frameworks for 2017
    http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/
  13. GUI Programming in Python
    https://wiki.python.org/mo­in/GuiProgramming
  14. Cameron Laird's personal notes on Python GUIs
    http://phaseit.net/claird/com­p.lang.python/python_GUI.html
  15. Python GUI development
    http://pythoncentral.io/introduction-python-gui-development/
  16. Graphic User Interface FAQ
    https://docs.python.org/2/faq/gu­i.html#graphic-user-interface-faq
  17. TkInter
    https://wiki.python.org/moin/TkInter
  18. Tkinter 8.5 reference: a GUI for Python
    http://infohost.nmt.edu/tcc/hel­p/pubs/tkinter/web/index.html
  19. TkInter (Wikipedia)
    https://en.wikipedia.org/wiki/Tkinter
  20. Rapid application development
    https://en.wikipedia.org/wi­ki/Rapid_application_deve­lopment
  21. Non-functional requirement
    https://en.wikipedia.org/wiki/Non-functional_requirement
  22. Graphical user interface builder
    https://en.wikipedia.org/wi­ki/Graphical_user_interfa­ce_builder
  23. User interface markup language
    https://en.wikipedia.org/wi­ki/User_interface_markup_lan­guage
  24. Top 10 programming languages that developers hate the most
    https://www.techworm.net/2017/11/perl-hated-programming-language-developers-says-report.html

Autor článku

Pavel Tišnovský vystudoval VUT FIT a v současné době pracuje ve společnosti Red Hat, kde vyvíjí nástroje pro OpenShift.io.