Obsah
1. Přepínací tlačítka (radio buttons)
2. Chování jediného přepínacího tlačítka v okně/dialogu
4. Použití přepínacích tlačítek, které nejsou sdruženy do jediné skupiny
6. Vypnutí režimu automatického sdružování přepínacích tlačítek do jedné skupiny
8. Vytvoření explicitních skupin přepínacích tlačítek
9. Čtvrtý demonstrační příklad
10. Použití klávesových zkratek namísto myši při přístupu ke standardním widgetům
12. Explicitní klávesové zkratky (Ctrl+?, Shift+?, Alt+?)
13. Šestý demonstrační příklad
14. Třída QMainWindow a její odlišnosti od QWidget
16. Přidání tlačítka do centrální části hlavního okna
17. Lepší přístup – odvození vlastního widgetu pro centrální část hlavního okna
18. Složitější layout komponent, stavový řádek a další vylepšení
19. Repositář s demonstračními příklady
1. Přepínací tlačítka (radio buttons)
Minule jsme si popsali způsob práce se standardními tlačítky představovanými třídou QPushButton (popř. jejími potomky) a taktéž se zaškrtávacími tlačítky, které jsou v knihovně PySide představována třídou QCheckBox. Připomeňme si jen, že zaškrtávací tlačítka mohou být použita pro výběr ze dvou či ze tří stavů a že je možné je spojovat do skupin, v nichž je možné zaškrtnout pouze jediné tlačítko. A právě přes tuto vlastnost se dostáváme ke třetí variantě tlačítka. Touto variantou je přepínač neboli radio button. Jedná se o zcela běžný prvek grafických uživatelských rozhraní, který se používá především ve chvíli, kdy je nutné zajistit, aby byl vybrán jen jediný prvek z dané množiny n prvků. Množina voleb by jen měla být dostatečně malá a ideálně předem známá, jinak je výhodnější použít widget typu seznam.

Obrázek 1: Se skupinami přepínacích tlačítek jsme se již setkali při popisu možností knihovny Tkinter.
V knihovně PySide jsou přepínací tlačítka představována instancemi tříd typu QRadioButton. Předkem této třídy je QAbstractButton, podobně jako u všech dalších typů tlačítek.

Obrázek 2: Hierarchie widgetů odvozených obecného ovládacího prvku QWidget.
2. Chování jediného přepínacího tlačítka v okně/dialogu
Přepínací tlačítka se typicky a v naprosté většině případů spojují do skupin, ovšem v extrémním případě může skupina obsahovat jen jediné tlačítko. Zajímavé je, že při použití jediného přepínacího tlačítka se různé toolkity (knihovny a frameworky pro tvorbu grafického uživatelského rozhraní) chovají odlišně. Nejprve si ukažme chování standardního Pythonovského GUI toolkitu, tedy knihovny Tkinter. Aplikace s oknem, v němž je (kromě dalších ovládacích prvků) jen jediné přepínací tlačítko, vypadá následovně:
#!/usr/bin/env python import tkinter import sys def print_state(): print(radio_var.get()) root = tkinter.Tk() radio_var = tkinter.StringVar() radio1 = tkinter.Radiobutton(root, variable=radio_var, value="Radio button", text="Radio button") testButton = tkinter.Button(root, text="Print state", command=print_state) quitButton = tkinter.Button(root, text="Quit", command=exit) radio1.grid(column=1, row=1) testButton.grid(column=1, row=2, sticky="we", padx=6, pady=6) quitButton.grid(column=1, row=3, sticky="we", padx=6, pady=6) root.mainloop()
Po spuštění této aplikace se zobrazí toto okno:

Obrázek 3: Okno s jediným přepínacím tlačítkem po spuštění aplikace naprogramované s využitím knihovny Tkinter.
Přepínací tlačítko je samozřejmě možné vybrat (nebude již zašedlé), ale výběr již nelze zrušit (pokud samozřejmě nenaprogramujeme odlišné chování):
Obrázek 4: Přepínací tlačítko je sice možné vybrat, ale již ne „odvybrat“.
V knihovně PySide je chování aplikace (resp. přesněji řečeno okna či dialogu) s jediným přepínacím tlačítkem odlišné, protože se tento widget začne chovat jako běžné zaškrtávací tlačítko. Vzhled je ovšem samozřejmě odlišný:

Obrázek 5: Aplikace naprogramovaná v PySide; výchozí stav.

Obrázek 6: Přepínací tlačítko je možné vybrat…

Obrázek 7: …a výběr lze také zrušit.
V knihovně PySide se přepínací tlačítko vytvoří velmi jednoduše; postačuje totiž zavolat konstruktor třídy QRadioButton a předat mu text, který má být na tlačítku zobrazen (i když to tak vizuálně nevypadá, zahrnuje aktivní plocha tlačítka i celý text, nejenom vlastní přepínací „kolečko“):
testRadioButton = QtGui.QRadioButton("radio button")
Kdykoli později můžeme otestovat, jestli je dané tlačítko vybráno, zavoláním metody isChecked, která vrací pravdivostní (booleovskou) hodnotu:
testRadioButton.isChecked()
Kromě toho je možné pracovat se všemi čtyřmi signály:
Jméno signálu | Význam |
---|---|
clicked | vyslán po stisku a puštění tlačítka |
pressed | vyslán ve chvíli, kdy došlo ke stlačení |
released | vyslán ve chvíli, kdy došlo k puštění tlačítka |
toggled | vyslán po změně stavu tlačítka (zapnuto/vypnuto) |
3. První demonstrační příklad
Podívejme se nyní na způsob implementace jednoduché aplikace, po jejímž spuštění se zobrazí okno obsahující trojici aktivních ovládacích prvků – přepínacího tlačítka, běžného tlačítka pro zjištění stavu aplikace a dalšího běžného tlačítka sloužícího k ukončení běhu aplikace. Vzhledem k jednoduchosti GUI aplikace použijeme pro rozmístění komponent obyčejný QVBoxLayout. Logika pro zjištění stavu přepínacího tlačítka je připravena na situaci, kdy do okna přidáme další ovládací prvky:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("Single radio button") # testovací přepínací tlačítko self.testRadioButton = QtGui.QRadioButton("radio button") # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit") # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.testRadioButton) layout.addWidget(testButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # po stisku testovacího tlačítka se zavolá metoda testButton.clicked.connect(self.printState) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def printState(self): print("-" * 50) MainWindow.printStateForRadioButton("radio button", self.testRadioButton) @staticmethod def printStateForRadioButton(name, radioButton): state = "checked" if radioButton.isChecked() else "unchecked" print("Radio button {name} is {state}".format(name=name, state=state)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
4. Použití přepínacích tlačítek, které nejsou sdruženy do jediné skupiny
Jediné přepínací tlačítko se samozřejmě většinou nepoužívá; setkáme se spíše se skupinou dvou až (přibližně) deseti tlačítek. Pokud tato tlačítka přímo vložíme do okna aplikace, bude jejich chování záviset na nastavení vlastnosti autoExclusive. Implicitně je tato vlastnost u přepínacích tlačítek nastavena, takže je možné vybrat maximálně jediné tlačítko ze skupiny (nemusí být ovšem vybráno žádné tlačítko). Skupinu ve skutečnosti není zapotřebí explicitně nastavovat – pokud to totiž neuděláme, budou tlačítka sdružena do skupin podle toho widgetu, na jehož plochu jsou umístěna. A vzhledem k tomu, že tlačítka umístíme přímo do okna, budou všechna implicitně patřit do jediné skupiny. Můžeme se o tom snadno přesvědčit.
Nejprve vytvoříme sadu šesti přepínacích tlačítek:
# testovací přepínací tlačítka testRadioButton1 = QtGui.QRadioButton("radio button #1") testRadioButton2 = QtGui.QRadioButton("radio button #2") testRadioButton3 = QtGui.QRadioButton("radio button #3") testRadioButton4 = QtGui.QRadioButton("radio button #4") testRadioButton5 = QtGui.QRadioButton("radio button #5") testRadioButton6 = QtGui.QRadioButton("radio button #6")
Následně (není to ovšem povinnost) jedno z tlačítek vybereme:
# které tlačítko bude vybráno testRadioButton3.setChecked(True)
Nakonec vložíme tlačítka přímo na plochu okna (zde konkrétně přes správce rozvržení QVBoxLayout):
# umístění widgetů do okna layout.addWidget(testRadioButton1) layout.addWidget(testRadioButton2) layout.addWidget(testRadioButton3) layout.addWidget(testRadioButton4) layout.addWidget(testRadioButton5) layout.addWidget(testRadioButton6)

Obrázek 8: Výchozí stav aplikace, kdy je vybráno třetí tlačítko.

Obrázek 9: Přepnutí na první tlačítko (myší či klávesnicí).
Pokud zakomentujeme tento řádek, nebude ve výchozím stavu vybráno žádné tlačítko:
self.testRadioButton3.setChecked(True)

Obrázek 10: Výchozí stav ve chvíli, kdy není vybráno žádné tlačítko.
5. Druhý demonstrační příklad
Ve druhém demonstračním příkladu je ukázán způsob použití většího množství přepínacích tlačítek vložených do jediného okna aplikace. U tlačítek není specifikována žádná skupina, což povede k tomu, že se tlačítka automaticky přepnou do režimu exkluzivity výběru (tj. bude možné vybrat vždy maximálně jedno tlačítko v celém oknu):
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("Six radio buttons") # testovací přepínací tlačítka self.testRadioButton1 = QtGui.QRadioButton("radio button #1") self.testRadioButton2 = QtGui.QRadioButton("radio button #2") self.testRadioButton3 = QtGui.QRadioButton("radio button #3") self.testRadioButton4 = QtGui.QRadioButton("radio button #4") self.testRadioButton5 = QtGui.QRadioButton("radio button #5") self.testRadioButton6 = QtGui.QRadioButton("radio button #6") # které tlačítko bude vybráno self.testRadioButton3.setChecked(True) # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit") # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.testRadioButton1) layout.addWidget(self.testRadioButton2) layout.addWidget(self.testRadioButton3) layout.addWidget(self.testRadioButton4) layout.addWidget(self.testRadioButton5) layout.addWidget(self.testRadioButton6) layout.addWidget(testButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # po stisku testovacího tlačítka se zavolá metoda testButton.clicked.connect(self.printState) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def printState(self): print("-" * 50) MainWindow.printStateForRadioButton("#1", self.testRadioButton1) MainWindow.printStateForRadioButton("#2", self.testRadioButton2) MainWindow.printStateForRadioButton("#3", self.testRadioButton3) MainWindow.printStateForRadioButton("#4", self.testRadioButton4) MainWindow.printStateForRadioButton("#5", self.testRadioButton5) MainWindow.printStateForRadioButton("#6", self.testRadioButton6) @staticmethod def printStateForRadioButton(name, radioButton): state = "checked" if radioButton.isChecked() else "unchecked" print("Radio button {name} is {state}".format(name=name, state=state)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
6. Vypnutí režimu automatického sdružování přepínacích tlačítek do jedné skupiny
Výše popsaný režim automatického sdružování přepínacích tlačítek do jedné skupiny můžeme vypnout, a to buď pro všechna tlačítka, nebo jen pro tlačítka vybraná. Vyzkoušejme si druhou možnost. Nejprve opět vytvoříme šest přepínacích tlačítek:
# testovací přepínací tlačítka testRadioButton1 = QtGui.QRadioButton("radio button #1") testRadioButton2 = QtGui.QRadioButton("radio button #2") testRadioButton3 = QtGui.QRadioButton("radio button #3") testRadioButton4 = QtGui.QRadioButton("radio button #4") testRadioButton5 = QtGui.QRadioButton("radio button #5") testRadioButton6 = QtGui.QRadioButton("radio button #6")
Poté u prvních tří tlačítek vypneme režim automatického zajišťování exkluzivity výběru:
# první tři tlačítka nebudou automaticky přidána do společné skupiny testRadioButton1.setAutoExclusive(False) testRadioButton2.setAutoExclusive(False) testRadioButton3.setAutoExclusive(False)
Chování je ukázáno na následující sekvenci screenshotů:

Obrázek 11: Výchozí stav aplikace, kdy není vybráno žádné tlačítko.

Obrázek 12: Ve druhé (spodní) trojici lze vždy vybrat maximálně jedno tlačítko.

Obrázek 13: První (horní) trojice umožňuje libovolnou kombinaci výběru.
7. Třetí demonstrační příklad
Třetí demonstrační příklad se do značné míry podobá příkladu druhému, s nímž jsme se seznámili v páté kapitole. Jediný podstatný rozdíl spočívá v tom, že první tři přepínací tlačítka nemají povolen režim exkluzivního výběru. Tato tlačítka jsou od další trojice vizuálně oddělena:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("Non exclusive selection") # testovací přepínací tlačítka self.testRadioButton1 = QtGui.QRadioButton("radio button #1") self.testRadioButton2 = QtGui.QRadioButton("radio button #2") self.testRadioButton3 = QtGui.QRadioButton("radio button #3") self.testRadioButton4 = QtGui.QRadioButton("radio button #4") self.testRadioButton5 = QtGui.QRadioButton("radio button #5") self.testRadioButton6 = QtGui.QRadioButton("radio button #6") # první tři tlačítka nebudou automaticky přidána do společné skupiny self.testRadioButton1.setAutoExclusive(False) self.testRadioButton2.setAutoExclusive(False) self.testRadioButton3.setAutoExclusive(False) # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit") # horizontální oddělovač horizontalLine = QtGui.QLabel() horizontalLine.setFrameStyle(QtGui.QFrame.HLine) # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.testRadioButton1) layout.addWidget(self.testRadioButton2) layout.addWidget(self.testRadioButton3) layout.addWidget(horizontalLine) layout.addWidget(self.testRadioButton4) layout.addWidget(self.testRadioButton5) layout.addWidget(self.testRadioButton6) layout.addWidget(testButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # po stisku testovacího tlačítka se zavolá metoda testButton.clicked.connect(self.printState) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def printState(self): print("-" * 50) MainWindow.printStateForRadioButton("#1", self.testRadioButton1) MainWindow.printStateForRadioButton("#2", self.testRadioButton2) MainWindow.printStateForRadioButton("#3", self.testRadioButton3) MainWindow.printStateForRadioButton("#4", self.testRadioButton4) MainWindow.printStateForRadioButton("#5", self.testRadioButton5) MainWindow.printStateForRadioButton("#6", self.testRadioButton6) @staticmethod def printStateForRadioButton(name, radioButton): state = "checked" if radioButton.isChecked() else "unchecked" print("Radio button {name} is {state}".format(name=name, state=state)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
8. Vytvoření explicitních skupin přepínacích tlačítek
V případě, že se mají v dialogu objevit přepínací tlačítka tvořící větší množství skupin, již musíme jednotlivé skupiny explicitně definovat. Není to nic těžkého, ostatně jsme se s tímto problémem již setkali minule při popisu tvorby skupiny zaškrtávacích tlačítek. Podívejme se tedy na postup ve chvíli, kdy budeme potřebovat vytvořit tři skupiny přepínacích tlačítek, přičemž v každé skupině budou pro jednoduchost pouze dvě tlačítka. Nejprve jednotlivá tlačítka vytvoříme, což už dobře známe:
# testovací přepínací tlačítka # první skupina testRadioButton1 = QtGui.QRadioButton("radio button #1") testRadioButton2 = QtGui.QRadioButton("radio button #2") # druhá skupina testRadioButton3 = QtGui.QRadioButton("radio button #3") testRadioButton4 = QtGui.QRadioButton("radio button #4") # třetí skupina testRadioButton5 = QtGui.QRadioButton("radio button #5") testRadioButton6 = QtGui.QRadioButton("radio button #6")
Dále musíme tlačítka sloučit do skupin, takže si jednotlivé skupiny vytvoříme. Stačí nám přitom dvě skupiny, a to z toho důvodu, že zbylá tlačítka budou patřit přímo do okna a vytvoří tedy automaticky skupinu vlastní:
# dvě explicitní skupiny tlačítek buttonGroup1and2 = QtGui.QButtonGroup() buttonGroup3and4 = QtGui.QButtonGroup()
Nastavíme chování tlačítek v jednotlivých skupinách:
# chování tlačítek ve skupinách buttonGroup1and2.setExclusive(True) buttonGroup3and4.setExclusive(True)
Přidáme dvě tlačítka do první skupiny:
# přidání přepínacích tlačítek do skupin buttonGroup1and2.addButton(testRadioButton1) buttonGroup1and2.addButton(testRadioButton2)
A další dvě tlačítka do skupiny druhé:
# přidání přepínacích tlačítek do skupin buttonGroup3and4.addButton(testRadioButton3) buttonGroup3and4.addButton(testRadioButton4)
Následně již jednotlivá tlačítka vložíme do okna, samozřejmě společně s vizuálním oddělovačem jednotlivých skupin:
# umístění widgetů do okna layout.addWidget(testRadioButton1) layout.addWidget(testRadioButton2) layout.addWidget(horizontalLine1) layout.addWidget(testRadioButton3) layout.addWidget(testRadioButton4) layout.addWidget(horizontalLine2) layout.addWidget(testRadioButton5) layout.addWidget(testRadioButton6)
Chování takto upravené aplikace je ukázáno na další sérii screenshotů:

Obrázek 14: Výchozí stav přepínačů – žádné tlačítko není vybráno.

Obrázek 15: Přepínaní je možné provádět v každé skupině zvlášť.

Obrázek 16: Samozřejmě nezávisle na ostatních skupinách.

Obrázek 17: Stav přepínačů zjištěných ve chvíli, kdy je aplikace ve stavu zobrazeném na předchozím screenshotu.
9. Čtvrtý demonstrační příklad
V dnešním třetím demonstračním příkladu je ukázáno, jakým způsobem je možné v případě potřeby rozdělit přepínací tlačítka do skupin. Zde se konkrétně používají dvě explicitně definované skupiny tlačítek, přičemž zbylá přepínací tlačítka mají vlastní (výchozí) skupinu:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("Custom radio button groups") # dvě explicitní skupiny tlačítek self.buttonGroup1and2 = QtGui.QButtonGroup() self.buttonGroup3and4 = QtGui.QButtonGroup() # chování tlačítek ve skupinách self.buttonGroup1and2.setExclusive(True) self.buttonGroup3and4.setExclusive(True) # testovací přepínací tlačítka self.testRadioButton1 = QtGui.QRadioButton("radio button #1") self.testRadioButton2 = QtGui.QRadioButton("radio button #2") self.testRadioButton3 = QtGui.QRadioButton("radio button #3") self.testRadioButton4 = QtGui.QRadioButton("radio button #4") self.testRadioButton5 = QtGui.QRadioButton("radio button #5") self.testRadioButton6 = QtGui.QRadioButton("radio button #6") # přidání přepínacích tlačítek do skupin self.buttonGroup1and2.addButton(self.testRadioButton1) self.buttonGroup1and2.addButton(self.testRadioButton2) self.buttonGroup3and4.addButton(self.testRadioButton3) self.buttonGroup3and4.addButton(self.testRadioButton4) # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit") # horizontální oddělovače horizontalLine1 = QtGui.QLabel() horizontalLine1.setFrameStyle(QtGui.QFrame.HLine) horizontalLine2 = QtGui.QLabel() horizontalLine2.setFrameStyle(QtGui.QFrame.HLine) # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.testRadioButton1) layout.addWidget(self.testRadioButton2) layout.addWidget(horizontalLine1) layout.addWidget(self.testRadioButton3) layout.addWidget(self.testRadioButton4) layout.addWidget(horizontalLine2) layout.addWidget(self.testRadioButton5) layout.addWidget(self.testRadioButton6) layout.addWidget(testButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # po stisku testovacího tlačítka se zavolá metoda testButton.clicked.connect(self.printState) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def printState(self): print("-" * 50) MainWindow.printStateForRadioButton("#1", self.testRadioButton1) MainWindow.printStateForRadioButton("#2", self.testRadioButton2) MainWindow.printStateForRadioButton("#3", self.testRadioButton3) MainWindow.printStateForRadioButton("#4", self.testRadioButton4) MainWindow.printStateForRadioButton("#5", self.testRadioButton5) MainWindow.printStateForRadioButton("#6", self.testRadioButton6) @staticmethod def printStateForRadioButton(name, radioButton): state = "checked" if radioButton.isChecked() else "unchecked" print("Radio button {name} is {state}".format(name=name, state=state)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
10. Použití klávesových zkratek namísto myši při přístupu ke standardním widgetům
Ve druhé třetině článku se budeme zabývat přiřazením klávesových zkratek k jednotlivým aktivním ovládacím prvkům. Při tvorbě zkratek můžeme použít dva přístupy – buď se spolehneme na použití kombinace klávesy Alt s dalším znakem, nebo budeme muset vytvořit vlastní klávesovou zkratku, která ovšem může být mnohonásobně komplikovanější a může obsahovat i sekvenci po sobě stisknutých kombinací kláves. Nejdříve se však budeme zabývat prvním případem, tj. klávesovými zkratkami ve tvaru Alt+znak. Příslušný znak může být součástí textu na ovládacím prvku; postačí před něj vložit znak &. Příslušný znak bude většinou zobrazen s podtržením a bude i správně reagovat na ovládání z klávesnice. Ukažme si příklad použití tohoto postupu pro různé typy widgetů:
# testovací zaškrtávací tlačítka testCheckBox1 = QtGui.QCheckBox("check box &x") testCheckBox2 = QtGui.QCheckBox("check box &y") testCheckBox3 = QtGui.QCheckBox("check box &z") # testovací přepínací tlačítka estRadioButton1 = QtGui.QRadioButton("radio button &a") estRadioButton2 = QtGui.QRadioButton("radio button &b") estRadioButton3 = QtGui.QRadioButton("radio button &c") # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("&Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("&Quit")

Obrázek 18: Ovládací prvky, k nimž je přiřazena kombinace Alt+znak.
Pokud budeme chtít pouze zobrazit znak &, musíme ho zdvojit a tím negovat jeho speciální význam:
# testovací zaškrtávací tlačítka testCheckBox1 = QtGui.QCheckBox("check box &&x") testCheckBox2 = QtGui.QCheckBox("check box &&y") testCheckBox3 = QtGui.QCheckBox("check box &&z") # testovací přepínací tlačítka estRadioButton1 = QtGui.QRadioButton("radio button &&a") estRadioButton2 = QtGui.QRadioButton("radio button &&b") estRadioButton3 = QtGui.QRadioButton("radio button &&c") # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("&&Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("&&Quit")

Obrázek 19: Ovládací prvky se zobrazením znaku & (nemá zde žádný speciální význam).
11. Pátý demonstrační příklad
V pořadí pátém demonstračním příkladu je ukázáno, jak lze k jednotlivým ovládacím prvkům, tj. k běžným tlačítkům, zaškrtávacím tlačítkům i k tlačítkům přepínacím přiřadit klávesové zkratky. Po spuštění příkladu si můžete sami vyzkoušet použít kombinaci Alt+znak pro stisk příslušného tlačítka bez nutnosti použít myš či přepínat fokus s využitím Tab:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("Shortcuts") # testovací zaškrtávací tlačítka self.testCheckBox1 = QtGui.QCheckBox("check box &x") self.testCheckBox2 = QtGui.QCheckBox("check box &y") self.testCheckBox3 = QtGui.QCheckBox("check box &z") self.testCheckBox1.setCheckState(QtCore.Qt.Unchecked) self.testCheckBox2.setCheckState(QtCore.Qt.Checked) self.testCheckBox3.setCheckState(QtCore.Qt.Unchecked) # testovací přepínací tlačítka self.testRadioButton1 = QtGui.QRadioButton("radio button &a") self.testRadioButton2 = QtGui.QRadioButton("radio button &b") self.testRadioButton3 = QtGui.QRadioButton("radio button &c") self.testRadioButton2.setChecked(True) # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("&Print state") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("&Quit") # horizontální oddělovače horizontalLine1 = QtGui.QLabel() horizontalLine1.setFrameStyle(QtGui.QFrame.HLine) horizontalLine2 = QtGui.QLabel() horizontalLine2.setFrameStyle(QtGui.QFrame.HLine) # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.testRadioButton1) layout.addWidget(self.testRadioButton2) layout.addWidget(self.testRadioButton3) layout.addWidget(horizontalLine1) layout.addWidget(self.testCheckBox1) layout.addWidget(self.testCheckBox2) layout.addWidget(self.testCheckBox3) layout.addWidget(horizontalLine2) layout.addWidget(testButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # po stisku testovacího tlačítka se zavolá metoda testButton.clicked.connect(self.printState) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def printState(self): print("-" * 50) MainWindow.printStateForRadioButton("#1", self.testRadioButton1) MainWindow.printStateForRadioButton("#2", self.testRadioButton2) MainWindow.printStateForRadioButton("#3", self.testRadioButton3) MainWindow.printStateForCheckbox("#1", self.testCheckBox1) MainWindow.printStateForCheckbox("#2", self.testCheckBox2) MainWindow.printStateForCheckbox("#3", self.testCheckBox3) @staticmethod def printStateForCheckbox(name, checkbox): state = "checked" if checkbox.isChecked() else "unchecked" print("Checkbox {name} is {state}".format(name=name, state=state)) @staticmethod def printStateForRadioButton(name, radioButton): state = "checked" if radioButton.isChecked() else "unchecked" print("Radio button {name} is {state}".format(name=name, state=state)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
12. Explicitní klávesové zkratky (Ctrl+?, Shift+?, Alt+?)
Pokud kombinace Alt+znak z nějakého důvodu nedostačuje pro potřeby aplikace, je nutné použít nepatrně složitější způsob deklarace klávesových zkratek. Tento způsob využívá metodu setShortcut deklarovanou ve třídě QAbstractButton. Této metodě se předává objekt typu QKeySequence. Instance QKeySequence lze získat různými způsoby, ovšem pokud nebudeme chtít klávesovou zkratku zobrazit uživateli (což u běžného dialogu asi nemá význam, na rozdíl od položek menu), je nejjednodušší použít konstruktor:
QKeySequence("klávesová zkratka")
Pozor: ve chvíli, kdy k ovládacímu prvku přiřadíte vlastní klávesovou zkratku, nebude možné použít implicitní zkratku Alt+znak, i když bude příslušný znak podtržený!
Příklady použití ukazují, jaké klávesové zkratky (nutno říci, že v této podobě jsou systémově závislé) se mohou v řetězci objevit:
# klávesové zkratky testRadioButton1.setShortcut(QtGui.QKeySequence("Ctrl+A")) testRadioButton2.setShortcut(QtGui.QKeySequence("Ctrl+B")) testRadioButton3.setShortcut(QtGui.QKeySequence("Ctrl+C")) testCheckBox1.setShortcut(QtGui.QKeySequence("F1")) testCheckBox2.setShortcut(QtGui.QKeySequence("F2")) testCheckBox3.setShortcut(QtGui.QKeySequence("F3")) testButton.setShortcut(QtGui.QKeySequence("Shift+P")) quitButton.setShortcut(QtGui.QKeySequence("Esc"))

Obrázek 20: Aplikace, kterou je možné ovládat klávesovými zkratkami.
13. Šestý demonstrační příklad
Způsob deklarace klávesových zkratek přiřazených k jednotlivým komponentám grafického uživatelského rozhraní je ukázán v dnešním šestém demonstračním příkladu, jehož zdrojový kód je vypsán pod tímto odstavcem:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("Custom shortcuts") # testovací zaškrtávací tlačítka self.testCheckBox1 = QtGui.QCheckBox("check box x (F1)") self.testCheckBox2 = QtGui.QCheckBox("check box y (F2)") self.testCheckBox3 = QtGui.QCheckBox("check box z (F3)") self.testCheckBox1.setCheckState(QtCore.Qt.Unchecked) self.testCheckBox2.setCheckState(QtCore.Qt.Checked) self.testCheckBox3.setCheckState(QtCore.Qt.Unchecked) # testovací přepínací tlačítka self.testRadioButton1 = QtGui.QRadioButton("radio button a (Ctrl+A)") self.testRadioButton2 = QtGui.QRadioButton("radio button b (Ctrl+B)") self.testRadioButton3 = QtGui.QRadioButton("radio button c (Ctrl+C)") self.testRadioButton2.setChecked(True) # tlačítko pro zjištění stavů přepínačů testButton = QtGui.QPushButton("Print state (Shift+P)") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit (Esc)") # klávesové zkratky self.testRadioButton1.setShortcut(QtGui.QKeySequence("Ctrl+A")) self.testRadioButton2.setShortcut(QtGui.QKeySequence("Ctrl+B")) self.testRadioButton3.setShortcut(QtGui.QKeySequence("Ctrl+C")) self.testCheckBox1.setShortcut(QtGui.QKeySequence("F1")) self.testCheckBox2.setShortcut(QtGui.QKeySequence("F2")) self.testCheckBox3.setShortcut(QtGui.QKeySequence("F3")) testButton.setShortcut(QtGui.QKeySequence("Shift+P")) quitButton.setShortcut(QtGui.QKeySequence("Esc")) # horizontální oddělovače horizontalLine1 = QtGui.QLabel() horizontalLine1.setFrameStyle(QtGui.QFrame.HLine) horizontalLine2 = QtGui.QLabel() horizontalLine2.setFrameStyle(QtGui.QFrame.HLine) # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.testRadioButton1) layout.addWidget(self.testRadioButton2) layout.addWidget(self.testRadioButton3) layout.addWidget(horizontalLine1) layout.addWidget(self.testCheckBox1) layout.addWidget(self.testCheckBox2) layout.addWidget(self.testCheckBox3) layout.addWidget(horizontalLine2) layout.addWidget(testButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # po stisku testovacího tlačítka se zavolá metoda testButton.clicked.connect(self.printState) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def printState(self): print("-" * 50) MainWindow.printStateForRadioButton("#1", self.testRadioButton1) MainWindow.printStateForRadioButton("#2", self.testRadioButton2) MainWindow.printStateForRadioButton("#3", self.testRadioButton3) MainWindow.printStateForCheckbox("#1", self.testCheckBox1) MainWindow.printStateForCheckbox("#2", self.testCheckBox2) MainWindow.printStateForCheckbox("#3", self.testCheckBox3) @staticmethod def printStateForCheckbox(name, checkbox): state = "checked" if checkbox.isChecked() else "unchecked" print("Checkbox {name} is {state}".format(name=name, state=state)) @staticmethod def printStateForRadioButton(name, radioButton): state = "checked" if radioButton.isChecked() else "unchecked" print("Radio button {name} is {state}".format(name=name, state=state)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
14. Třída QMainWindow a její odlišnosti od QWidget
V poslední třetině článku si ukážeme, jakým způsobem je možné použít třídu QMainWindow pro vytvoření hlavního okna aplikace. Všechny předchozí příklady byly založeny na použití obecné komponenty QWidget, od níž jsme odvodili vlastní třídu s odlišnými vlastnostmi (a samozřejmě i vzhledem):
# nový widget bude odvozen od obecného widgetu class MainWindow(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__()
Využití QWidgetu je možné doporučit v případě, že vše, co vyžadujeme, je prázdné okno či dialog, na jehož plochu budeme vkládat další komponenty. Ovšem na hlavní okno aplikace jsou kladeny poněkud odlišné požadavky, neboť uživatelé očekávají:
- Existenci hlavního menu
- Existenci stavového řádku
- Většinou taktéž toolbar
- U některých aplikací taby s jednotlivými listy
Právě v tomto případě není nutné všechny očekávané vlastnosti implementovat ručně, ale lze namísto QWidgetu použít právě třídu QMainWindow. Plocha hlavního okna je rozdělena na oblasti, do kterých lze vkládat zmíněné hlavní menu (představované komponentou QMenuBar), stavový řádek představovaný komponentou QStatusBar, dále zde existuje oblast určená pro vložení toolbaru a tzv. centrální plocha, do které je možné (většinou nepřímo) vkládat další ovládací prvky.

Obrázek 21: Okno vytvořené odvozením od komponenty QMainWindow.
Kostra aplikace používající třídu QMainWindow může vypadat prakticky stejně, jako aplikace založená na třídě QWidget:
# nový widget bude odvozen od obecného hlavního okna class MainWindow(QtGui.QMainWindow): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__()
O dalších odlišnostech, které jsou mnohdy zásadního charakteru, se dozvíme v dalších kapitolách.
15. Zobrazení hlavního okna
Způsob použití třídy QMainWindow pro odvození třídy reprezentující konkrétní hlavní okno aplikace je ukázán v dalším demonstračním příkladu, jehož zdrojový kód je vypsán pod tímto odstavcem. Povšimněte si, že se tato aplikace prakticky nijak neliší od aplikací, v nichž jsme hlavní okno odvodili od obecného ovládacího prvku QWidget. Ve skutečnosti však bude chování odlišné, což uvidíme ve chvíli, kdy do hlavního okna budeme vkládat stavový řádek, hlavní menu, nástrojový pruh či „pouze“ libovolné další ovládací prvky:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného hlavního okna class MainWindow(QtGui.QMainWindow): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("QMainWindow") def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
16. Přidání tlačítka do centrální části hlavního okna
Jak se vlastně do hlavního okna přidávají další widgety? Už ve čtrnácté kapitole jsme si řekli, že hlavní okno se v některých ohledech odlišuje od obecného widgetu QWidget, a to především v tom ohledu, že v hlavním oknu už jsou předem vyhrazené oblasti na speciální ovládací prvky. Proto není vhodné přidávat na hlavní okno další komponenty stylem:
# návěští label = QtGui.QLabel("Hello world!", self) # posun v rámci nadřazeného widgetu label.move(100, 100)
Widget (či widgety) budeme vkládat do centrální oblasti, která se v případě potřeby automaticky zvětší a ostatní nepoužité oblasti se zmenší na nulovou plochu:
# tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit") # vložení komponenty do okna self.setCentralWidget(quitButton)

Obrázek 22: Hlavní okno aplikace s tlačítkem Quit.
Celý příklad, který po svém spuštění zobrazí hlavní okno s jediným tlačítkem Quit, vypadá následovně:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného hlavního okna class MainWindow(QtGui.QMainWindow): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("QMainWindow") # tlačítko pro ukončení aplikace quitButton = QtGui.QPushButton("Quit") # vložení komponenty do okna self.setCentralWidget(quitButton) # navázání akce na stisk tlačítka pro ukončení aplikace quitButton.clicked.connect(self.quit) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def quit(self): print("Closing...") self.close() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
17. Lepší přístup – odvození vlastního widgetu pro centrální část hlavního okna
V předchozím příkladu se tlačítko Quit zvětšilo tak, že vyplnilo celou plochu hlavního okna (resp. přesněji řečeno jeho centrální oblasti). Ovšem ve chvíli, kdy budeme chtít do okna přidávat další ovládací prvky (a to asi budeme, protože okno s jediným tlačítkem je poněkud nepraktické), využijeme správce rozvržení neboli layout manager. Podívejme se nyní na jeden z možných přístupů. Vytvoříme novou třídu představující „vnitřek“ hlavního okna. Tato třída bude odvozena od QWidget, tedy stylem, s nímž jsme se již setkali. Můžeme zde použít libovolného správce rozvržení, atd. atd.
# nový widget bude odvozen od obecného widgetu class MainWindowContent(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindowContent, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # tlačítko button = QtGui.QPushButton("Quit", self) button.resize(button.sizeHint()) # navázání akce na signál button.clicked.connect(QtCore.QCoreApplication.instance().quit)
Následně náš nový widget (obsahující libovolné množství dalších widgetů) vložíme do hlavního okna, konkrétně do jeho centrální oblasti:
def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("QMainWindow") # vložení komponenty do okna self.setCentralWidget(MainWindowContent())

Obrázek 23: Hlavní okno aplikace s tlačítkem Quit.
Celý příklad s dvojicí tříd vypadá následovně:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindowContent(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindowContent, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # tlačítko button = QtGui.QPushButton("Quit", self) button.resize(button.sizeHint()) # navázání akce na signál button.clicked.connect(QtCore.QCoreApplication.instance().quit) # nový widget bude odvozen od obecného hlavního okna class MainWindow(QtGui.QMainWindow): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("QMainWindow") # vložení komponenty do okna self.setCentralWidget(MainWindowContent()) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
18. Složitější layout komponent, stavový řádek a další vylepšení
Rozdělení funkcionality hlavního okna do dvou tříd může vést k větší přehlednosti zdrojového kódu, ovšem někdy se setkáme s nutností posílání zpráv mezi instancemi obou tříd. V následujícím příkladu je řešen problém jednoduchého čítače, jehož hodnota je zvýšena po každém stisku tlačítka:

Obrázek 24: Hlavní okno aplikace ihned po spuštění.

Obrázek 25: Stav aplikace po několikerém stisku tlačítka.
Čítač je ovšem umístěn do stavového řádku hlavního okna, takže je nutné, aby tlačítko (které je součástí třídy MainWindowContent) komunikovalo se stavovým řádkem (ten je ovšem součástí třídy MainWindow). Jedno z řešení – schválně zatím neřeknu, jak moc je dobré – je ukázáno níže. Sami se zkuste zamyslet nad dalšími způsoby řešení tohoto problému. Některé z nich si popíšeme příště:
#!/usr/bin/env python # vim: set fileencoding=utf-8 import sys # import "jádra" frameworku Qt i modulu pro GUI from PySide import QtCore from PySide import QtGui # nový widget bude odvozen od obecného widgetu class MainWindowContent(QtGui.QWidget): def __init__(self): # zavoláme konstruktor předka super(MainWindowContent, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareGUI(self): # tlačítko 1 self.counterButton = QtGui.QPushButton("Counter", self) self.counterButton.resize(self.counterButton.sizeHint()) # tlačítko 2 quitButton = QtGui.QPushButton("Quit", self) quitButton.resize(quitButton.sizeHint()) # vytvoření správce geometrie layout = QtGui.QVBoxLayout() # umístění widgetů do okna layout.addWidget(self.counterButton) layout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(layout) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) # nový widget bude odvozen od obecného hlavního okna class MainWindow(QtGui.QMainWindow): def __init__(self): # zavoláme konstruktor předka super(MainWindow, self).__init__() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() self._counter = 0 def prepareGUI(self): # velikost není potřeba specifikovat # self.resize(320, 240) self.setWindowTitle("QMainWindow") self.statusBar().showMessage("QMainWindow") content = MainWindowContent() self.setCentralWidget(content) # jedna z variant naprogramování reakce na stisk tlačítka content.counterButton.clicked.connect(self.counterClicked) def counterClicked(self): self._counter += 1 self.statusBar().showMessage(str(self._counter)) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
19. Repositář s demonstračními příklady
Zdrojové kódy všech jedenácti dnes popsaných demonstračních příkladů byly opět, podobně jako tomu bylo i v předchozích článcích, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/presentations. Pokud nechcete klonovat celý repositář, můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
Poznámka: první příklad je naprogramován s využitím Tkinteru a ukazuje chování jediného přepínacího tlačítka v této knihovně.
20. Odkazy na Internetu
- PySide 1.2.1 documentation
https://pyside.github.io/docs/pyside/index.html - Differences Between PySide and PyQt
https://wiki.qt.io/Differences_Between_PySide_and_PyQt - PySide 1.2.1 tutorials
https://pyside.github.io/docs/pyside/tutorials/index.html - PySide tutorial
http://zetcode.com/gui/pysidetutorial/ - Qt Core
https://pyside.github.io/docs/pyside/PySide/QtCore/Qt.html - QLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QLayout.html - QStackedLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QStackedLayout.html - QFormLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QFormLayout.html - QBoxLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QBoxLayout.html - QHBoxLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QHBoxLayout.html - QVBoxLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QVBoxLayout.html - QGridLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QGridLayout.html - Signals & Slots
http://doc.qt.io/qt-4.8/signalsandslots.html - Signals and Slots in PySide
http://wiki.qt.io/Signals_and_Slots_in_PySide - Intro to PySide/PyQt: Basic Widgets and Hello, World!
http://www.pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/ - QWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QWidget.html - QMainWindow
https://pyside.github.io/docs/pyside/PySide/QtGui/QMainWindow.html - QLabel
https://pyside.github.io/docs/pyside/PySide/QtGui/QLabel.html - QAbstractButton
https://pyside.github.io/docs/pyside/PySide/QtGui/QAbstractButton.html - QCheckBox
https://pyside.github.io/docs/pyside/PySide/QtGui/QCheckBox.html - QRadioButton
https://pyside.github.io/docs/pyside/PySide/QtGui/QRadioButton.html - QButtonGroup
https://pyside.github.io/docs/pyside/PySide/QtGui/QButtonGroup.html - QFrame
https://pyside.github.io/docs/pyside/PySide/QtGui/QFrame.html#PySide.QtGui.PySide.QtGui.QFrame - QFrame.frameStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QFrame.html#PySide.QtGui.PySide.QtGui.QFrame.frameStyle - Leo editor
http://leoeditor.com/ - IPython Qt Console aneb vylepšený pseudoterminál
https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-ipython-a-ipython-notebook/#k06 - Vývojová prostředí ve Fedoře (4. díl)
https://mojefedora.cz/vyvojova-prostredi-ve-fedore-4-dil/ - Seriál Letní škola programovacího jazyka Logo
http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/ - Educational programming language
http://en.wikipedia.org/wiki/Educational_programming_language - Logo Tree Project:
http://www.elica.net/download/papers/LogoTreeProject.pdf - Hra Breakout napísaná v Tkinteri
https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/ - Hra Snake naprogramovaná v Pythone s pomocou Tkinter
https://www.root.cz/clanky/hra-snake-naprogramovana-v-pythone-s-pomocou-tkinter/ - 24.1. turtle — Turtle graphics
https://docs.python.org/3.5/library/turtle.html#module-turtle - TkDND
http://freecode.com/projects/tkdnd - Python Tkinter Fonts
https://www.tutorialspoint.com/python/tk_fonts.htm - The Tkinter Canvas Widget
http://effbot.org/tkinterbook/canvas.htm - 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 - 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/ - appJar widgets
http://appjar.info/pythonWidgets/ - 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/