Obsah
1. Tvorba GUI v Pythonu: použití kaskádových stylů v PySide
2. Použití vlastních kaskádových stylů pro úpravu stylu celé aplikace
3. První demonstrační příklad – použití vlastních kaskádových stylů přímo v aplikaci
4. Galerie: screenshoty prvního příkladu při použití všech základních podporovaných stylů
5. Využití externích kaskádových stylů
6. Význam jednotlivých vlastností deklarovaných v souboru stylesheet.css
7. Druhý demonstrační příklad – načtení externího kaskádového stylu
8. Galerie: screenshoty druhého příkladu při použití všech základních podporovaných stylů
9. Selektory v kaskádních stylech i v programovém kódu
10. Třetí demonstrační příklad – použití selektorů pro výběr typu tlačítek
11. Galerie: screenshoty třetího příkladu při použití všech základních podporovaných stylů
12. Pseudotřídy: styly tlačítek ve chvíli stisku popř. když je nad nimi umístěn kurzor myši
13. Nastavení pozadí u vybraných prvků GUI
14. Čtvrtý demonstrační příklad – použití různých kaskádových stylů (pseudotřídy, pozadí prvků, …)
15. Galerie: screenshoty čtvrtého příkladu při použití všech základních podporovaných stylů
16. Nastavení stylů zaškrtávacích tlačítek
17. Pátý demonstrační příklad – vlastní styl zaškrtávacích tlačítek
18. Galerie: screenshoty pátého příkladu při použití všech základních podporovaných stylů
19. Repositář s demonstračními příklady
1. Tvorba GUI v Pythonu: použití kaskádových stylů v PySide
V předchozí části seriálu o tvorbě aplikací s grafickým uživatelským rozhraním v Pythonu jsme si ukázali některé možnosti změny stylů vykreslování jak jednotlivých ovládacích prvků, tak i celých dialogů a aplikací s využitím knihovny PySide. Připomeňme si, že tato knihovna na většině podporovaných platforem nabízí šest základních stylů ovlivňujících vzhled a do určité míry i chování widgetů. Jedná se o tyto styly, které je možné v případě potřeby nastavit pomocí parametru příkazové řádky -style nebo programově při běhu aplikace:
- CDE
- Cleanlooks
- GTK+
- Motif
- Plastique
- Windows

Obrázek 1: Ovládací prvky vykreslené při použití standardního stylu nazvaného Plastique.
Kromě toho je však možné změnit styl vykreslování s využitím kaskádových stylů neboli CSS (Cascading Style Sheet). I o této možnosti jsme se minule zmínili; dnes si však použití kaskádových stylů vyzkoušíme na větším množství demonstračních příkladů, a to včetně speciálních voleb platných jen pro některý typ ovládacích prvků (zaškrtávací tlačítko, scrollovací oblast atd.).

Obrázek 2: Změna vzhledu ovládacích prvků s využitím kaskádových stylů.
2. Použití vlastních kaskádových stylů pro úpravu stylu celé aplikace
Zdánlivě nejjednodušším způsobem použití kaskádních stylů je vytvoření řetězce obsahujícího příslušná pravidla s následným zavoláním metody QMainWindow.setStyleSheet(), které se tento řetězec předá. Způsob programového nastavení vlastních kaskádových stylů může vypadat následovně (úplný kód je uveden v navazující kapitole):
# nový widget bude odvozen od obecného hlavního okna class MainWindow(QtGui.QMainWindow): def __init__(self): ... ... ... def prepareGUI(self): ... ... ... styleSheet = """ QWidget {border-radius: 10px; border: 1px solid gray;} QPushButton { color: #404040; background-color: rgba(188, 188, 188, 50); font-size: 18px; border: 1px solid black; outline-color: red; } QLabel { color: #404040; background-color: rgba(255, 188, 20, 0); border: 0px; font-size: 14px; } QToolBar { margin: 10px; } QLineEdit { background-color: #c0ffc0; selection-background-color: red; selection-color: white; font-size: 24px;} """ self.setStyleSheet(styleSheet) ... ... ...
Tento způsob však má několik nevýhod, zejména pak:
- Není možné jednoduše nahradit jeden styl za jiný (například jen pro jednu vybranou platformu). Ztrácíme tedy flexibilitu.
- Tím, že je CSS zapsán v obecném řetězci, přijdeme o možnosti nabízené moderními textovými editory (zvýraznění syntaxe, automatické doplňování atd.)
- Taktéž přijdeme o možnost použít validátory a lintery CSS (popravdě ale velké množství validátorů bude hlásit chyby z toho důvodu, že se používají ve světě WWW neznámé vlastnosti/properties).

Obrázek 3: Změna stylu vykreslení ovládacích prvků aplikace, a to včetně hlavního menu, s využitím kaskádových stylů.
3. První demonstrační příklad – použití vlastních kaskádových stylů přímo v aplikaci
Použití řetězce obsahujícího programátorem definované kaskádové styly (které jsou tak zabudovány přímo do aplikace), je ukázáno v dnešním prvním demonstračním příkladu, jehož zdrojový kód je zobrazen pod tímto odstavcem. Povšimněte si, že se nejedná o příliš flexibilní a vlastně ani o dobře čitelné či udržovatelné řeš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): # tlačítka, na které je navázán handler quitButton = self.prepareQuitButton() # další tlačítka button1 = self.prepareButtonWithBackground("#e08080") button2 = self.prepareButtonWithBackground("lightblue") button3 = self.prepareButtonWithBackground("yellow") # ostatní widgety lineEdit = self.prepareLineEdit() # vytvoření správců geometrie topLayout = QtGui.QVBoxLayout() # vložení widgetů do okna topLayout.addWidget(button1) topLayout.addWidget(button2) topLayout.addWidget(button3) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(lineEdit) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareLineEdit(self): # jednořádkové vstupní textové pole lineEdit = QtGui.QLineEdit(self) # naplnění textového pole textem lineEdit.setText(u"příliš žluťoučký kůň úpěl ďábelské ódy") return lineEdit def prepareButtonWithBackground(self, background): # tlačítko s popisem button = QtGui.QPushButton(background, self) # nastavení stylu styleSheet = "background-color: {background}".format(background=background) button.setStyleSheet(styleSheet) button.resize(button.sizeHint()) return button def prepareQuitButton(self): # tlačítko s popisem 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 # 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(400, 300) self.setWindowTitle("Custom Stylesheets") # hlavní menu menubar = self.menuBar() # příkaz File/Quit fileQuitItem = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) fileQuitItem.triggered.connect(self.close) fileQuitItem.setStatusTip('Quit the application') fileQuitItem.setShortcut('Ctrl+Q') # položka File v hlavním menu fileMenu = menubar.addMenu('&File') fileMenu.addAction(fileQuitItem) # položka Style v hlavním menu styleMenu = menubar.addMenu('&Style') # jednotlivé položky menu s nabízenými styly for key in QtGui.QStyleFactory.keys(): styleMenuItem = QtGui.QAction(key, self) styleMenuItem.triggered.connect(lambda key=key: self.setStyle(key)) styleMenu.addAction(styleMenuItem) # tlačítko Quit quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) quitAction.triggered.connect(self.close) quitAction.setStatusTip('Quit the application') # tlačítko About aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'), '&About', self) aboutAction.triggered.connect(self.aboutDialog) aboutAction.setStatusTip('About this application') # nástrojový pruh self.toolbar = self.addToolBar('title') # přidání tlačítek na nástrojový pruh self.toolbar.addAction(quitAction) self.toolbar.addAction(aboutAction) # vložení komponenty do okna self.setCentralWidget(MainWindowContent()) styleSheet = """ QWidget {border-radius: 10px; border: 1px solid gray;} QPushButton { color: #404040; background-color: rgba(188, 188, 188, 50); font-size: 18px; border: 1px solid black; outline-color: red; } QLabel { color: #404040; background-color: rgba(255, 188, 20, 0); border: 0px; font-size: 14px; } QToolBar { margin: 10px; } QLineEdit { background-color: #c0ffc0; selection-background-color: red; selection-color: white; font-size: 24px;} """ self.setStyleSheet(styleSheet) def setStyle(self, styleName): # nastavení vybraného stylu QtGui.QApplication.setStyle(styleName) def aboutDialog(self): msgBox = QtGui.QMessageBox() msgBox.setText('About:\n...\n...\n...') msgBox.setIcon(QtGui.QMessageBox.Information) msgBox.exec_() def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): # QtGui.QApplication.setStyle("plastique") # QtGui.QApplication.setStyleSheet("background-color: #407040; color: white") app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
4. Galerie: screenshoty prvního příkladu při použití všech základních podporovaných stylů
Podívejme se nyní, jak se změní okno prvního demonstračního příkladu při výběru některého ze šesti dostupných standardních stylů. Ze screenshotů je patrné, že kaskádní styly nastavené programátorem mají větší prioritu, ovšem změna stylu se projeví například na tvaru handleru nástrojového pruhu atd.:

Obrázek 4: Okno prvního demonstračního příkladu po výběru standardního stylu Windows.

Obrázek 5: Okno prvního demonstračního příkladu po výběru standardního stylu Motif.

Obrázek 6: Okno prvního demonstračního příkladu po výběru standardního stylu CDE.

Obrázek 7: Okno prvního demonstračního příkladu po výběru standardního stylu Plastique.

Obrázek 8: Okno prvního demonstračního příkladu po výběru standardního stylu GTK+.

Obrázek 9: Okno prvního demonstračního příkladu po výběru standardního stylu Cleanlooks.
5. Využití externích kaskádových stylů
Podívejme se nyní na způsob využití externích kaskádových stylů, což je řešení, které nám přinese jak lepší flexibilitu, tak i možnost editovat soubor s kaskádovými styly způsobem odpovídajícím 21.století. Nejprve vytvoříme samostatný soubor nazvaný stylesheet.css. Obsah tohoto souboru bude následující:
QWidget { border-radius: 10px; border: 1px solid gray; } QPushButton { color: #404040; background-color: rgba(188, 188, 188, 50); font-size: 18px; border: 1px solid black; outline-color: red; } QLabel { color: #404040; background-color: rgba(255, 188, 20, 0); border: 0px; font-size: 14px; } QToolBar { margin: 10px; } QLineEdit { background-color: #c0ffc0; selection-background-color: red; selection-color: white; font-size: 24px; }
O načtení kaskádového stylu uloženého v externím souboru s následným nastavením stylů vykreslování se postará následující trojice programových řádků:
with open("stylesheet.css") as fin: styleSheet = fin.read() self.setStyleSheet(styleSheet)

Obrázek 10: Editace souboru stylesheet.css v programátorském editoru se zvýrazněním syntaxe.
6. Význam jednotlivých vlastností deklarovaných v souboru stylesheet.css
Podívejme se nyní podrobněji na jednotlivé vlastnosti, které jsou deklarovány v souboru stylesheet.css. V prvním bloku jsou deklarovány vlastnosti platné pro všechny ovládací prvky, samozřejmě s výjimkou těch prvků, u nichž obecnou vlastnost „přebijeme“ vlastností konkrétní. Je zde deklarováno, že ovládací prvky mají mít šedý okraj široký jeden pixel a rohy mají být zaobleny obloukem s poloměrem deseti pixelů (nutno říci, že ne všechny widgety okraj obsahují či podporují):
QWidget { border-radius: 10px; border: 1px solid gray; }
Dále deklarujeme vlastnosti zobrazení platné pro klasická tlačítka. Nastavena je barva textu, barva pozadí (s průhledností), velikost písma (tj. popisků tlačítek) a v neposlední řade i vlastnosti okraje. Ostatně právě zde „přebíjíme“ původní šedou barvu barvou černou:
QPushButton { color: #404040; background-color: rgba(188, 188, 188, 50); font-size: 18px; border: 1px solid black; outline-color: red; }
Stejným způsobem měníme vlastnost popisků (labels). Povšimněte si, že šířka okraje je nastavena na 0 pixelů, tj. okraj nebude zobrazen:
QLabel { color: #404040; background-color: rgba(255, 188, 20, 0); border: 0px; font-size: 14px; }
U nástrojového pruhu je zvětšena mezera mezi plochou vyhrazenou pro tento widget a skutečně použitou plochou widgetu. Ze všech stran jsme vytvořili prázdný prostor o šířce deseti pixelů:
QToolBar { margin: 10px; }
A konečně měníme i vlastnosti jednořádkového textového pole. Zde stojí za povšimnutí fakt, že je možné modifikovat i barvu vybraného textu popř. barvu samotného výběru:
QLineEdit { background-color: #c0ffc0; selection-background-color: red; selection-color: white; font-size: 24px; }

Obrázek 11: Modifikovaná barva textu a výběru.
7. Druhý demonstrační příklad – načtení externího kaskádového stylu
Implementace načtení externího kaskádového stylu je ukázána v dnešním druhém demonstračním příkladu, jehož zdrojový kód je zobrazen 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 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čítka, na které je navázán handler quitButton = self.prepareQuitButton() # další tlačítka button1 = self.prepareButtonWithBackground("#e08080") button2 = self.prepareButtonWithBackground("lightblue") button3 = self.prepareButtonWithBackground("yellow") # ostatní widgety lineEdit = self.prepareLineEdit() # vytvoření správců geometrie topLayout = QtGui.QVBoxLayout() # vložení widgetů do okna topLayout.addWidget(button1) topLayout.addWidget(button2) topLayout.addWidget(button3) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(lineEdit) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareLineEdit(self): # jednořádkové vstupní textové pole lineEdit = QtGui.QLineEdit(self) # naplnění textového pole textem lineEdit.setText(u"příliš žluťoučký kůň úpěl ďábelské ódy") return lineEdit def prepareButtonWithBackground(self, background): # tlačítko s popisem button = QtGui.QPushButton(background, self) # nastavení stylu styleSheet = "background-color: {background}".format(background=background) button.setStyleSheet(styleSheet) button.resize(button.sizeHint()) return button def prepareQuitButton(self): # tlačítko s popisem 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 # 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(400, 300) self.setWindowTitle("Custom Stylesheets") # hlavní menu menubar = self.menuBar() # příkaz File/Quit fileQuitItem = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) fileQuitItem.triggered.connect(self.close) fileQuitItem.setStatusTip('Quit the application') fileQuitItem.setShortcut('Ctrl+Q') # položka File v hlavním menu fileMenu = menubar.addMenu('&File') fileMenu.addAction(fileQuitItem) # položka Style v hlavním menu styleMenu = menubar.addMenu('&Style') # jednotlivé položky menu s nabízenými styly for key in QtGui.QStyleFactory.keys(): styleMenuItem = QtGui.QAction(key, self) styleMenuItem.triggered.connect(lambda key=key: self.setStyle(key)) styleMenu.addAction(styleMenuItem) # tlačítko Quit quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) quitAction.triggered.connect(self.close) quitAction.setStatusTip('Quit the application') # tlačítko About aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'), '&About', self) aboutAction.triggered.connect(self.aboutDialog) aboutAction.setStatusTip('About this application') # nástrojový pruh self.toolbar = self.addToolBar('title') # přidání tlačítek na nástrojový pruh self.toolbar.addAction(quitAction) self.toolbar.addAction(aboutAction) # vložení komponenty do okna self.setCentralWidget(MainWindowContent()) with open("stylesheet.css") as fin: styleSheet = fin.read() self.setStyleSheet(styleSheet) def setStyle(self, styleName): # nastavení vybraného stylu QtGui.QApplication.setStyle(styleName) def aboutDialog(self): msgBox = QtGui.QMessageBox() msgBox.setText('About:\n...\n...\n...') msgBox.setIcon(QtGui.QMessageBox.Information) msgBox.exec_() def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): # QtGui.QApplication.setStyle("plastique") # QtGui.QApplication.setStyleSheet("background-color: #407040; color: white") app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
8. Galerie: screenshoty druhého příkladu při použití všech základních podporovaných stylů
V této kapitole je opět ukázána galerie screenshotů dnešního druhého demonstračního příkladu, tentokrát včetně ukázky stylu výběru textu v jednořádkovém vstupním textovém poli:

Obrázek 12: Okno druhého demonstračního příkladu po výběru standardního stylu Windows.

Obrázek 13: Okno druhého demonstračního příkladu po výběru standardního stylu Motif.

Obrázek 14: Okno druhého demonstračního příkladu po výběru standardního stylu CDE.

Obrázek 15: Okno druhého demonstračního příkladu po výběru standardního stylu Plastique.

Obrázek 16: Okno druhého demonstračního příkladu po výběru standardního stylu GTK+.

Obrázek 17: Okno druhého demonstračního příkladu po výběru standardního stylu Cleanlooks.
9. Selektory v kaskádních stylech i v programovém kódu
V kaskádních stylech jsme prozatím používali pouze selektory obsahující jména tříd, například QPushButton, QWidget atd. Tyto selektory odpovídají jménům značek v XML či HTML. Ovšem selektory mohou být i komplikovanější. Podívejme se na typický příklad. Budeme chtít vytvořit specifikace stylů pro tři typy tlačítek: potvrzovací tlačítko, tlačítko pro zobrazení nápovědy a konečně tlačítko, kterým se nějaká akce zakazuje popř. se jím zavírá dialogové okno. Takový styl není možné přiřadit celé třídě QPushButton, ovšem můžeme použít následující trik, který by v HTML/XML odpovídal identifikátoru prvku:
QPushButton#ok { background-color: #c0ffc0; } QPushButton#cancel { background-color: #ffc0c0; } QPushButton#help { background-color: #c0c0ff; }
Jak se přiřadí „ID“ k nějakému widgetu? Pro tento účel se používá metoda nazvaná poněkud jinak, než bychom očekávali: QObject.setObjectName, přičemž není nutné zaručit unikátnost widgetu s tímto jménem (na rozdíl od HTML/XML). Následující metoda vytvoří nové tlačítko a přiřadí mu příslušné jméno:
def prepareButtonWithClass(self, className): # tlačítko s popisem button = QtGui.QPushButton(className, self) # nastavení třídy button.setObjectName(className) button.resize(button.sizeHint()) return button
Příklad použití – vytvoření trojice tlačítek:
button1 = self.prepareButtonWithClass("ok") button2 = self.prepareButtonWithClass("cancel") button3 = self.prepareButtonWithClass("help")
10. Třetí demonstrační příklad – použití selektorů pro výběr typu tlačítek
Způsob použití selektorů pro výběr typu tlačítek (Ok, Cancel, …) je ukázán v dnešním třetím demonstračním příkladu, jehož úplný zdrojový kód je umístě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 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čítka, na které je navázán handler quitButton = self.prepareQuitButton() # další tlačítka button1 = self.prepareButtonWithClass("ok") button2 = self.prepareButtonWithClass("cancel") button3 = self.prepareButtonWithClass("help") # vytvoření správců geometrie topLayout = QtGui.QVBoxLayout() # vložení widgetů do okna topLayout.addWidget(button1) topLayout.addWidget(button2) topLayout.addWidget(button3) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareButtonWithClass(self, className): # tlačítko s popisem button = QtGui.QPushButton(className, self) # nastavení třídy button.setObjectName(className) button.resize(button.sizeHint()) return button def prepareQuitButton(self): # tlačítko s popisem 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 # 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(400, 300) self.setWindowTitle("Custom Stylesheets") # hlavní menu menubar = self.menuBar() # příkaz File/Quit fileQuitItem = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) fileQuitItem.triggered.connect(self.close) fileQuitItem.setStatusTip('Quit the application') fileQuitItem.setShortcut('Ctrl+Q') # položka File v hlavním menu fileMenu = menubar.addMenu('&File') fileMenu.addAction(fileQuitItem) # položka Style v hlavním menu styleMenu = menubar.addMenu('&Style') # jednotlivé položky menu s nabízenými styly for key in QtGui.QStyleFactory.keys(): styleMenuItem = QtGui.QAction(key, self) styleMenuItem.triggered.connect(lambda key=key: self.setStyle(key)) styleMenu.addAction(styleMenuItem) # tlačítko Quit quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) quitAction.triggered.connect(self.close) quitAction.setStatusTip('Quit the application') # tlačítko About aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'), '&About', self) aboutAction.triggered.connect(self.aboutDialog) aboutAction.setStatusTip('About this application') # nástrojový pruh self.toolbar = self.addToolBar('title') # přidání tlačítek na nástrojový pruh self.toolbar.addAction(quitAction) self.toolbar.addAction(aboutAction) # vložení komponenty do okna self.setCentralWidget(MainWindowContent()) with open("stylesheet2.css") as fin: styleSheet = fin.read() self.setStyleSheet(styleSheet) def setStyle(self, styleName): # nastavení vybraného stylu QtGui.QApplication.setStyle(styleName) def aboutDialog(self): msgBox = QtGui.QMessageBox() msgBox.setText('About:\n...\n...\n...') msgBox.setIcon(QtGui.QMessageBox.Information) msgBox.exec_() def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): # QtGui.QApplication.setStyle("plastique") # QtGui.QApplication.setStyleSheet("background-color: #407040; color: white") app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
11. Galerie: screenshoty třetího příkladu při použití všech základních podporovaných stylů
V této kapitole je ukázána galerie screenshotů dnešního třetího demonstračního příkladu:

Obrázek 18: Okno třetího demonstračního příkladu po výběru standardního stylu Windows.

Obrázek 19: Okno třetího demonstračního příkladu po výběru standardního stylu Motif.

Obrázek 20: Okno třetího demonstračního příkladu po výběru standardního stylu CDE.

Obrázek 21: Okno třetího demonstračního příkladu po výběru standardního stylu Plastique.

Obrázek 22: Okno třetího demonstračního příkladu po výběru standardního stylu GTK+.

Obrázek 23: Okno třetího demonstračního příkladu po výběru standardního stylu Cleanlooks.
12. Pseudotřídy: styly tlačítek ve chvíli stisku popř. když je nad nimi umístěn kurzor myši
Knihovna PySide podporuje i použití takzvaných pseudotříd při specifikaci selektorů těch ovládacích prvků, které mají vypadat odlišně například ve chvíli, kdy jsou vybrány, je nad nimi umístěn kurzor myši či se na ně kliklo. Podívejme se na příklad s našimi třemi tlačítky typu „ok“, „cancel“ a „help“. Základní „klidový“ styl těchto tlačítek již známe:
QPushButton#ok { background-color: #b0ffb0; } QPushButton#cancel { background-color: #ffb0b0; } QPushButton#help { background-color: #b0b0ff; }

Obrázek 24: Tlačítka ve výchozím stavu.
Pseudotřídou hover můžeme specifikovat pozadí tlačítek ve chvíli, kdy je nad nimi kurzor myši. Tlačítka uděláme nepatrně světlejší:
QPushButton#ok:hover { background-color: #d0ffd0; } QPushButton#cancel:hover { background-color: #ffd0d0; } QPushButton#help:hover { background-color: #d0d0ff; }

Obrázek 25: Nad jedním tlačítkem (Cancel) byl umístěn kurzor myši.
Pseudotřídou pressed pak specifikujeme pozadí tlačítek ve chvíli, kdy jsou stisknuta. V tomto případě budou tlačítka tmavší:
QPushButton#ok:pressed { background-color: #a0d0a0; } QPushButton#cancel:pressed { background-color: #d0a0a0; } QPushButton#help:pressed { background-color: #a0a0d0; }

Obrázek 26: Tlačítko (Cancel) bylo vybráno a stisknuto.
13. Nastavení pozadí u vybraných prvků GUI
U některých typů aplikací, které jsou například skinovatelné (multimediální přehrávače atd.) může být požadováno, aby vybrané ovládací prvky grafického uživatelského rozhraní zobrazovaly na svém pozadí rastrový obrázek. I to je samozřejmě možné zařídit, a to s využitím vlastnosti background-image. Té se předá adresa (většinou lokální) s obrázkem:
QMainWindow { background-image: url("pixmaps/voronoi.png"); }
14. Čtvrtý demonstrační příklad – použití různých kaskádových stylů (pseudotřídy, pozadí prvků, …)
Možnosti kaskádových stylů popsané ve dvanácté a třinácté kapitole jsou použity v dnešním čtvrtém demonstračním příkladu. Po jeho spuštění se zobrazí okno s trojicí tlačítek, přičemž tato tlačítka reagují změnou odstínu jak na pouhé najetí kurzorem myši, tak i na kliknutí. Pokud navíc namísto souboru stylesheet3.css použijete soubor stylesheet4, nastaví se i pozadí hlavního okna:
#!/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čítka, na které je navázán handler quitButton = self.prepareQuitButton() # další tlačítka button1 = self.prepareButtonWithClass("ok") button2 = self.prepareButtonWithClass("cancel") button3 = self.prepareButtonWithClass("help") # vytvoření správců geometrie topLayout = QtGui.QVBoxLayout() # vložení widgetů do okna topLayout.addWidget(button1) topLayout.addWidget(button2) topLayout.addWidget(button3) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareButtonWithClass(self, className): # tlačítko s popisem button = QtGui.QPushButton(className, self) # nastavení třídy button.setObjectName(className) button.resize(button.sizeHint()) return button def prepareQuitButton(self): # tlačítko s popisem 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 # 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(400, 300) self.setWindowTitle("Custom Stylesheets") # hlavní menu menubar = self.menuBar() # příkaz File/Quit fileQuitItem = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) fileQuitItem.triggered.connect(self.close) fileQuitItem.setStatusTip('Quit the application') fileQuitItem.setShortcut('Ctrl+Q') # položka File v hlavním menu fileMenu = menubar.addMenu('&File') fileMenu.addAction(fileQuitItem) # položka Style v hlavním menu styleMenu = menubar.addMenu('&Style') # jednotlivé položky menu s nabízenými styly for key in QtGui.QStyleFactory.keys(): styleMenuItem = QtGui.QAction(key, self) styleMenuItem.triggered.connect(lambda key=key: self.setStyle(key)) styleMenu.addAction(styleMenuItem) # tlačítko Quit quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) quitAction.triggered.connect(self.close) quitAction.setStatusTip('Quit the application') # tlačítko About aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'), '&About', self) aboutAction.triggered.connect(self.aboutDialog) aboutAction.setStatusTip('About this application') # nástrojový pruh self.toolbar = self.addToolBar('title') # přidání tlačítek na nástrojový pruh self.toolbar.addAction(quitAction) self.toolbar.addAction(aboutAction) # vložení komponenty do okna self.setCentralWidget(MainWindowContent()) with open("stylesheet3.css") as fin: styleSheet = fin.read() self.setStyleSheet(styleSheet) def setStyle(self, styleName): # nastavení vybraného stylu QtGui.QApplication.setStyle(styleName) def aboutDialog(self): msgBox = QtGui.QMessageBox() msgBox.setText('About:\n...\n...\n...') msgBox.setIcon(QtGui.QMessageBox.Information) msgBox.exec_() def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): # QtGui.QApplication.setStyle("plastique") # QtGui.QApplication.setStyleSheet("background-color: #407040; color: white") app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
15. Galerie: screenshoty čtvrtého příkladu při použití všech základních podporovaných stylů
Na následující šestici screenshotů si povšimněte jedné zajímavosti – u některých standardních stylů je možné nastavit pozadí nástrojového pruhu, kdežto u stylů jiných má nástrojový pruh pouze jednobarevné pozadí (popř. barvový přechod), ovšem nikoli rastrový obrázek:

Obrázek 27: Okno čtvrtého demonstračního příkladu po výběru standardního stylu Windows.

Obrázek 28: Okno čtvrtého demonstračního příkladu po výběru standardního stylu Motif.

Obrázek 29: Okno čtvrtého demonstračního příkladu po výběru standardního stylu CDE.

Obrázek 30: Okno čtvrtého demonstračního příkladu po výběru standardního stylu Plastique.

Obrázek 31: Okno čtvrtého demonstračního příkladu po výběru standardního stylu GTK+.

Obrázek 32: Okno čtvrtého demonstračního příkladu po výběru standardního stylu Cleanlooks.
16. Nastavení stylů zaškrtávacích tlačítek
Na závěr si ukažme, jak lze relativně snadno změnit styly zaškrtávacích tlačítek. Samotná ikona tlačítka má minimálně šest podob vzniklých těmito kombinacemi – zaškrtnuto/nezaškrtnuto, kurzor myši je/není nad tlačítkem, tlačítko je/není vybráno. Proto si připravíme šestici ikon:
Soubor | Ukázka ikony |
---|---|
checkbox_off_hover.png | ![]() |
checkbox_off.png | ![]() |
checkbox_off_pressed.png | ![]() |
checkbox_on_hover.png | ![]() |
checkbox_on.png | ![]() |
checkbox_on_pressed.png | ![]() |
Tyto ikony se opět vyberou s využitím pseudotříd. Povšimněte si, že je možné v selektoru specifikovat větší množství tříd:
QCheckBox::indicator:unchecked { image: url(icons/checkbox_off.png); } QCheckBox::indicator:unchecked:hover { image: url(icons/checkbox_off_hover.png); } QCheckBox::indicator:unchecked:pressed { image: url(icons/checkbox_off_pressed.png); } QCheckBox::indicator:checked { image: url(icons/checkbox_on.png); } QCheckBox::indicator:checked:hover { image: url(icons/checkbox_on_hover.png); } QCheckBox::indicator:checked:pressed { image: url(icons/checkbox_on_pressed.png); }
17. Pátý demonstrační příklad – vlastní styl zaškrtávacích tlačítek
V pátém a současně i dnešním posledním demonstračním příkladu je ukázáno, jakým způsobem je možné změnit styl vykreslování zaškrtávacích tlačítek, tj. ovládacích prvků představovaných instancemi třídy QCheckBox popř. instancemi potomků této třídy. Po spuštění příkladu si vyzkoušejte na zaškrtávací tlačítka klikat – mělo by postupně dojít k zobrazení všech šesti bitmapových obrázků zmíněných v předchozí kapitole:
#!/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čítka, na které je navázán handler quitButton = self.prepareQuitButton() # testovací zaškrtávací tlačítka testCheckBox1 = QtGui.QCheckBox("check box 1") testCheckBox2 = QtGui.QCheckBox("check box 2") # které tlačítko bude vybráno testCheckBox2.setChecked(True) # vytvoření správců geometrie topLayout = QtGui.QVBoxLayout() # vložení widgetů do okna topLayout.addWidget(testCheckBox1) topLayout.addWidget(testCheckBox2) topLayout.addWidget(QtGui.QLabel("")) topLayout.addWidget(quitButton) # nastavení správce geometrie a vložení všech komponent do okna self.setLayout(topLayout) def prepareQuitButton(self): # tlačítko s popisem 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 # 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(400, 300) self.setWindowTitle("Custom Stylesheets") # hlavní menu menubar = self.menuBar() # příkaz File/Quit fileQuitItem = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) fileQuitItem.triggered.connect(self.close) fileQuitItem.setStatusTip('Quit the application') fileQuitItem.setShortcut('Ctrl+Q') # položka File v hlavním menu fileMenu = menubar.addMenu('&File') fileMenu.addAction(fileQuitItem) # položka Style v hlavním menu styleMenu = menubar.addMenu('&Style') # jednotlivé položky menu s nabízenými styly for key in QtGui.QStyleFactory.keys(): styleMenuItem = QtGui.QAction(key, self) styleMenuItem.triggered.connect(lambda key=key: self.setStyle(key)) styleMenu.addAction(styleMenuItem) # tlačítko Quit quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'), '&Quit', self) quitAction.triggered.connect(self.close) quitAction.setStatusTip('Quit the application') # tlačítko About aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'), '&About', self) aboutAction.triggered.connect(self.aboutDialog) aboutAction.setStatusTip('About this application') # nástrojový pruh self.toolbar = self.addToolBar('title') # přidání tlačítek na nástrojový pruh self.toolbar.addAction(quitAction) self.toolbar.addAction(aboutAction) # vložení komponenty do okna self.setCentralWidget(MainWindowContent()) with open("stylesheet5.css") as fin: styleSheet = fin.read() self.setStyleSheet(styleSheet) def setStyle(self, styleName): # nastavení vybraného stylu QtGui.QApplication.setStyle(styleName) def aboutDialog(self): msgBox = QtGui.QMessageBox() msgBox.setText('About:\n...\n...\n...') msgBox.setIcon(QtGui.QMessageBox.Information) msgBox.exec_() def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) app.exec_() def main(): # QtGui.QApplication.setStyle("plastique") # QtGui.QApplication.setStyleSheet("background-color: #407040; color: white") app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
18. Galerie: screenshoty pátého příkladu při použití všech základních podporovaných stylů
Dnes již naposledy se můžeme podívat na screenshoty získané při běhu dnešního pátého demonstračního příkladu, opět při použití různých základních stylů:

Obrázek 33: Okno pátého demonstračního příkladu po výběru standardního stylu Windows.

Obrázek 34: Okno pátého demonstračního příkladu po výběru standardního stylu Motif.

Obrázek 35: Okno pátého demonstračního příkladu po výběru standardního stylu CDE.

Obrázek 36: Okno pátého demonstračního příkladu po výběru standardního stylu Plastique.

Obrázek 37: Okno pátého demonstračního příkladu po výběru standardního stylu GTK+.

Obrázek 38: Okno pátého demonstračního příkladu po výběru standardního stylu Cleanlooks.
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes popsaných demonstračních příkladů společně s jedním pomocným skriptem 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:
# | Příklad | Adresa |
---|---|---|
1 | 141_custom_stylesheet2.py | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/141_custom_stylesheet2.py |
2 | 142_external_stylesheet.py | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/142_external_stylesheet.py |
3 | 143_style_selectors.py | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/143_style_selectors.py |
4 | 144_pseudo_classes.py | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/144_pseudo_classes.py |
5 | 145_checkbox_style.py | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/145_checkbox_style.py |
Následují soubory obsahující kaskádové styly používané výše zmíněnými demonstračními příklady:
# | Stylesheet | Adresa |
---|---|---|
1 | stylesheet.css | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/stylesheet.css |
2 | stylesheet2.css | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/stylesheet2.css |
3 | stylesheet3.css | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/stylesheet3.css |
4 | stylesheet4.css | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/stylesheet4.css |
5 | stylesheet5.css | https://github.com/tisnik/presentations/blob/master/Python_GUI/PySide/stylesheet5.css |
20. Odkazy na Internetu
- PySide 1.2.1 documentation
https://pyside.github.io/docs/pyside/index.html - QStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QStyle.html - QCommonStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QCommonStyle.html - QPlastiqueStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QPlastiqueStyle.html - QMacStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QMacStyle.html - QCleanlooksStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QCleanlooksStyle.html - QGtkStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QGtkStyle.html - QCDEStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QCDEStyle.html - QMotifStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QMotifStyle.html - QWindowsStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QWindowsStyle.html - QStyleFactory
https://pyside.github.io/docs/pyside/PySide/QtGui/QStyleFactory.html - QStyleOptionHeader
https://pyside.github.io/docs/pyside/PySide/QtGui/QStyleOptionHeader.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/