Obsah
1. Další možnosti konfigurace tlačítek u dialogu QMessageBox
2. První demonstrační příklad – použití metody QMessageBox.addButton pro konfigurace tlačítek
4. Použití nestandardní ikony v dialogu QMessageBox
5. Třetí demonstrační příklad – vlastní ikona zobrazená v dialogu QMessageBox
6. Změna popisků tlačítek u standardního vstupního dialogu
7. Čtvrtý demonstrační příklad – české popisky tlačítek standardního vstupního dialogu
8. Vstupní dialog zobrazený bez tlačítek (pouze s polem pro zadání údajů uživatelem)
9. Pátý demonstrační příklad – vstupní dialog bez tlačítek
10. Navázání handlerů na událost generovanou při změně údajů ve vstupním dialogu
11. Šestý demonstrační příklad – reakce na průběžnou změnu údajů ve vstupním dialogu
12. Barvová paleta vybraná uživatelem přes QColorDialog
14. Standardní dialog pro výběr souboru či adresáře
15. Osmý demonstrační příklad – výběr souboru pro otevření souboru
16. Repositář s demonstračními příklady
1. Další možnosti konfigurace tlačítek u dialogu QMessageBox
V předchozím článku o tvorbě aplikací s grafickým uživatelským rozhraním s využitím knihovny PySide jsme si mj. popsali i jednoduchý standardní dialog určený pro zobrazení zprávy uživateli. Připomeňme si, že tento dialog je představován třídou QMessageBox popř. potomky této třídy. Víme již, že u tohoto typu dialogu je (pochopitelně) možné specifikovat zprávu, která se má uživateli zobrazit a taktéž lze vybrat jednu ze čtyř standardních ikon nebo naopak zvolit, že se žádná ikona nemá zobrazit:
Ikona |
---|
QMessageBox.NoIcon |
QMessageBox.Question |
QMessageBox.Information |
QMessageBox.Warning |
QMessageBox.Critical |
Obrázek 1: Standardní dialog s ikonou QMessageBox.Warning.
Dnes si ukážeme další možnosti konfigurace tohoto jednoduchého standardního dialogu. Dialog QMessageBox totiž ve skutečnosti neslouží pouze k zobrazení zprávy uživateli, ale může být použit pro dotazy s odpověďmi typu Ano/Ne, Ok/Storno, Ano/Ano pro všechny možnosti/Ne/Ne pro všechny možnosti apod. Pro určení tlačítek, které se mají v dialogu zobrazit, slouží v první řadě metoda addButton, které se předá jak popisek tlačítka, tak i jeho role (ve skutečnosti není zapotřebí roli specifikovat, jedná se o nepovinný parametr). Popis tlačítka může být prakticky libovolný, ovšem roli je nutné vybrat z konstant nabízených samotnou třídou QMessageBox. Role určuje chování tlačítek:
Role tlačítka | Poznámka hodnota |
---|---|
QMessageBox.AcceptRole | zavře dialog s hodnotou odpovídající tlačítku Ok |
QMessageBox.RejectRole | zavře dialog s hodnotou odpovídající tlačítku Cancel/Storno |
QMessageBox.HelpRole | uživatel vyžaduje zobrazení nápovědy |
QMessageBox.YesRole | odpovídá roli tlačítka „Yes“ |
QMessageBox.NoRole | odpovídá roli tlačítka „No“ |
QMessageBox.ApplyRole | odpovídá roli tlačítka „Apply“ |
QMessageBox.ResetRole | odpovídá roli tlačítka „Reset“ (v jiném dialogu obnovení původních hodnot) |
QMessageBox.InvalidRole | nevalidní tlačítko |
Obrázek 2: Standardní dialog s ikonou QMessageBox.Critical.
Podívejme se na příklad použití u dialogu, v němž potřebujeme zobrazit trojici tlačítek:
def showMessageBox(self): # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení zprávy a ikony, která se má zobrazit vedle zprávy msgBox.setText(u'Zpráva') msgBox.setIcon(QtGui.QMessageBox.Information) # nastavení tlačítek, které mají být součástí dialogu msgBox.addButton("Help", QtGui.QMessageBox.HelpRole) msgBox.addButton("Accept", QtGui.QMessageBox.AcceptRole) msgBox.addButton("Reject", QtGui.QMessageBox.RejectRole)
Pokud dialog zobrazíme metodou exec_, bude návratová hodnota obsahovat index zvoleného tlačítka v tom pořadí, jak byla tlačítka předána do dialogu. To je trošku problematické, protože pozice zobrazených tlačítek (a tedy i jejich index) je platformově závislá. Například na Linuxu sice požadujeme zobrazení tlačítek v pořadí Help-Accept-Reject, ovšem ve skutečnosti se tlačítka zobrazí v pořadí Help-Reject-Accept (pořadí je určeno rolí, nikoli textem).
Obrázek 3: Standardní dialog se třemi nakonfigurovanými tlačítky Help, Accept a Reject.
Třída QMessageBox poskytuje programátorům i několik standardních tlačítek, které je do dialogu možné přidat metodou setStandardButton popř. v případě většího množství tlačítek setStandardButtons. Každé standardní tlačítko obsahuje (standardní) popisek a taktéž přiřazenou roli (viz tabulka zobrazená výše):
Tlačítko | Text | Role |
---|---|---|
QMessageBox.Ok | „OK“ | AcceptRole |
QMessageBox.Open | „Open“ | AcceptRole |
QMessageBox.Save | „Save“ | AcceptRole |
QMessageBox.Cancel | „Cancel“ | RejectRole |
QMessageBox.Close | „Close“ | RejectRole |
QMessageBox.Discard | „Discard“ nebo „Don’t Save“ | DestructiveRole |
QMessageBox.Apply | „Apply“ | ApplyRole |
QMessageBox.Reset | „Reset“ | ResetRole |
QMessageBox.RestoreDefaults | „Restore Defaults“ | ResetRole |
QMessageBox.Help | „Help“ | HelpRole |
QMessageBox.SaveAll | „Save All“ | AcceptRole |
QMessageBox.Yes | „Yes“ | YesRole |
QMessageBox.YesToAll | „Yes to All“ | YesRole |
QMessageBox.No | „No“ | NoRole |
QMessageBox.NoToAll | „No to All“ | NoRole |
QMessageBox.Abort | „Abort“ | RejectRole |
QMessageBox.Retry | „Retry“ | AcceptRole |
QMessageBox.Ignore | „Ignore“ | AcceptRole |
QMessageBox.NoButton | nevalidní tlačítko | × |
Následuje ukázka kódu, z něhož se dozvíme, jakým způsobem je možné deklarovat větší množství tlačítek, které se mají na dialogu objevit. Povšimněte si použití operátoru | (or):
def showMessageBox(self): # tlačítka, která mají být součástí dialogu buttons = QtGui.QMessageBox.Yes | \ QtGui.QMessageBox.YesToAll | \ QtGui.QMessageBox.No | \ QtGui.QMessageBox.NoToAll | \ QtGui.QMessageBox.Help # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení zprávy a ikony, která se má zobrazit vedle zprávy msgBox.setStandardButtons(buttons) msgBox.setText(u'Zpráva') msgBox.setIcon(QtGui.QMessageBox.Question)
Pro výběr výchozího tlačítka se použije metoda setDefaultButton. Taktéž je možné zvolit, které tlačítko se pomyslně vybere ve chvíli stlačení klávesy Esc. Pro tento účel se používá metoda setEscapeButton.
Obrázek 4: Standardní dialog s pěti nakonfigurovanými tlačítky.
Opět platí, že pokud dialog zobrazíme zavoláním metody exec_, vrátí se celočíselná hodnota odpovídající zvolenému tlačítku. Samotná tlačítka QMessageBox.* jsou konstanty výčtového typu, takže je možné psát například:
ret = msgBox.exec_() if ret == QtGui.QMessageBox.Yes: print("Yes!!!") elif ret == QtGui.QMessageBox.No: print("No!!!") else: print("something else")
Obrázek 5: Standardní dialog se čtyřmi nakonfigurovanými tlačítky.
2. První demonstrační příklad – použití metody QMessageBox.addButton pro konfigurace tlačítek
V dnešním prvním demonstračním příkladu je ukázáno, jakým způsobem je možné použít metodu nazvanou QMessageBox.addButton pro vytvoření dialogu, v němž bude zobrazena trojice tlačítek Help, Accept a Reject. Podívejme se na úplný zdrojový kód tohoto příkladu, v němž je důležitá především metoda nazvaná jednoduše showMessageBox:
#!/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): quitButton = self.prepareQuitButton() messageBoxButton = self.prepareMessageBoxButton() # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(messageBoxButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareMessageBoxButton(self): # tlačítko messageBoxButton = QtGui.QPushButton('Message Box', self) messageBoxButton.resize(messageBoxButton.sizeHint()) # navázání akce na signál messageBoxButton.clicked.connect(self.showMessageBox) return messageBoxButton def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showMessageBox(self): # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení zprávy a ikony, která se má zobrazit vedle zprávy msgBox.setText(u'Zpráva') msgBox.setIcon(QtGui.QMessageBox.Information) # msgBox.setIcon(QtGui.QMessageBox.Question) # msgBox.setIcon(QtGui.QMessageBox.Warning) # msgBox.setIcon(QtGui.QMessageBox.Critical) # nastavení tlačítek, které mají být součástí dialogu msgBox.addButton("Help", QtGui.QMessageBox.HelpRole) msgBox.addButton("Accept", QtGui.QMessageBox.AcceptRole) msgBox.addButton("Reject", QtGui.QMessageBox.RejectRole) # zobrazení dialogu print(msgBox.exec_()) # 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("QMessageBox") # 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()
3. Druhý demonstrační příklad – použití metody QMessageBox.setStandardButtons pro konfigurace tlačítek
Ve druhém příkladu můžeme vidět použití metody QMessageBox.setStandardButtons, které se předá objekt představující všechna tlačítka, která se mají v dialogu zobrazit. Povšimněte si, jakým způsobem je možné tento objekt vytvořit s využitím operátoru | (opět viz metodu showMessageBox obsahující nejdůležitější část tohoto příkladu):
#!/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): quitButton = self.prepareQuitButton() messageBoxButton = self.prepareMessageBoxButton() # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(messageBoxButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareMessageBoxButton(self): # tlačítko messageBoxButton = QtGui.QPushButton('Message Box', self) messageBoxButton.resize(messageBoxButton.sizeHint()) # navázání akce na signál messageBoxButton.clicked.connect(self.showMessageBox) return messageBoxButton def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showMessageBox(self): # tlačítka, která mají být součástí dialogu buttons = QtGui.QMessageBox.Yes | \ QtGui.QMessageBox.YesToAll | \ QtGui.QMessageBox.No | \ QtGui.QMessageBox.NoToAll | \ QtGui.QMessageBox.Help # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení zprávy a ikony, která se má zobrazit vedle zprávy msgBox.setStandardButtons(buttons) msgBox.setText(u'Zpráva') msgBox.setIcon(QtGui.QMessageBox.Question) # msgBox.setIcon(QtGui.QMessageBox.Question) # msgBox.setIcon(QtGui.QMessageBox.Warning) # msgBox.setIcon(QtGui.QMessageBox.Critical) # zobrazení dialogu print(msgBox.exec_()) # 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("QMessageBox") # 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()
4. Použití nestandardní ikony v dialogu QMessageBox
I další úpravy standardního dialogu představovaného třídou QMessageBox jsou z programátorského hlediska velmi jednoduché. Již minule jsme se zmínili o možnosti výběru standardní ikony metodou QMessageBox.setIcon. V některých případech nám však nemusí nabídka standardních ikon vyhovovat a proto namísto této metody použijeme metodu QMessageBox.setIconPixmap, které lze předat libovolný rastrový obrázek reprezentovaný instancí třídy QPixmap. Základní možnosti této třídy již dobře známe, takže si jen ve stručnosti ukažme, jakým postupem lze zařídit načtení externího rastrového obrázku a použít ho jako ikonu:
def showMessageBox(self): # tlačítko, která mají být součástí dialogu buttons = QtGui.QMessageBox.Ok # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení zprávy a ikony, která se má zobrazit vedle zprávy msgBox.setStandardButtons(buttons) msgBox.setText(u'') # načtení pixmapy a její nastavení jako ikony pro dialog pixmap = QtGui.QPixmap("pixmaps/pysidelogo.png") msgBox.setIconPixmap(pixmap)
Obrázek 6: Dialog, v němž je zpráva představována prázdným řetězcem a ve kterém je použita vlastní ikona.
5. Třetí demonstrační příklad – vlastní ikona zobrazená v dialogu QMessageBox
Podívejme se nyní na zdrojový kód dnešního třetího demonstračního příkladu, ve kterém vytváříme dialog typu QMessageBox a přitom v něm použijeme vlastní ikonu, kterou jsme již mimochodem v tomto seriálu použili při zobrazování tzv. splash screenu. Zpráva je nastavena na prázdný řetězec (samotná ikona je totiž poměrně velká a tak je v dialogu dostatečně dominantní) a kromě již zmíněné ikony se zobrazí jen jediné tlačítko Ok:
#!/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): quitButton = self.prepareQuitButton() messageBoxButton = self.prepareMessageBoxButton() # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(messageBoxButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareMessageBoxButton(self): # tlačítko messageBoxButton = QtGui.QPushButton('Message Box', self) messageBoxButton.resize(messageBoxButton.sizeHint()) # navázání akce na signál messageBoxButton.clicked.connect(self.showMessageBox) return messageBoxButton def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showMessageBox(self): # tlačítko, která mají být součástí dialogu buttons = QtGui.QMessageBox.Ok # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení zprávy a ikony, která se má zobrazit vedle zprávy msgBox.setStandardButtons(buttons) msgBox.setText(u'') # načtení pixmapy a její nastavení jako ikony pro dialog pixmap = QtGui.QPixmap("pixmaps/pysidelogo.png") msgBox.setIconPixmap(pixmap) # zobrazení dialogu print(msgBox.exec_()) # 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("QMessageBox") # 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()
6. Změna popisků tlačítek u standardního vstupního dialogu
Ve standardním vstupním dialogu nalezneme tlačítko Ok a Cancel:
Obrázek 7: Standardní vstupní dialog s tlačítky Ok a Cancel i se vstupním textovým polem.
Shodná tlačítka budou použita i ve chvíli, kdy je vstupní dialog nakonfigurován tak, aby akceptoval jen celá čísla, reálná čísla, výběr prvku ze seznamu či kombo boxu atd.
Obrázek 8: Standardní vstupní dialog s tlačítky Ok a Cancel i se vstupním polem určeným pro zadání celého čísla.
Popisky těchto dvou tlačítek můžeme snadno změnit, a to konkrétně zavoláním metod QInputDialog.setOkButtonText a QInputDialog.setCancelButtonText, kterým se předá nový text tlačítek. To je ukázáno v další funkci. Kvůli kompatibilitě s Pythonem 2.x je u všech řetězců explicitně uvedeno, že se používá kódování Unicode a nikoli ASCII:
def textInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.TextInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Text input:") dialog.setTextValue("default text") # nastavení textů tlačítek dialog.setCancelButtonText(u"Zrušit") dialog.setOkButtonText(u"Potvrdit")
Obrázek 9: Standardní vstupní dialog s modifikovanými tlačítky Ok a Cancel.
7. Čtvrtý demonstrační příklad – české popisky tlačítek standardního vstupního dialogu
V dnešním čtvrtém demonstračním příkladu je ukázána změna textu u tlačítek standardního vstupního dialogu. Zdrojový text tohoto příkladu se od příkladu uvedeného minule odlišuje pouze ve volání metod QInputDialog.setOkButtonText a QInputDialog.setCancelButtonText:
#!/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): quitButton = self.prepareQuitButton() textInputDialogButton = self.prepareButton( "Text Input", self.textInputDialogHandler) # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(textInputDialogButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def textInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.TextInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Text input:") dialog.setTextValue("default text") # nastavení textů tlačítek dialog.setCancelButtonText(u"Zrušit") dialog.setOkButtonText(u"Potvrdit") # zobrazení dialogu a čekání na uživatelský vstup result = dialog.exec_() # zpracování a zobrazení výsledků text = dialog.textValue() message = "Entered text: '{t}'\nClicked on: {c}".format( t=text, c="Ok" if result == 1 else "Cancel") # zobrazení dialogu s informací o vstupu od uživatele self.showMessageBox(message) def prepareButton(self, label, handler): # tlačítko button = QtGui.QPushButton(label, self) button.resize(button.sizeHint()) # navázání akce na signál button.clicked.connect(handler) return button def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showMessageBox(self, text): # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení textu a ikony, které se mají zobrazit msgBox.setText(text) msgBox.setIcon(QtGui.QMessageBox.Information) # zobrazení dialogu msgBox.exec_() # 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("QInputDialog") # 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()
8. Vstupní dialog zobrazený bez tlačítek (pouze s polem pro zadání údajů uživatelem)
Standardní vstupní dialog QInputDialog je dokonce možné nakonfigurovat i takovým způsobem, aby se v něm nezobrazily žádné další ovládací prvky kromě vstupního textového políčka, kombo boxu nebo seznamu prvků. Pokud skutečně nevyžadujete použití dalších ovládacích prvků, tedy především tlačítek, je možné dialog nakonfigurovat následujícím způsobem:
QInputDialog.setInputMode(QtGui.QInputDialog.TextInput) QInputDialog.setOption(QtGui.QInputDialog.NoButtons, True)
Obrázek 10: Vstupní dialog zobrazený bez tlačítek.
Metoda, která zajistí konfiguraci dialogu pro vstup textu (bez tlačítek), bude vypadat takto:
def textInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.TextInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Text input:") dialog.setTextValue("default text") # dialog bude zobrazen bez tlačítek dialog.setOption(QtGui.QInputDialog.NoButtons, True)
Obrázek 11: Další varianta vstupního dialogu zobrazeného bez tlačítek.
Podobně je možné nakonfigurovat dialog pro vstup celého čísla:
def integerInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.IntInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Integer input:") dialog.setIntMinimum(10) dialog.setIntMaximum(20) # dialog bude zobrazen bez tlačítek dialog.setOption(QtGui.QInputDialog.NoButtons, True)
Takto nakonfigurovaný dialog lze zavřít klávesou Esc nebo pomocí myši.
9. Pátý demonstrační příklad – vstupní dialog bez tlačítek
V pátém demonstračním příkladu je ukázán způsob zobrazení vstupního dialogu bez tlačítek. Dialog tedy obsahuje pouze vstupní textové pole a je ho možné zavřít buď klávesou Esc nebo myší. Ovšem ve standardním nastavení nebude fungovat klávesa Enter/Return, takže vlastně dialog vždy vrátí hodnotu „Cancel“ (zadaný text samozřejmě není ztracen, protože ho lze přečíst metodou QInputDialog.textValue, nezávisle na tom, jakým způsobem byl dialog zavřen:
#!/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): quitButton = self.prepareQuitButton() textInputDialogButton = self.prepareButton( "Text Input", self.textInputDialogHandler) # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(textInputDialogButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def textInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.TextInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Text input:") dialog.setTextValue("default text") # dialog bude zobrazen bez tlačítek dialog.setOption(QtGui.QInputDialog.NoButtons, True) # zobrazení dialogu a čekání na uživatelský vstup result = dialog.exec_() # zpracování a zobrazení výsledků text = dialog.textValue() message = "Entered text: '{t}'\nClicked on: {c}".format( t=text, c="Ok" if result == 1 else "Cancel") # zobrazení dialogu s informací o vstupu od uživatele self.showMessageBox(message) def prepareButton(self, label, handler): # tlačítko button = QtGui.QPushButton(label, self) button.resize(button.sizeHint()) # navázání akce na signál button.clicked.connect(handler) return button def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showMessageBox(self, text): # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení textu a ikony, které se mají zobrazit msgBox.setText(text) msgBox.setIcon(QtGui.QMessageBox.Information) # zobrazení dialogu msgBox.exec_() # 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("QInputDialog") # 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()
10. Navázání handlerů na událost generovanou při změně údajů ve vstupním dialogu
V případě, že je vstupní dialog zobrazen bez tlačítek Ok a Cancel, je většinou nutné, aby aplikace reagovala přímo na zadávané hodnoty. Představme si například webový prohlížeč, v němž se v reálném čase mohou vyhledávat části textu atd. U dialogů odvozených od třídy QInputDialog lze zaregistrovat handlery pro šest typů událostí, ovšem vždy pouze dvě události mají skutečný smysl. Které dvě události to budou záleží na tom, jaký typ vstupu je nakonfigurován – zda lze zadat libovolný text, celé číslo či číslo reálné:
Událost | Předaný parametr |
---|---|
intValueChanged | změněná hodnota typu int |
intValueSelected | vybraná hodnota typu int |
doubleValueChanged | změněná hodnota typu double |
doubleValueSelected | vybraná hodnota typu double |
textValueChanged | změněný řetězec |
textValueSelected | vybraný řetězec |
Navázání handleru na událost (přes signál) se provede snadno. Příkladem může být nejběžnější dialog určený pro vstup běžného textu, v němž potřebujeme reagovat na každou změnu textu v dialogu (přidání dalšího znaku, vymazání znaku, použití schránky apod.):
# při změně textu se zavolá handler dialog.textValueChanged.connect(self.onTextValueChanged)
Vytvoření dialogu s navázáním události na handler bude vypadat například následovně:
def registerTextInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.TextInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Text input:") dialog.setTextValue("") # dialog bude zobrazen bez tlačítek dialog.setOption(QtGui.QInputDialog.NoButtons, True) # při změně textu se zavolá handler dialog.textValueChanged.connect(self.onTextValueChanged)
Samotný handler může například změnit hodnotu zobrazenou v hlavním okně aplikace:
def onTextValueChanged(self, text): """Handler zavolaný při změně textu ve vstupním dialogu.""" self.enteredTextLabel.setText(text)
Obrázek 12: Text labelu na hlavním okně reflektuje změny prováděné uživatelem ve vstupním dialogu.
11. Šestý demonstrační příklad – reakce na průběžnou změnu údajů ve vstupním dialogu
V dnešním šestém demonstračním příkladu je ukázáno, jak lze jednoduše naprogramovat handler reagující na změnu údajů ve vstupním dialogu. Samotný handler je realizován metodou nazvanou onTextValueChanged, jeho registrace a navázání na signál je provedeno v metodě pojmenované textInputDialogHandler. Následuje výpis zdrojového kódu tohoto příkladu:
#!/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): quitButton = self.prepareQuitButton() textInputDialogButton = self.prepareButton( "Text Input", self.textInputDialogHandler) self.enteredTextLabel = QtGui.QLabel("") # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(self.enteredTextLabel) topLayout.addWidget(textInputDialogButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def onTextValueChanged(self, text): """Handler zavolaný při změně textu ve vstupním dialogu.""" self.enteredTextLabel.setText(text) def textInputDialogHandler(self): # vytvoření a konfigurace vstupního dialogu dialog = QtGui.QInputDialog(self) dialog.setInputMode(QtGui.QInputDialog.TextInput) # nastavení výchozího stavu dialogu dialog.setLabelText("Text input:") dialog.setTextValue("") # dialog bude zobrazen bez tlačítek dialog.setOption(QtGui.QInputDialog.NoButtons, True) # při změně textu se zavolá handler dialog.textValueChanged.connect(self.onTextValueChanged) # zobrazení dialogu a čekání na uživatelský vstup result = dialog.exec_() # zpracování a zobrazení výsledků text = dialog.textValue() message = "Entered text: '{t}'\nClicked on: {c}".format( t=text, c="Ok" if result == 1 else "Cancel") # zobrazení dialogu s informací o vstupu od uživatele self.showMessageBox(message) def prepareButton(self, label, handler): # tlačítko button = QtGui.QPushButton(label, self) button.resize(button.sizeHint()) # navázání akce na signál button.clicked.connect(handler) return button def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showMessageBox(self, text): # vytvoření dialogu msgBox = QtGui.QMessageBox() # nastavení textu a ikony, které se mají zobrazit msgBox.setText(text) msgBox.setIcon(QtGui.QMessageBox.Information) # zobrazení dialogu msgBox.exec_() # 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("QInputDialog") # 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()
12. Barvová paleta vybraná uživatelem přes QColorDialog
Již minule jsme si popsali dialog určený pro výběr barvy. Ovšem tento dialog má ještě jednu důležitou vlastnost – může si totiž „pamatovat“ uživatelem vybrané barvy, které tak tvoří relativně malou barvovou paletu (zapamatovaná paleta je permanentní, přežije i restart systému). Vypadá to následovně:
Obrázek 13: Dialog pro výběr barvy s prázdnou uživatelskou barvovou paletou.
Obrázek 14: Dialog pro výběr barvy s nastavenou uživatelskou barvovou paletou.
Barvová paleta je interně uložena v třídním atributu třídy QColorDialog a je možné se k ní dostat po jednotlivých barvách zadáním indexu od 0 do 15:
for index in range(0, 16): color = QtGui.QColorDialog.customColor(index)
Výsledkem je kód barvy, který je možné použít například následujícím způsobem:
def redrawColorBoxes(self): # vytvoření objektu typu QPainter s předáním # reference na "pokreslovaný" objekt qp = QtGui.QPainter(self.image) # vykreslení čtverců s barvami získanými z dialogu index = 0 for row in range(0, 2): for column in range(0, 8): color = QtGui.QColorDialog.customColor(index) x = 10 + column * (MainWindowContent.SQUARE_SIZE + 10) y = 10 + row * (MainWindowContent.SQUARE_SIZE + 10) drawRectangleUsingBrush(qp, color, x, y, MainWindowContent.SQUARE_SIZE, MainWindowContent.SQUARE_SIZE) index += 1 # vytvoření instance třídy QPixmap z objektu QImage self.pixmap = QtGui.QPixmap.fromImage(self.image)
Vykreslení obdélníků vybranou barvou je realizováno touto funkcí:
# funkce pro vykreslení obdélníku zadanou barvou def drawRectangleUsingBrush(qPainter, color, x, y, width, height): # změna barvy štětce brush = QtGui.QBrush(QtGui.QColor(color)) brush.setStyle(QtCore.Qt.SolidPattern) qPainter.setBrush(brush) # vykreslení obdélníku qPainter.drawRect(x, y, width, height)
13. Sedmý demonstrační příklad – zobrazení barvové palety vybrané uživatelem a zapamatované v QColorDialogu
Výše popsaná statická metoda QColorDialog.customColor je použita v dnešním sedmém demonstračním příkladu. Po jeho spuštění se zobrazí hlavní okno, které mj. obsahuje i šestnáct barevných obdélníků ukazujících uživatelskou paletu. Výchozí barvy vypadají takto:
Obrázek 15: Výchozí stav hlavního okna aplikace s uživatelskou barvovou paletou.
Po zobrazení dialogu pro výběr barvy si můžete nastavit vlastní barvovou paletu, takže se ihned po zavření dialogu hlavní okno změní, například následovně:
Obrázek 16: Barvová paleta poté, co do ní uživatel vložil další barvy.
Následuje výpis zdrojového kódu tohoto demonstračního příkladu:
#!/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 # funkce pro vykreslení obdélníku zadanou barvou def drawRectangleUsingBrush(qPainter, color, x, y, width, height): # změna barvy štětce brush = QtGui.QBrush(QtGui.QColor(color)) brush.setStyle(QtCore.Qt.SolidPattern) qPainter.setBrush(brush) # vykreslení obdélníku qPainter.drawRect(x, y, width, height) # nový widget bude odvozen od obecného widgetu class MainWindowContent(QtGui.QWidget): # rozměry rastrového obrázku IMAGE_WIDTH = 330 IMAGE_HEIGHT = 90 SQUARE_SIZE = 30 def __init__(self): # zavoláme konstruktor předka super(MainWindowContent, self).__init__() self.prepareImage() self.redrawColorBoxes() # konfigurace GUI + přidání widgetu do okna self.prepareGUI() def prepareImage(self): # vytvoření instance třídy QImage self.image = QtGui.QImage(MainWindowContent.IMAGE_WIDTH, MainWindowContent.IMAGE_HEIGHT, QtGui.QImage.Format_RGB32) # vymazání obrázku self.image.fill(0) def redrawColorBoxes(self): # vytvoření objektu typu QPainter s předáním # reference na "pokreslovaný" objekt qp = QtGui.QPainter(self.image) # vykreslení čtverců s barvami získanými z dialogu index = 0 for row in range(0, 2): for column in range(0, 8): color = QtGui.QColorDialog.customColor(index) x = 10 + column * (MainWindowContent.SQUARE_SIZE + 10) y = 10 + row * (MainWindowContent.SQUARE_SIZE + 10) drawRectangleUsingBrush(qp, color, x, y, MainWindowContent.SQUARE_SIZE, MainWindowContent.SQUARE_SIZE) index += 1 # vytvoření instance třídy QPixmap z objektu QImage self.pixmap = QtGui.QPixmap.fromImage(self.image) def prepareGUI(self): quitButton = self.prepareQuitButton() colorDialogButton = self.prepareColorDialogButton() # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # vytvoření návěští self.colorPalette = QtGui.QLabel("test") # přiřazení rastrového obrázku k návěští self.colorPalette.setPixmap(self.pixmap) # umístění widgetů do okna topLayout.addWidget(self.colorPalette) topLayout.addWidget(colorDialogButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareColorDialogButton(self): # tlačítko colorDialogButton = QtGui.QPushButton('Select color', self) colorDialogButton.resize(colorDialogButton.sizeHint()) # navázání akce na signál colorDialogButton.clicked.connect(self.showColorDialog) return colorDialogButton def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showColorDialog(self): colorDialog = QtGui.QColorDialog() colorDialog.setCurrentColor(QtGui.QColor("#aabbcc")) result = colorDialog.exec_() self.redrawColorBoxes() self.colorPalette.setPixmap(self.pixmap) # 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("QColorDialog colors") # 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()
14. Standardní dialog pro výběr souboru či adresáře
Již minule jsme se zmínili o tom, že knihovna PySide programátorům nabízí i standardní dialogy určené pro výběr souborů či adresářů pro otevření či naopak pro zápis. V nejjednodušším případě je použití těchto dialogů velmi snadné, zejména tehdy, pokud uživateli nabídneme libovolný soubor k otevření (nebudeme ho tedy omezovat jen na určité typy souborů) a pokud nezadáme výchozí cestu.
Příkladem může být dialog pro otevření souboru, přičemž výchozí adresář bude nastaven na pwd
. Prvním parametrem je reference na hlavní okno aplikace, druhý parametr je textový popisek dialogu a třetím parametrem pak cesta (může a pro jistotu by měla být v Unicode):
fileName = QtGui.QFileDialog.getOpenFileName(self, "Open file", u".")
Obrázek 17: Standardní dialog pro výběr souboru.
Další možnosti těchto typů dialogů si popíšeme v navazujícím článku.
15. Osmý demonstrační příklad – výběr souboru pro otevření souboru
Osmý a současně i poslední demonstrační příklad, s nímž se dnes setkáme, po svém spuštění zobrazí okno, z něhož je možné spustit dialog určený pro otevření souboru, resp. přesněji řečeno pro výběr souboru z prakticky libovolného adresáře na disku. Po výběru souboru se jeho celá cesta zobrazí v informačním dialogu:
Obrázek 18: Zobrazení cesty k vybranému souboru.
Celý zdrojový kód tohoto příkladu 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): quitButton = self.prepareQuitButton() openFileButton = self.prepareOpenFileButton() # vytvoření správce geometrie topLayout = QtGui.QVBoxLayout() # umístění widgetů do okna topLayout.addWidget(openFileButton) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareOpenFileButton(self): # tlačítko openFileButton = QtGui.QPushButton('Open file...', self) openFileButton.resize(openFileButton.sizeHint()) # navázání akce na signál openFileButton.clicked.connect(self.showOpenFileDialog) return openFileButton def prepareQuitButton(self): # tlačítko quitButton = QtGui.QPushButton('Quit', self) quitButton.resize(quitButton.sizeHint()) # navázání akce na signál quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit) return quitButton def showOpenFileDialog(self): fileName = QtGui.QFileDialog.getOpenFileName(self, "Open file", u".") # vytvoření dialogu msgBox = QtGui.QMessageBox() msgBox.setText(u'Vybraný soubor\n{f}'.format(f=fileName)) msgBox.setIcon(QtGui.QMessageBox.Information) msgBox.exec_() # 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("QMessageBox") # 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()
16. Repositář s demonstračními příklady
Zdrojové kódy všech devíti 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:
17. Odkazy na Internetu
- PySide 1.2.1 documentation
https://pyside.github.io/docs/pyside/index.html - QAbstractSlider
https://pyside.github.io/docs/pyside/PySide/QtGui/AbstractSlider.html - QScrollBar
https://pyside.github.io/docs/pyside/PySide/QtGui/ScrollBar.html - QSlider
https://pyside.github.io/docs/pyside/PySide/QtGui/Slider.html - QDial
https://pyside.github.io/docs/pyside/PySide/QtGui/Dial.html - QImage
https://pyside.github.io/docs/pyside/PySide/QtGui/QImage.html - QPixmap
https://pyside.github.io/docs/pyside/PySide/QtGui/QPixmap.html - QBitmap
https://pyside.github.io/docs/pyside/PySide/QtGui/QBitmap.html - QPaintDevice
https://pyside.github.io/docs/pyside/PySide/QtGui/QPaintDevice.html - QPicture
https://pyside.github.io/docs/pyside/PySide/QtGui/QPicture.html - QPainter
https://pyside.github.io/docs/pyside/PySide/QtGui/QPainter.html - QPainterPath
https://pyside.github.io/docs/pyside/PySide/QtGui/QPainterPath.html - QGradient
https://pyside.github.io/docs/pyside/PySide/QtGui/QGradient.html - QLinearGradient
https://pyside.github.io/docs/pyside/PySide/QtGui/QLinearGradient.html - QRadialGradient
https://pyside.github.io/docs/pyside/PySide/QtGui/QRadialGradient.html - QTableWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QTableWidget.html - QTableWidgetItem
https://pyside.github.io/docs/pyside/PySide/QtGui/QTableWidgetItem.html - QTreeWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QTreeWidget.html - QTreeWidgetItem
https://pyside.github.io/docs/pyside/PySide/QtGui/QTreeWidgetItem.html - Afinní zobrazení
https://cs.wikipedia.org/wiki/Afinn%C3%AD_zobrazen%C3%AD - 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/ - Drawing in PySide
http://zetcode.com/gui/pysidetutorial/drawing/ - Qt Core
https://pyside.github.io/docs/pyside/PySide/QtCore/Qt.html - QLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QLayout.html - QValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QValidator.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 - QAction
https://pyside.github.io/docs/pyside/PySide/QtGui/QAction.html - QDialog
https://pyside.github.io/docs/pyside/PySide/QtGui/QDialog.html - QMessageBox
https://pyside.github.io/docs/pyside/PySide/QtGui/QMessageBox.html - QErrorMessage
https://pyside.github.io/docs/pyside/PySide/QtGui/QErrorMessage.html - QInputDialog
https://pyside.github.io/docs/pyside/PySide/QtGui/QInputDialog.html - QColorDialog
https://pyside.github.io/docs/pyside/PySide/QtGui/QColorDialog.html - QListWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QListWidget.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/ - QLineEdit
https://pyside.github.io/docs/pyside/PySide/QtGui/QLineEdit.html - QTextEdit
https://pyside.github.io/docs/pyside/PySide/QtGui/QTextEdit.html - QValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QValidator.html - QIntValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QIntValidator.html - QRegExpValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QRegExpValidator.html - 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/