Hlavní navigace

Tvorba GUI v Pythonu: použití kaskádových stylů v PySide

20. 3. 2018
Doba čtení: 32 minut

Sdílet

V dnešní části seriálu o tvorbě uživatelského rozhraní v Pythonu si ukážeme některé zajímavé možnosti ovlivnění stylů vykreslování ovládacích prvků, které programátorům nabízí knihovna PySide díky podpoře kaskádových stylů (CSS).

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

20. Odkazy na Internetu

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.

Cloud23

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/pre­sentations. Pokud nechcete klonovat celý repositář, můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:

Následují soubory obsahující kaskádové styly používané výše zmíněnými demonstračními příklady:

20. Odkazy na Internetu

  1. PySide 1.2.1 documentation
    https://pyside.github.io/doc­s/pyside/index.html
  2. QStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QSty­le.html
  3. QCommonStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QCom­monStyle.html
  4. QPlastiqueStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QPlas­tiqueStyle.html
  5. QMacStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QMac­Style.html
  6. QCleanlooksStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QCle­anlooksStyle.html
  7. QGtkStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QGtkSty­le.html
  8. QCDEStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QCDES­tyle.html
  9. QMotifStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QMo­tifStyle.html
  10. QWindowsStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QWin­dowsStyle.html
  11. QStyleFactory
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QSty­leFactory.html
  12. QStyleOptionHeader
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QSty­leOptionHeader.html
  13. QAbstractSlider
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/Abstrac­tSlider.html
  14. QScrollBar
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/Scro­llBar.html
  15. QSlider
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/Sli­der.html
  16. QDial
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/Dial­.html
  17. QImage
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QIma­ge.html
  18. QPixmap
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QPix­map.html
  19. QBitmap
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QBit­map.html
  20. QPaintDevice
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QPa­intDevice.html
  21. QPicture
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QPic­ture.html
  22. QPainter
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QPa­inter.html
  23. QPainterPath
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QPa­interPath.html
  24. QGradient
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QGra­dient.html
  25. QLinearGradient
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLi­nearGradient.html
  26. QRadialGradient
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QRa­dialGradient.html
  27. QTableWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QTa­bleWidget.html
  28. QTableWidgetItem
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QTa­bleWidgetItem.html
  29. QTreeWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QTre­eWidget.html
  30. QTreeWidgetItem
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QTre­eWidgetItem.html
  31. Afinní zobrazení
    https://cs.wikipedia.org/wi­ki/Afinn%C3%AD_zobrazen%C3%AD
  32. Differences Between PySide and PyQt
    https://wiki.qt.io/Differen­ces_Between_PySide_and_PyQt
  33. PySide 1.2.1 tutorials
    https://pyside.github.io/doc­s/pyside/tutorials/index.html
  34. PySide tutorial
    http://zetcode.com/gui/py­sidetutorial/
  35. Drawing in PySide
    http://zetcode.com/gui/py­sidetutorial/drawing/
  36. Qt Core
    https://pyside.github.io/doc­s/pyside/PySide/QtCore/Qt­.html
  37. QLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLa­yout.html
  38. QValidator
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QVa­lidator.html
  39. QStackedLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QStac­kedLayout.html
  40. QFormLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QFor­mLayout.html
  41. QBoxLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QBox­Layout.html
  42. QHBoxLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QHBox­Layout.html
  43. QVBoxLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QVBox­Layout.html
  44. QGridLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QGrid­Layout.html
  45. QAction
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QAc­tion.html
  46. QDialog
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QDi­alog.html
  47. QMessageBox
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QMes­sageBox.html
  48. QErrorMessage
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QError­Message.html
  49. QInputDialog
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QIn­putDialog.html
  50. QColorDialog
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QCo­lorDialog.html
  51. QListWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLis­tWidget.html
  52. Signals & Slots
    http://doc.qt.io/qt-4.8/signalsandslots.html
  53. Signals and Slots in PySide
    http://wiki.qt.io/Signals_an­d_Slots_in_PySide
  54. Intro to PySide/PyQt: Basic Widgets and Hello, World!
    http://www.pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/
  55. QLineEdit
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLi­neEdit.html
  56. QTextEdit
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QTex­tEdit.html
  57. QValidator
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QVa­lidator.html
  58. QIntValidator
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QIn­tValidator.html
  59. QRegExpValidator
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QRe­gExpValidator.html
  60. QWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QWid­get.html
  61. QMainWindow
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QMa­inWindow.html
  62. QLabel
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLa­bel.html
  63. QAbstractButton
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QAb­stractButton.html
  64. QCheckBox
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QChec­kBox.html
  65. QRadioButton
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QRa­dioButton.html
  66. QButtonGroup
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QBut­tonGroup.html
  67. QFrame
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QFra­me.html#PySide.QtGui.PySi­de.QtGui.QFrame
  68. QFrame.frameStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QFra­me.html#PySide.QtGui.PySi­de.QtGui.QFrame.frameStyle
  69. Leo editor
    http://leoeditor.com/
  70. IPython Qt Console aneb vylepšený pseudoterminál
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-ipython-a-ipython-notebook/#k06
  71. Vývojová prostředí ve Fedoře (4. díl)
    https://mojefedora.cz/vyvojova-prostredi-ve-fedore-4-dil/
  72. Seriál Letní škola programovacího jazyka Logo
    http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/
  73. Educational programming language
    http://en.wikipedia.org/wi­ki/Educational_programmin­g_language
  74. Logo Tree Project:
    http://www.elica.net/downlo­ad/papers/LogoTreeProject­.pdf
  75. Hra Breakout napísaná v Tkinteri
    https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/
  76. Hra Snake naprogramovaná v Pythone s pomocou Tkinter
    https://www.root.cz/clanky/hra-snake-naprogramovana-v-pythone-s-pomocou-tkinter/
  77. 24.1. turtle — Turtle graphics
    https://docs.python.org/3­.5/library/turtle.html#mo­dule-turtle
  78. TkDND
    http://freecode.com/projects/tkdnd
  79. Python Tkinter Fonts
    https://www.tutorialspoin­t.com/python/tk_fonts.htm
  80. The Tkinter Canvas Widget
    http://effbot.org/tkinter­book/canvas.htm
  81. Ovládací prvek (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Ovl%C3%A1dac%C3%AD_prvek_­%28po%C4%8D%C3%ADta%C4%8D%29
  82. Rezervovaná klíčová slova v Pythonu
    https://docs.python.org/3/re­ference/lexical_analysis.html#ke­ywords
  83. TkDocs: Styles and Themes
    http://www.tkdocs.com/tuto­rial/styles.html
  84. Drawing in Tkinter
    http://zetcode.com/gui/tkin­ter/drawing/
  85. Changing ttk widget text color (StackOverflow)
    https://stackoverflow.com/qu­estions/16240477/changing-ttk-widget-text-color
  86. The Hitchhiker's Guide to Pyhton: GUI Applications
    http://docs.python-guide.org/en/latest/scenarios/gui/
  87. 7 Top Python GUI Frameworks for 2017
    http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/
  88. GUI Programming in Python
    https://wiki.python.org/mo­in/GuiProgramming
  89. Cameron Laird's personal notes on Python GUIs
    http://phaseit.net/claird/com­p.lang.python/python_GUI.html
  90. Python GUI development
    http://pythoncentral.io/introduction-python-gui-development/
  91. Graphic User Interface FAQ
    https://docs.python.org/2/faq/gu­i.html#graphic-user-interface-faq
  92. TkInter
    https://wiki.python.org/moin/TkInter
  93. Tkinter 8.5 reference: a GUI for Python
    http://infohost.nmt.edu/tcc/hel­p/pubs/tkinter/web/index.html
  94. TkInter (Wikipedia)
    https://en.wikipedia.org/wiki/Tkinter
  95. appJar
    http://appjar.info/
  96. appJar (Wikipedia)
    https://en.wikipedia.org/wiki/AppJar
  97. appJar na Pythonhosted
    http://pythonhosted.org/appJar/
  98. appJar widgets
    http://appjar.info/pythonWidgets/
  99. Stránky projektu PyGTK
    http://www.pygtk.org/
  100. PyGTK (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  101. Stránky projektu PyGObject
    https://wiki.gnome.org/Pro­jects/PyGObject
  102. Stránky projektu Kivy
    https://kivy.org/#home
  103. Stránky projektu PyQt
    https://riverbankcomputin­g.com/software/pyqt/intro
  104. PyQt (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  105. Stránky projektu PySide
    https://wiki.qt.io/PySide
  106. PySide (Wikipedia)
    https://en.wikipedia.org/wiki/PySide
  107. Stránky projektu Kivy
    https://kivy.org/#home
  108. Kivy (framework, Wikipedia)
    https://en.wikipedia.org/wi­ki/Kivy_(framework)
  109. QML Applications
    http://doc.qt.io/qt-5/qmlapplications.html
  110. KDE
    https://www.kde.org/
  111. Qt
    https://www.qt.io/
  112. GNOME
    https://en.wikipedia.org/wiki/GNOME
  113. Category:Software that uses PyGTK
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGTK
  114. Category:Software that uses PyGObject
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGObject
  115. Category:Software that uses wxWidgets
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_wxWidgets
  116. GIO
    https://developer.gnome.or­g/gio/stable/
  117. GStreamer
    https://gstreamer.freedesktop.org/
  118. GStreamer (Wikipedia)
    https://en.wikipedia.org/wi­ki/GStreamer
  119. Wax Gui Toolkit
    https://wiki.python.org/moin/Wax
  120. Python Imaging Library (PIL)
    http://infohost.nmt.edu/tcc/hel­p/pubs/pil/
  121. 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/