Tvorba grafického uživatelského rozhraní v Pythonu: dokončení popisu widgetů v knihovně appJar

17. 10. 2017
Doba čtení: 21 minut

Sdílet

Ve třetím článku o knihovně appJar dokončíme popis widgetů, které tato knihovna nabízí. Bude se jednat o užitečné doplňkové widgety – posuvník, zobrazení průběhu činnosti, widget pro výběr data apod.

Obsah

1. Tvorba grafického uživatelského rozhraní v Pythonu: dokončení popisu widgetů v knihovně appJar

2. Horizontální posuvník (slider, scale)

3. Zobrazení hodnot na horizontální ose posuvníku

4. Zobrazení aktuálně vybrané hodnoty na posuvníku

5. Změna rozsahu hodnot, které lze posuvníkem vybrat

6. Vertikální posuvník

7. Callback funkce volaná při změně posuvníku

8. Widget zobrazující průběh činnosti (meter)

9. Změna hodnoty widgetu meter

10. Úprava barevného gradientu widgetu meter

11. Automatické sledování a zobrazení hodnot vybrané proměnné

12. Widget meter rozdělený na dva barevné gradienty

13. Úprava obou barevných gradientů rozděleného widgetu meter

14. Widget umožňující současné zobrazení dvou hodnot (dual meter)

15. Widget pro výběr data

16. Použití aktuálního data popř. explicitní určení odlišného data

17. Widget umožňující uchopení a přesun okna

18. Horizontální a vertikální oddělovač widgetů

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

20. Odkazy na Internetu

1. Tvorba grafického uživatelského rozhraní v Pythonu: dokončení popisu widgetů v knihovně appJar

V již třetím pokračování článku o tvorbě grafického uživatelského rozhraní v Pythonu s využitím knihovny appJar dokončíme popis většiny zbývajících ovládacích prvků (widgetů), z nichž je možné skládat složitější dialogy a formuláře (widgety pro vstup testu si popíšeme společně s formuláři). Pro připomenutí jsou v následující tabulce vypsány všechny základní widgety, které tato knihovna podporuje. Odkazy vedou na podrobnější popis každého widgetu:

Jméno widgetu Stručný popis
Label textové návěští neměnitelné uživatelem
Message několikařádkové textové návěští (viz Label)
   
Entry šest typů vstupních polí (základní + 5 speciálních)
TextArea několikařádkové vstupní pole
   
Button klasické „klikací“ tlačítko, existují však i další varianty (tlačítko s ikonou atd.)
RadioButton přepínací tlačítko, které je typicky sdružováno do větších skupin
CheckBox zaškrtávací tlačítko
Properties skupina zaškrtávacích tlačítek
OptionBox výběrové pole se seznamem voleb (drop-down box)
SpinBox výběrové pole s přetáčením voleb
ListBox seznam prvků s možností výběru jednoho prvku či skupiny prvků
   
Scale scrollovací prvek (horizontální a vertikální posuvník)
DatePicker výběr data
   
Link klikací odkaz
WebLink klikací odkaz
Grip ploška sloužící k přesunu okna/dialogu/toolbaru
   
Meter (pasivní) zobrazení průběhu výpočtu atd.
Separator (pasivní) horizontální či vertikální oddělení widgetů

2. Horizontální posuvník (slider, scale)

Prvním widgetem, který si dnes popíšeme, je horizontální posuvník. Většinou se tento ovládací prvek nazývá slider, ovšem v knihovně appJar zvolili název scale. Tento posuvník se v nejjednodušším případě vytváří metodou addScale popř. metodou addLabelScale. Druhá z těchto metod navíc zobrazí na levé straně widgetu i jeho název:

app.addScale("scale1")
app.addLabelScale("scale1")

Pro čtení aktuálně nastavené pozice posuvníku použijte metodu getScale:

value1 = app.getScale("scale1")
value2 = app.getScale("scale2")

Obrázek 1: Nejjednodušší forma horizontálního posuvníku, který implicitně umožňuje vybírat hodnoty od 1 do 100 (včetně obou mezí).

V dnešním prvním demonstračním příkladu se zobrazí jeden posuvník a jeho hodnota je vypsána do informačního dialogu po stisku tlačítka „Show scale value“:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addLabelScale("scale")
 
app.addButton("Show scale value", onButtonPress)
app.addButton("Quit", onButtonPress)
 
app.go()

Obrázek 2: Zobrazení aktuálně vybrané hodnoty na posuvníku.

3. Zobrazení hodnot na horizontální ose posuvníku

Posuvník z prvního příkladu ve skutečnosti nebyl nakonfigurován tak, aby byl uživatelsky přívětivý, protože nebylo zřejmé, jaký rozsah hodnot vlastně posuvník představuje. Tento problém lze velice snadno napravit, protože pod posuvníkem může být zobrazena osa s hodnotami. Tato osa se zapíná metodou showScaleValue, které se kromě jména posuvníku předá i interval mezi zobrazenými hodnotami. Musíte si pouze dát pozor na to, aby nebylo hodnot zobrazeno příliš mnoho, protože by se překrývaly (knihovna appJar tuto kontrolu za nás neudělá):

app.showScaleIntervals("scale", 20)

Obrázek 3: Posuvník, pod nímž je zobrazena osa s hodnotami.

V následujícím demonstračním příkladu je zajištěno, že se pod posuvníkem zobrazí i osa s hodnotami:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 20)
 
app.addButton("Show scale value", onButtonPress, 1, 0)
app.addButton("Quit", onButtonPress, 1, 1)
 
app.go()

4. Zobrazení aktuálně vybrané hodnoty na posuvníku

Uživatelskou přívětivost při použití posuvníku lze dále vylepšit tak, že nad jeho posuvnou částí zobrazíme aktuálně nastavenou hodnotu. Tato konfigurace je velmi snadná, protože pouze postačuje zavolat následující metodu, které se pouze předá jméno posuvníku:

app.showScaleValue("scale")

Alternativně lze použít i volání:

app.showScaleValue("scale", show=True)

Opětovný zákaz zobrazení aktuální hodnoty se provede voláním:

app.showScaleValue("scale", show=False)

Obrázek 4: Posuvník, nad nímž je zobrazena aktuálně vybraná hodnota. Současně se pod posuvníkem zobrazuje osa s hodnotami. Jedná se o největší množství informací, které tento widget dokáže v dané chvíli poskytnout.

Podívejme se nyní na demonstrační příklad, v němž je zobrazen posuvník jak s osou hodnot, tak i s aktuálně vybranou hodnotou:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 20)
app.showScaleValue("scale")
 
app.addButton("Show scale value", onButtonPress, 1, 0)
app.addButton("Quit", onButtonPress, 1, 1)
 
app.go()

5. Změna rozsahu hodnot, které lze posuvníkem vybrat

Ve druhé kapitole jsme si řekli, že posuvníkem je možné vybírat hodnoty z rozsahu 1 až 100. Samozřejmě se nejedná o jediný možný rozsah, který by bylo nutné programově přepočítávat na rozsah požadovaný zpracovávanou úlohou. Pomocí metody setScaleRange je totiž možné specifikovat vlastní dolní i horní mez hodnot vrácených posuvníkem (ovšem na obrazovce se posuvník vždy bude pohybovat od levého dorazu do dorazu pravého):

app.setScaleRange("scale", dolní_mez, horní_mez)

popř. je možné nastavit aktuální hodnotu:

app.setScaleRange("scale", dolní_mez, horní_mez, aktuální_hodnota)

Obrázek 5: Posuvník umožňující vybírat hodnoty z rozsahu 50 až 150 (včetně obou mezí).

Opět si ukažme demonstrační příklad, v němž nakonfigurujeme možnosti posuvníku:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleRange("scale", 50, 150, 100)
 
app.addButton("Show scale value", onButtonPress, 1, 0)
app.addButton("Quit", onButtonPress, 1, 1)
 
app.go()

6. Vertikální posuvník

Metodou setScaleVertical lze vytvořit vertikální posuvník, který je zobrazen na šestém obrázku. Při použití vertikálního posuvníku si musíte dát pozor na to, aby se zbytečně „nenatáhly“ ostatní widgety umístěné vedle posuvníku popř. aby nebyl posuvník příliš nízký. Řešení poskytuje metoda setPadding a roztažení posuvníku přes několik řádků:

app.setScaleVertical("scale")

Obrázek 6: Vertikální posuvník zobrazený na dialogu.

Další příklad po svém spuštění zobrazí vertikální posuvník umístěný v levé části dialogu. Posuvník zabere všechny tři řádky pomyslné mřížky:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 10)
 
app.addLabelScale("scale", rowspan=3)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleRange("scale", 50, 150, 100)
app.setScaleVertical("scale")
 
app.addButton("Show scale value", onButtonPress, 0, 1)
app.addLabel("", "", 1, 1)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

7. Callback funkce volaná při změně posuvníku

Ve chvíli, kdy uživatel změní pozici posuvníku, může dojít k automatickému zavolání callback funkce, které se v jediném parametru předá jméno widgetu (posuvníku), kterého se tato událost týká. Registraci takové callback funkce provedeme velmi snadno:

app.setScaleChangeFunction(jméno_posuvníku, scaleCallback)

Samotná callback funkce může vypadat například takto:

def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))

Obrázek 7: Po změně pozice posuvníku se automaticky změní titulek okna.

Podívejme se nyní na demonstrační příklad, který dokáže změnit titulek okna po změně pozice posuvníku:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleChangeFunction("scale", scaleCallback)
app.setScaleRange("scale", 50, 150, 100)
 
app.addButton("Show scale value", onButtonPress, 1, 0)
app.addButton("Quit", onButtonPress, 1, 1)
 
app.go()

8. Widget zobrazující průběh činnosti (meter)

Většina ovládacích prvků, s nimiž jsme se doposud seznámili, dokáže aktivně reagovat na akce prováděné uživatelem (klik, drag and drop atd.). Ovšem widget nazvaný meter je vlastně z tohoto pohledu pasivní, protože nijak nereaguje na přímé uživatelovy akce. Tento ovládací prvek je totiž určený na zobrazení průběhu nějaké činnosti, takže se v jiných grafických knihovnách jmenuje progress bar apod. (ostatně i z tohoto důvodu jsou hodnoty zobrazené v rozsahu 0% až 100%). V knihovně appJar se widget meter v tom nejjednodušším případě vytváří takto:

app.addMeter("progressBar")

popř. s udáním pozice prvku v rámci neviditelné mřížky (grid):

app.addMeter("progressBar", 2, 3)

Obrázek 8: Nejjednodušší podoba widgetu, který umožňuje zobrazit průběh nějaké činnosti. Povšimněte si, že tento widget zobrazuje hodnoty v procentech.

Podívejme se nyní na způsob přidání tohoto widgetu do našeho demonstračního příkladu. Je to velmi snadné:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addMeter("progressBar", 1, 0)
app.addButton("Quit", onButtonPress, 1, 1)
 
app.go()

9. Změna hodnoty widgetu meter

Widget typu meter můžeme použít dvěma způsoby:

  1. Hodnotu zobrazenou tímto widgetem (0% až 100%) budeme nastavovat explicitně v programu. V tomto případě se použije metodaapp.setMeter().
  2. Necháme widget, aby sám sledoval zvolenou proměnnou a aktualizoval svoji hodnotu automaticky. Aby vše fungovalo, musíme zaregistrovat událost pomocíapp.registerEvent(vhod­ná_callback_funkce).

Nejdříve si ukážeme první způsob, tj. explicitní nastavení hodnoty zobrazované widgetem. Hodnotu budeme získávat z posuvníku:

def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))
    app.setMeter("progressBar", value)

Obrázek 9: Nastavení hodnoty widgetu meter na 42%

Úplný zdrojový kód příkladu vypadá následovně:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))
    app.setMeter("progressBar", value)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addMeter("progressBar", 0, 0, colspan=2)
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleChangeFunction("scale", scaleCallback)
app.setScaleRange("scale", 0, 100, 50)
 
app.addButton("Show scale value", onButtonPress, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

10. Úprava barevného gradientu widgetu meter

V případě, že vám nevyhovuje výchozí barevný gradient použitý ve widgetu meter, není žádný problém ho změnit. Použijte přitom metodu nazvanou setMeterFill, které se ve druhém parametru předá barva ve formě řetězce:

app.setMeterFill("progressBar", "green")

popř. je možné barvu specifikovat i „hexa-trojicí“ používanou i v HTML a CSS:

app.setMeterFill("progressBar", "#aabbcc")

Obrázek 10: Výchozí barevný gradient widgetu meter.

Obrázek 11: Změna gradientu na škálu zeleného odstínu.

Opět si ukažme zařazení výše uvedeného kódu do demonstračního příkladu:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))
    app.setMeter("progressBar", value)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addMeter("progressBar", 0, 0, colspan=2)
app.setMeterFill("progressBar", "green")
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleChangeFunction("scale", scaleCallback)
app.setScaleRange("scale", 0, 100, 50)
 
app.addButton("Show scale value", onButtonPress, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

11. Automatické sledování a zobrazení hodnot vybrané proměnné

Ovládací prvek meter dokáže automaticky sledovat a zobrazit hodnotu vybrané proměnné (ideálně ve chvíli, kdy tato hodnota leží v rozsahu 0 až 100). Aby toto sledování pracovalo korektně, je nutné vytvořit „univerzální“ callback funkci zavolanou ve chvíli, kdy je nutné změnit hodnoty zobrazené v GUI. V této callback funkci přečteme proměnnou meterValue (což je jen příklad) a změníme hodnotu zobrazovanou widgetem meter:

def updateMeter():
    app.setMeter("progressBar", meterValue)

Tuto univerzální callback funkci dále zaregistrujeme:

app.registerEvent(updateMeter)

Pokud si spustíte další demonstrační příklad, můžete posuvníkem měnit hodnotu zobrazenou widgetem meter. Povšimněte si zpoždění mezi změnou posuvníku a zobrazením hodnoty. Toto zpoždění je způsobeno tím, že se callback funkce nevolá příliš často:

#!/usr/bin/env python
 
from appJar import gui
 
meterValue = 50
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    global meterValue
    meterValue = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=meterValue))
 
 
def updateMeter():
    app.setMeter("progressBar", meterValue)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addMeter("progressBar", 0, 0, colspan=2)
app.setMeterFill("progressBar", "green")
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleChangeFunction("scale", scaleCallback)
app.setScaleRange("scale", 0, 100, meterValue)
 
app.registerEvent(updateMeter)
 
app.addButton("Show scale value", onButtonPress, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

12. Widget meter rozdělený na dva barevné gradienty

Pokud ovládací prvek meter vytvoříme metodou addSplitMeter:

app.addSplitMeter("progressBar")

a nikoli metodou addMeter:

app.addMeter("progressBar")

bude tento widget zobrazený takovým způsobem, jaký je naznačený na dalším screenshotu:

Obrázek 12: Widget meter rozdělený na dva barevné gradienty.

Funkce tohoto widgetu však zůstane zachována, o čemž se můžeme snadno přesvědčit spuštěním dalšího příkladu:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))
    app.setMeter("progressBar", value)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addSplitMeter("progressBar", 0, 0, colspan=2)
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleChangeFunction("scale", scaleCallback)
app.setScaleRange("scale", 0, 100, 50)
 
app.addButton("Show scale value", onButtonPress, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

13. Úprava obou barevných gradientů rozděleného widgetu meter

Ve chvíli, kdy použijeme widget meter rozdělený na dva barevné gradienty, již není možné barvu tohoto ovládacího prvku nastavit způsobem, který jsme si popsali v desáté kapitole, tj. voláním:

app.setMeterFill("progressBar", "green")

Namísto toho je nutné předat metodě setMeterFill dvě barvy, a to s využitím n-tice nebo seznamu:

app.setMeterFill("progressBar", ["green", "yellow"])

Obrázek 13: Explicitní nastavení dvou barevných gradientů.

Úprava zdrojového kódu příkladu je v tomto případě triviální:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scale: {s}".format(s=app.getScale("scale"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value = app.getScale(widgetName)
    app.setTitle("Scale: {v}".format(v=value))
    app.setMeter("progressBar", value)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addSplitMeter("progressBar", 0, 0, colspan=2)
app.setMeterFill("progressBar", ["green", "yellow"])
 
app.addLabelScale("scale", colspan=2)
app.showScaleIntervals("scale", 25)
app.showScaleValue("scale")
app.setScaleChangeFunction("scale", scaleCallback)
app.setScaleRange("scale", 0, 100, 50)
 
app.addButton("Show scale value", onButtonPress, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

14. Widget umožňující současné zobrazení dvou hodnot (dual meter)

Další varianta widgetu meter spočívá v tom, že tento widget zobrazí dvě na sobě nezávislé hodnoty. Nejdříve se podívejme na screenshot, z něhož je patrné, jak takové zobrazení vypadá:

Obrázek 14: Widget meter zobrazující dvě hodnoty, jednu nalevo a druhou napravo od společného počátku.

Tuto variantu widgetu vytvoříme následovně:

app.addDualMeter("progressBar", 0, 0, colspan=2)

Nastavíme barvu obou částí:

app.setMeterFill("progressBar", ["yellow", "red"])

A pozici (hodnoty) obou částí, opět s využitím n-tice nebo seznamu:

def scaleCallback(widgetName):
    value1 = app.getScale("scale1")
    value2 = app.getScale("scale2")
    app.setMeter("progressBar", [value1, value2])

Následuje zdrojový kód příkladu, v němž je takto upravený widget použit:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scales:\n{s1}\n{s2}".format(
            s1=app.getScale("scale1"),
            s2=app.getScale("scale2"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value1 = app.getScale("scale1")
    value2 = app.getScale("scale2")
    app.setMeter("progressBar", [value1, value2])
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addDualMeter("progressBar", 0, 0, colspan=2)
app.setMeterFill("progressBar", ["yellow", "red"])
 
app.addLabelScale("scale1", colspan=2)
app.showScaleIntervals("scale1", 25)
app.showScaleValue("scale1")
 
app.addLabelScale("scale2", colspan=2)
app.showScaleIntervals("scale2", 25)
app.showScaleValue("scale2")
 
app.setScaleChangeFunction("scale1", scaleCallback)
app.setScaleChangeFunction("scale2", scaleCallback)
 
app.setScaleRange("scale1", 0, 100, 50)
app.setScaleRange("scale2", 0, 100, 50)
 
app.addButton("Show scale value", onButtonPress, 3, 0)
app.addButton("Quit", onButtonPress, 3, 1)
 
app.go()

15. Widget pro výběr data

Další widget, s nímž se dnes seznámíme, vlastně spojuje tři listboxy určené pro výběr data. Nejedná se tedy o plnohodnotný kalendář (což je zajisté škoda), ovšem i přesto může mít tento ovládací prvek své využití, protože automaticky hlídá počet dnů v měsíci, a to i pro přestupné roky. Podívejme se nejdříve na to, jak je tento widget zobrazen na Linuxu:

Obrázek 15: Widget pro výběr data se skládá ze tří listboxů (a nevypadá tedy příliš uživatelsky přívětivě).

Tento widget se vytvoří voláním:

app.addDatePicker("datePicker")

Pro jistotu ještě přidejte předpokládaný rozsah roků, které bude možné vybrat:

app.setDatePickerRange("datePicker", 2000, 2017)

Vybrané datum se získá voláním:

getDatePicker("datePicker")

Podívejme se nyní na příklad, v němž je tento widget použitý:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
 
 
def showDate(btn):
    msg = "Selected date: {d}".format(d=app.getDatePicker("datePicker"))
    app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addDatePicker("datePicker")
app.setDatePickerRange("datePicker", 2000, 2017)
 
app.addButton("Show selected date", showDate, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

Obrázek 16: Zobrazení vybraného data.

16. Použití aktuálního data popř. explicitní určení odlišného data

Widget date picker je možné „donutit“ k zobrazení aktuálního data po zavolání metody setDatePicker, které se předá pouze jméno widgetu a žádný další parametr:

app.setDatePicker("datePicker")

Pokud naopak potřebujete vybrat jiné explicitně zadané datum, použijte volání:

setDatePicker(title, date="yyyy-mm-dd)

Obrázek 17: Nastavení aktuálního data (ve chvíli přípravy článku).

Podívejme se nyní na příklad, jenž po svém spuštění zobrazí aktuální datum:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
 
 
def showDate(btn):
    msg = "Selected date: {d}".format(d=app.getDatePicker("datePicker"))
    app.infoBox("Show scale:", msg)
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addDatePicker("datePicker")
app.setDatePickerRange("datePicker", 2000, 2018)
 
# toto volani musi byt umisteno za predchozi prikaz!
app.setDatePicker("datePicker")
 
app.addButton("Show selected date", showDate, 2, 0)
app.addButton("Quit", onButtonPress, 2, 1)
 
app.go()

17. Widget umožňující uchopení a přesun okna

Předposlední widget, který si dnes popíšeme, umožňuje uchopení a přesun okna; není tedy nutné používat část okna s titulkem. Tento widget se vytvoří velmi jednoduše:

app.addGrip()

Obrázek 18: Widget umožňující uchopení a přesun okna.

Chování tohoto widgetu si můžeme sami jednoduše odzkoušet, ovšem jeho reálné použití může být problematické, protože tento ovládací prvek uživatelé pravděpodobně nebudou znát:

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addLabel("topLabel", "\u25bc", 0, 1)
app.addLabel("leftLabel", "grip \u25b6", 1, 0)
app.addLabel("rightLabel", "\u25c0 grip", 1, 2)
app.addLabel("bottomLabel", "\u25b2", 2, 1)
app.addGrip(1, 1)
 
app.addButton("Quit", onButtonPress, 4, 1)
 
app.go()

18. Horizontální a vertikální oddělovač widgetů

Do dialogů lze vložit horizontální a vertikální oddělovače, což je ostatně patrné při pohledu na další screenshot:

Obrázek 18: Horizontální a vertikální oddělovače widgetů.

Tyto oddělovače se vytváří metodami:

app.addHorizontalSeparator(y, x, colspan=2, colour="blue")
 
app.addVerticalSeparator(y, x, rowspan=6)

Z příkladů volání je patrné, že se oddělovače pozicují stejně, jako všechny ostatní widgety:

bitcoin školení listopad 24

#!/usr/bin/env python
 
from appJar import gui
 
 
def onButtonPress(buttonName):
    if buttonName == "Quit":
        app.stop()
    else:
        msg = "Your choice of scales:\n{s1}\n{s2}".format(
            s1=app.getScale("scale1"),
            s2=app.getScale("scale2"))
        app.infoBox("Show scale:", msg)
 
 
def scaleCallback(widgetName):
    value1 = app.getScale("scale1")
    value2 = app.getScale("scale2")
    app.setMeter("progressBar", [value1, value2])
 
 
app = gui()
 
app.setSticky("news")
app.setPadding(10, 2)
 
app.addDualMeter("progressBar", 0, 1, colspan=2)
app.setMeterFill("progressBar", ["yellow", "red"])
 
app.addHorizontalSeparator(1, 1, colspan=2, colour="blue")
 
app.addVerticalSeparator(0, 0, rowspan=6)
app.addVerticalSeparator(0, 3, rowspan=6)
 
app.addLabelScale("scale1", 2, 1, colspan=2)
app.showScaleIntervals("scale1", 25)
app.showScaleValue("scale1")
 
app.addLabelScale("scale2", 3, 1, colspan=2)
app.showScaleIntervals("scale2", 25)
app.showScaleValue("scale2")
 
app.addHorizontalSeparator(4, 1, colspan=2, colour="green")
 
app.setScaleChangeFunction("scale1", scaleCallback)
app.setScaleChangeFunction("scale2", scaleCallback)
 
app.setScaleRange("scale1", 0, 100, 50)
app.setScaleRange("scale2", 0, 100, 50)
 
app.addButton("Show scale value", onButtonPress, 5, 1)
app.addButton("Quit", onButtonPress, 5, 2)
 
app.go()

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

Zdrojové kódy všech sedmnácti dnes popsaných demonstračních příkladů naleznete pod následujícími odkazy:

Příklad Adresa
24_scale.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/24_scale.py
25_scale_show_intervals.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/25_scale_show_in­tervals.py
26_scale_show_value.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/26_scale_show_va­lue.py
27_scale_range.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/27_scale_ran­ge.py
28_vertical_scale.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/28_vertical_sca­le.py
29_scale_function.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/29_scale_fun­ction.py
30_meter.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/30_meter.py
31_active_meter.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/31_active_me­ter.py
32_meter_fill.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/32_meter_fi­ll.py
33_meter_update.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/33_meter_up­date.py
34_split_meter.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/34_split_me­ter.py
35_split_meter_color.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/35_split_me­ter_color.py
36_dual_meter.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/36_dual_me­ter.py
37_date_picker.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/37_date_pic­ker.py
38_set_date_picker.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/38_set_date_pic­ker.py
39_grip.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/39_grip.py
40_separator.py https://github.com/tisnik/pre­sentations/blob/master/Pyt­hon_GUI/appJar/40_separator­.py

Poznámka: pro úspěšné spuštění těchto příkladů musíte mít v aktuálním adresáři rozbalenou knihovnu appJar!. Podrobnosti jsme si řekli v úvodním článku.

20. Odkazy na Internetu

  1. Hra Breakout napísaná v Tkinteri
    https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/
  2. Hra Snake naprogramovaná v Pythone s pomocou Tkinter
    https://www.root.cz/clanky/hra-snake-naprogramovana-v-pythone-s-pomocou-tkinter/
  3. TkDND
    http://freecode.com/projects/tkdnd
  4. Python Tkinter Fonts
    https://www.tutorialspoin­t.com/python/tk_fonts.htm
  5. The Tkinter Canvas Widget
    http://effbot.org/tkinter­book/canvas.htm
  6. Ovládací prvek (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Ovl%C3%A1dac%C3%AD_prvek_­%28po%C4%8D%C3%ADta%C4%8D%29
  7. Rezervovaná klíčová slova v Pythonu
    https://docs.python.org/3/re­ference/lexical_analysis.html#ke­ywords
  8. TkDocs: Styles and Themes
    http://www.tkdocs.com/tuto­rial/styles.html
  9. Drawing in Tkinter
    http://zetcode.com/gui/tkin­ter/drawing/
  10. Changing ttk widget text color (StackOverflow)
    https://stackoverflow.com/qu­estions/16240477/changing-ttk-widget-text-color
  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. appJar
    http://appjar.info/
  21. appJar (Wikipedia)
    https://en.wikipedia.org/wiki/AppJar
  22. appJar na Pythonhosted
    http://pythonhosted.org/appJar/
  23. appJar widgets
    http://appjar.info/pythonWidgets/
  24. Stránky projektu PyGTK
    http://www.pygtk.org/
  25. PyGTK (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  26. Stránky projektu PyGObject
    https://wiki.gnome.org/Pro­jects/PyGObject
  27. Stránky projektu Kivy
    https://kivy.org/#home
  28. Stránky projektu PyQt
    https://riverbankcomputin­g.com/software/pyqt/intro
  29. PyQt (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  30. Stránky projektu PySide
    https://wiki.qt.io/PySide
  31. PySide (Wikipedia)
    https://en.wikipedia.org/wiki/PySide
  32. Stránky projektu Kivy
    https://kivy.org/#home
  33. Kivy (framework, Wikipedia)
    https://en.wikipedia.org/wi­ki/Kivy_(framework)
  34. QML Applications
    http://doc.qt.io/qt-5/qmlapplications.html
  35. KDE
    https://www.kde.org/
  36. Qt
    https://www.qt.io/
  37. GNOME
    https://en.wikipedia.org/wiki/GNOME
  38. Category:Software that uses PyGTK
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGTK
  39. Category:Software that uses PyGObject
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGObject
  40. Category:Software that uses wxWidgets
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_wxWidgets
  41. GIO
    https://developer.gnome.or­g/gio/stable/
  42. GStreamer
    https://gstreamer.freedesktop.org/
  43. GStreamer (Wikipedia)
    https://en.wikipedia.org/wi­ki/GStreamer
  44. Wax Gui Toolkit
    https://wiki.python.org/moin/Wax
  45. Python Imaging Library (PIL)
    http://infohost.nmt.edu/tcc/hel­p/pubs/pil/
  46. 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/

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.