Hlavní navigace

Tvorba GUI v Pythonu s PySide: hlavní menu, nástrojový pruh a výběrový seznam

Pavel Tišnovský

V pátém článku o knihovně PySide si ukážeme, jak se do hlavního okna aplikace přidává menu (samozřejmě i s ikonami a klávesovými zkratkami) a nástrojový pruh. Ve druhé polovině si popíšeme další užitečné widgety, především výběrový seznam.

Doba čtení: 30 minut

Obsah

1. Rozšíření možností hlavního okna odvozeného od třídy QMainWindow

2. Přidání menu do hlavního okna

3. První příklad: jednoduché rozbalovací menu

4. Druhý příklad: zobrazení nápovědy k aktuálně vybraným položkám menu

5. Třetí příklad: položky menu vyvolávané klávesovými zkratkami

6. Ikony ve frameworku PySide

7. Čtvrtý příklad: položky menu s ikonami

8. Přidání nástrojového pruhu do hlavního okna

9. Pátý příklad: jednoduchý nástrojový pruh se dvěma tlačítky

10. Šestý příklad: kombinace hlavního menu i nástrojového pruhu

11. Další užitečné widgety nabízené frameworkem PySide

12. Výběrový seznam (listbox)

13. Sedmý příklad: jednoduchý výběrový seznam s textovými položkami

14. Osmý příklad: alternativní způsob přidání položek do výběrového seznamu

15. Události generované při práci s výběrovým seznamem

16. Devátý příklad: reakce na základní události při práci s výběrovým seznamem

17. Desátý příklad: seznam s ikonami

18. Obsah dalšího pokračování seriálu

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

20. Odkazy na Internetu

1. Rozšíření možností hlavního okna odvozeného od třídy QMainWindow

předchozí části seriálu o tvorbě aplikací s grafickým uživatelským rozhraním v Pythonu jsme se seznámili se základními vlastnostmi třídy QMainWindow. Ukázali jsme si, jak se od této třídy odvozuje vlastní hlavní okno aplikace, způsob přidání stavového řádku, dalších ovládacích prvků atd. Dnes budeme v popisu možností této třídy pokračovat, protože do hlavního okna aplikace postupně přidáme menu (položkám v menu samozřejmě přiřadíme klávesové zkratky a ikony) a taktéž nástrojový pruh (toolbar). Druhá část článku je pak věnována dalším užitečným a často používaným ovládacím prvkům, především výběrovému seznamu, který je reprezentován třídou QListWidget. Tento seznam může obsahovat jak jednoduché textové prvky, tak i ikony a samozřejmě též kombinaci text+ikona.

Pro začátek si připomeňme, jak vypadá ta prakticky nejjednodušší aplikace s hlavním oknem odvozeným od třídy QMainWindow:

# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QMainWindow")
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()

Hlavní okno aplikace se zobrazí (a tím pádem i „spustí“) jednoduše:

def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)

Obrázek 1: Prázdné hlavní okno jednoduché aplikace postavené na widgetu QMainWindow.

2. Přidání menu do okna

Podívejme se nyní, jakým způsobem je možné do hlavního okna aplikace přidat menu. Stále budeme rozšiřovat funkcionalitu třídy QMainWindow, tj. budeme postupovat stejně, jak to bylo naznačeno v předchozím příkladu:

class MainWindow(QtGui.QMainWindow):

Přidání plochy pro menu (resp. přesněji pro pruh či lištu s menu) zajistí jediný příkaz:

menubar = self.menuBar()

Pokud ovšem nebude do menu přidán žádný obsah, bude skutečná plocha alokovaná pro menu jen zcela minimální:

Obrázek 2: Po přidání pruhu pro menu vypadá hlavní okno aplikace následovně. V porovnání s prvním screenshotem můžeme vidět jen malou změnu – pětipixelový proužek na horním okraji okna.

Prozatím prázdné listy rozbalovacích menu lze vytvořit následovně. Povšimněte si, že můžeme použít znak & pro specifikaci klávesové zkratky Alt+znak:

fileMenu = menubar.addMenu('&File')
helpMenu = menubar.addMenu('&Help')

Obrázek 3: Hlavní menu s dvojicí prázdných listů File a Help.

Do jednotlivých listů můžeme přidat jednotlivé položky menu. Každá položka je reprezentována instancí třídy QAction:

fileQuitItem = QtGui.QAction('&Quit', self)

Přidání již vytvořené položky do listu menu zajistí metoda addAction

fileMenu.addAction(fileQuitItem)

U každé položky lze s využitím signálu specifikovat, jaká funkce, metoda či anonymní funkce se zavolá ve chvíli, kdy je položka menu vybrána myší, klávesnicí (najetím + Enter) nebo klávesovou zkratkou:

fileQuitItem.triggered.connect(self.close)

Obrázek 4: Menu s naplněnými listy.

3. První příklad: jednoduché rozbalovací menu

V dnešním prvním demonstračním příkladu je ukázán způsob vytvoření lišty menu se dvěma položkami File a Help. Po výběru každé z těchto položek se příslušné menu rozbalí a zobrazí svůj obsah (což je v každém případě jediný příkaz, alespoň v této verzi aplikace). První příkaz ukončí aplikaci voláním metody QMainWindow.close(), druhý příkaz zobrazí dialog s informacemi o aplikaci. Používá se zde třída QMessageBox, kterou jsme si sice prozatím nepopsali, ale její základní použití je viditelné ze zdrojového kódu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle('QMainWindow + statusBar + mainMenu')
 
        # hlavní menu
        menubar = self.menuBar()
 
        # příkaz File/Quit
        fileQuitItem = QtGui.QAction('&Quit', self)
        fileQuitItem.triggered.connect(self.close)
 
        # položka File v hlavním menu
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(fileQuitItem)
 
        # příkaz Help/About
        helpAboutItem = QtGui.QAction('&About', self)
        helpAboutItem.triggered.connect(self.aboutDialog)
 
        # položka Help v hlavním menu
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAboutItem)
 
        # zobrazení hlavního okna
        self.show()
 
    def aboutDialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setText('About:\n...\n...\n...')
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
        pass
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

4. Druhý příklad: zobrazení nápovědy k aktuálně vybraným položkám menu

Ve druhém demonstračním příkladu je do hlavního okna přidán stavový řádek:

# stavový řádek
self.statusBar().showMessage('QMainWindow')

Obrázek 5: Druhý příklad ihned po svém spuštění s inicializovaným stavovým řádkem.

Navíc budeme u každé položky menu specifikovat krátký text s nápovědou. Ta bude zcela automaticky zobrazena ve stavovém řádku ve chvíli, kdy je daná položka vybrána. Pro mnoho aplikací se složitějšími příkazy se jedná o důležitou část GUI, kterou navíc získáme prakticky „zadarmo“, takže vlastně pravděpodobně ani neexistuje žádný důvod, proč ji nevyužít:

# příkaz File/Quit
fileQuitItem = QtGui.QAction('&Quit', self)
fileQuitItem.triggered.connect(self.close)
fileQuitItem.setStatusTip('Quit the application')
 
# příkaz Help/About
helpAboutItem = QtGui.QAction('&About', self)
helpAboutItem.triggered.connect(self.aboutDialog)
helpAboutItem.setStatusTip('About this application')

Obrázek 6: Způsob zobrazení nápovědy k vybrané položce menu ve stavovém řádku.

Následuje výpis zdrojového kódu dnešního druhého demonstračního příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle('QMainWindow + statusBar + mainMenu')
 
        # stavový řádek
        self.statusBar().showMessage('QMainWindow')
 
        # hlavní menu
        menubar = self.menuBar()
 
        # příkaz File/Quit
        fileQuitItem = QtGui.QAction('&Quit', self)
        fileQuitItem.triggered.connect(self.close)
        fileQuitItem.setStatusTip('Quit the application')
 
        # položka File v hlavním menu
        fileMenu = menubar.addMenu('&File')
        fileMenu.addAction(fileQuitItem)
 
        # příkaz Help/About
        helpAboutItem = QtGui.QAction('&About', self)
        helpAboutItem.triggered.connect(self.aboutDialog)
        helpAboutItem.setStatusTip('About this application')
 
        # položka Help v hlavním menu
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAboutItem)
 
        # zobrazení hlavního okna
        self.show()
 
    def aboutDialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setText('About:\n...\n...\n...')
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
        pass
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

5. Třetí příklad: položky menu vyvolávané klávesovými zkratkami

Menu můžeme dále vylepšit, a to tak, že jednotlivým položkám/příkazům přiřadíme klávesové zkratky. Jedná se o téma, kterému jsme se již částečně věnovali minule v kontextu dalších ovládacích prvků, takže si dnes jen rychle ukážeme, jak příkazu File→Quit přiřadíme klávesovou zkratku Ctrl+Q a příkazu Help→About klávesovou zkratku F1:

# příkaz File/Quit
fileQuitItem = QtGui.QAction('&Quit', self)
fileQuitItem.triggered.connect(self.close)
fileQuitItem.setStatusTip('Quit the application')
fileQuitItem.setShortcut('Ctrl+Q')

Obrázek 7: Položka menu (příkaz), který je možné vyvolat i klávesovou zkratkou.

Druhá položka (příkaz) menu:

# příkaz Help/About
helpAboutItem = QtGui.QAction('&About', self)
helpAboutItem.triggered.connect(self.aboutDialog)
helpAboutItem.setStatusTip('About this application')
helpAboutItem.setShortcut('F1')

Obrázek 8: Druhá položka menu (příkaz), který je možné vyvolat i klávesovou zkratkou.

Žádné další úpravy již v aplikaci nemusíme provádět, což je ostatně patrné i při pohledu na úplný zdrojový kód dnešního třetího demonstračního příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle('QMainWindow + statusBar + mainMenu')
 
        # stavový řádek
        self.statusBar().showMessage('QMainWindow')
 
        # hlavní menu
        menubar = self.menuBar()
 
        # příkaz File/Quit
        fileQuitItem = QtGui.QAction('&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)
 
        # příkaz Help/About
        helpAboutItem = QtGui.QAction('&About', self)
        helpAboutItem.triggered.connect(self.aboutDialog)
        helpAboutItem.setStatusTip('About this application')
        helpAboutItem.setShortcut('F1')
 
        # položka Help v hlavním menu
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAboutItem)
 
        # zobrazení hlavního okna
        self.show()
 
    def aboutDialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setText('About:\n...\n...\n...')
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
        pass
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

6. Ikony ve frameworku PySide

V mnoha ovládacích prvcích je možné kromě textu zobrazit i ikony. Týká se to samozřejmě i položek menu, takže si nyní ukažme, jak se s ikonami pracuje. Je to ve skutečnosti velmi jednoduché, protože při vytváření (konstrukci) nové položky můžeme v prvním parametru konstruktoru uvést objekt typu QIcon. A vytvoření tohoto objektu je opět snadné, protože konstruktoru pouze předáme cestu k externímu souboru s rastrovým obrázkem. Na rozdíl od knihovny Tkinter, v níž se nijak nehlídala existence reference na objekt s ikonou (a musel to tedy zajistit programátor, například použitím globálních proměnných a/nebo atributů třídy) je kód psaný pro framework PySide mnohem čistší:

# 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')
 
# příkaz Help/About
helpAboutItem = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'),
                              '&About', self)
helpAboutItem.triggered.connect(self.aboutDialog)
helpAboutItem.setStatusTip('About this application')
helpAboutItem.setShortcut('F1')

Obrázek 9: Menu s ikonami použitými u jednotlivých položek/příkazů.

7. Čtvrtý příklad: položky menu s ikonami

Ve čtvrtém příkladu použijeme dvě ikony, které přiřadíme položkám menu File→Quit a Help→About. Obě ikony jsou uloženy v podadresáři icons, který samozřejmě taktéž naleznete v repositáři s projekty. Další zde uložené ikony budou použity v následujících příkladech popsaných v navazujících kapitolách.

Obrázek 10: Druhé menu s ikonami použitými u jednotlivých položek/příkazů.

Zdrojový kód dnešního čtvrtého demonstračního příkladu vypadá následovně:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle('QMainWindow + statusBar + mainMenu')
 
        # stavový řádek
        self.statusBar().showMessage('QMainWindow')
 
        # 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)
 
        # příkaz Help/About
        helpAboutItem = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'),
                                      '&About', self)
        helpAboutItem.triggered.connect(self.aboutDialog)
        helpAboutItem.setStatusTip('About this application')
        helpAboutItem.setShortcut('F1')
 
        # položka Help v hlavním menu
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAboutItem)
 
        # zobrazení hlavního okna
        self.show()
 
    def aboutDialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setText('About:\n...\n...\n...')
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
        pass
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

8. Přidání nástrojového pruhu do hlavního okna

Kromě menu, jehož existenci očekává většina uživatelů klasických desktopových aplikací, je možné do hlavního okna přidat i nástrojový pruh neboli toolbar. Na tomto pruhu mohou být umístěny různé widgety, typicky se však setkáme s tlačítky (mnohdy bez textu) a s výběrovými seznamy. Nástrojový pruh může být vybaven „ouškem“ určeným pro jeho přesun do jiné oblasti hlavního okna či dokonce zcela mimo hlavní okno. Na sekvenci screenshotů zobrazených pod tímto odstavcem můžeme vidět jednotlivé možnosti umístění jednoduchého nástrojového pruhu se dvěma tlačítky:

Obrázek 11: Nástrojový pruh je zadokován u horního okraje okna.

Obrázek 12: Nástrojový pruh je zadokován u levého okraje okna.

Obrázek 13: Nástrojový pruh je zadokován u dolního okraje okna.

Obrázek 14: Nástrojový pruh je zadokován u pravého okraje okna.

Obrázek 15: Nástrojový pruh se chová jako samostatné okno.

9. Pátý příklad: jednoduchý nástrojový pruh se dvěma tlačítky

Ukažme si nyní použití jednoduchého nástrojového pruhu, který bude obsahovat dvě tlačítka s ikonami. První z těchto tlačítek ukončí aplikaci, druhé vyvolá dialog s informacemi o aplikaci. Samotný (prozatím prázdný) nástrojový pruh se vytvoří zavoláním metody addToolBar():

self.toolbar = self.addToolBar('title')

Dále vytvoříme obě tlačítka a také nadeklarujeme klávesové zkratky pro ně:

# tlačítko Quit
quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'),
                           '&Quit', self)
quitAction.triggered.connect(self.close)
quitAction.setStatusTip('Quit the application')
quitAction.setShortcut('Ctrl+Q')
 
# tlačítko About
aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'),
                            '&About', self)
aboutAction.triggered.connect(self.aboutDialog)
aboutAction.setStatusTip('About this application')
aboutAction.setShortcut('F1')

Poznámka: texty sice nejsou u tlačítek zobrazeny, ale pokud přejedeme kurzorem myši na zvolené tlačítko, zobrazí se popisek tlačítka v bublinové nápovědě:

Obrázek 16: Zobrazení popisku tlačítka v bublinové nápovědě.

Tlačítka samozřejmě musíme přidat na nástrojový pruh, což je už snadné:

self.toolbar.addAction(quitAction)
self.toolbar.addAction(aboutAction)

Následuje výpis zdrojového kódu příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle('QMainWindow + statusBar + toolBar')
 
        # tlačítko Quit
        quitAction = QtGui.QAction(QtGui.QIcon('icons/application-exit.png'),
                                   '&Quit', self)
        quitAction.triggered.connect(self.close)
        quitAction.setStatusTip('Quit the application')
        quitAction.setShortcut('Ctrl+Q')

        # tlačítko About
        aboutAction = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'),
                                    '&About', self)
        aboutAction.triggered.connect(self.aboutDialog)
        aboutAction.setStatusTip('About this application')
        aboutAction.setShortcut('F1')
 
        # 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)
 
        # zobrazení hlavního okna
        self.show()
 
    def aboutDialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setText('About:\n...\n...\n...')
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
        pass
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

10. Šestý příklad: kombinace hlavního menu i nástrojového pruhu

Samozřejmě nám nic nebrání v tom, abychom zkombinovali hlavní menu a nástrojový pruh. Jen si musíme dát pozor na to, aby se ke dvěma různým ovládacím prvkům nepřiřadila stejná klávesová zkratka.

Obrázek 17: Kombinace hlavního menu s nástrojovým pruhem v jednom oknu.

Použití hlavního menu i nástrojového pruhu si můžete vyzkoušet po spuštění dalšího příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle('QMainWindow + statusBar + mainMenu + toolBar')
 
        # stavový řádek
        self.statusBar().showMessage('QMainWindow')
 
        # 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)
 
        # příkaz Help/About
        helpAboutItem = QtGui.QAction(QtGui.QIcon('icons/dialog-information.png'),
                                      '&About', self)
        helpAboutItem.triggered.connect(self.aboutDialog)
        helpAboutItem.setStatusTip('About this application')
        helpAboutItem.setShortcut('F1')
 
        # položka Help v hlavním menu
        helpMenu = menubar.addMenu('&Help')
        helpMenu.addAction(helpAboutItem)
 
        # 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)
 
        # zobrazení hlavního okna
        self.show()
 
    def aboutDialog(self):
        msgBox = QtGui.QMessageBox()
        msgBox.setText('About:\n...\n...\n...')
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
        pass
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

11. Další užitečné widgety nabízené frameworkem PySide

Kromě ovládacích prvků popsaných v předchozích částech tohoto seriálu nabízí framework PySide programátorům i další typy widgetů. V tabulce jsou vypsány ty widgety, které si ještě postupně popíšeme:

Komponenta Stručný popis
QFrame komponenta s volitelným okrajem, odvozují se od ní další widgety
   
QListWidget seznam prvků
QComboBox kombo box (vstupní prvek + seznam prvků)
QLineEdit vstup jednoho řádku textu
   
QPlainTextEdit jednoduché vstupní víceřádkové textové pole
QTextEdit vstupní textové pole (umožňuje práci s tabulkami, obrázky atd.)
QTextBrowser komponenta s textem, který může obsahovat hypertextové odkazy
   
QSvgWidget komponenta pro zobrazení SVG (vektorová grafika)
QGLWidget komponenta pro zobrazení 2D/3D výstupu generovaného přes OpenGL

V dalších kapitolách si popíšeme způsob použití klasického výběrového seznamu, který je představován třídou QListWidget.

12. Výběrový seznam (listbox)

Dalším užitečným ovládacím prvkem, který nalezneme v mnoha aplikacích, je výběrový seznam neboli listbox. Tento prvek je možné ve frameworku PySide vytvořit minimálně dvěma způsoby, a to s využitím třídy QListView nebo pouze třídy QListWidget, přičemž se první zmíněná třída používá až ve chvíli, kdy je užitečnější oddělit pohled na data od jejich vlastní reprezentace. V dalších příkladech však použijeme „pouze“ třídu QListWidget, přičemž uvidíme, že pro jednodušší aplikace může být její použití dostačující.

Obrázek 18: Nejjednodušší varianta výběrového seznamu (listbox).

13. Sedmý příklad: jednoduchý výběrový seznam s textovými položkami

Výběrový seznam obsahující několik textových položek se vytvoří následovně. Nejdříve zavoláme konstruktor seznamu:

listWidget = QtGui.QListWidget(self)

Dále vytvoříme několik položek (prvků) seznamu, a to s využitím konstruktoru QListWidgetItem. Povšimněte si, že druhým parametrem konstruktoru je reference na již dříve vytvořený seznam, takže se prvky automaticky do seznamu vloží, a to ve správném pořadí:

QtGui.QListWidgetItem(u'jedna', listWidget)
QtGui.QListWidgetItem(u'dvě', listWidget)
QtGui.QListWidgetItem(u'tři', listWidget)

Samozřejmě ještě musíme seznam umístit na plochu okna, a to s využitím layout manageru:

layout.addWidget(listWidget)

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

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
 
        # seznam prvků
        listWidget = QtGui.QListWidget(self)
        QtGui.QListWidgetItem(u'jedna', listWidget)
        QtGui.QListWidgetItem(u'dvě', listWidget)
        QtGui.QListWidgetItem(u'tři', listWidget)
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(listWidget)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QMainWindow + QListWidget")
 
        # vložení komponenty do okna
        self.setCentralWidget(MainWindowContent())
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

14. Osmý příklad: alternativní způsob přidání položek do výběrového seznamu

V předchozím příkladu jsme do seznamu vkládali prvky explicitně jeden po druhém:

QtGui.QListWidgetItem(u'jedna', listWidget)
QtGui.QListWidgetItem(u'dvě', listWidget)
QtGui.QListWidgetItem(u'tři', listWidget)

Existuje však i jednodušší způsob, který lze využít ve chvíli, kdy do výběrového seznamu vkládáme textové prvky. S využitím metody insertItems() je totiž možné do výběrového seznamu vložit běžný Pythonovský seznam (řetězců). Podívejme se, jak se tato operace provede v praxi:

items = [u'jedna',
         u'dva',
         u'tři',
         u'čtyři']
listWidget.insertItems(listWidget.currentRow(), items)

Prvním parametrem metody insertItems() je index prvku v rámci seznamu, od něhož budeme vkládat další prvky. My jsme zde použili volání listWidget.currentRow(), což je užitečné v případě, že do výběrového seznamu postupně vkládáme více běžných Pythonovských seznamů a nechce se nám postupně zjišťovat indexy prvků pro vkládání.

Obrázek 19: Výběrový seznam se čtyřmi prvky, které do něj byly vloženy jediným voláním metody insertItems.

Výsledný zdrojový kód příkladu vypadá takto:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
 
        # seznam prvků
        listWidget = QtGui.QListWidget(self)
        items = [u'jedna',
                 u'dva',
                 u'tři',
                 u'čtyři']
        listWidget.insertItems(listWidget.currentRow(), items)
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(listWidget)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QMainWindow + QListWidget")
 
        # vložení komponenty do okna
        self.setCentralWidget(MainWindowContent())
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

15. Události generované při práci s výběrovým seznamem

Při práci s výběrovým seznamem může vzniknout celkem deset typů událostí, pro které je samozřejmě možné si zaregistrovat příslušné handlery:

  1. currentItemChanged
  2. currentRowChanged
  3. currentTextChanged
  4. itemActivated
  5. itemChanged
  6. itemClicked
  7. itemDoubleClicked
  8. itemEntered
  9. itemPressed
  10. itemSelectionChanged

U klasických seznamů, jejichž prvky nejsou editovatelné, patří mezi nejdůležitější události itemPressed, itemClicked a itemActivated. Událost itemPressed vznikne ve chvíli stisku (levého) tlačítka myši na prvku. Po ukončení stisku se vygeneruje událost itemClicked, což je chování, které již známe z dalších typů widgetů. Užitečnější je ale událost itemActivated, neboť ta je vygenerována buď po dvojkliku nebo ve chvíli, kdy je prvek vybrán klávesnicí (tedy posunem kurzoru šipkami a stiskem klávesy Enter).

Obrázek 20: První událost je vygenerována po kliknutí na prvek umístěný ve výběrovém seznamu.

Registrace handlerů událostí je stejně snadná, jako u dalších widgetů:

listWidget = QtGui.QListWidget(self)
 
listWidget.itemActivated.connect(self.onItemActivated)
listWidget.itemPressed.connect(self.onItemPressed)
listWidget.itemClicked.connect(self.onItemClicked)

Samotné handlery mohou být implementovány formou metod třídy odvozené od QMainWindow:

def onItemPressed(self, item):
    message = u"tlačítko stisknuto na prvku: {text}".format(text=item.text())
    self.showMessage(message)
 
def onItemActivated(self, item):
    message = u"aktivován prvek: {text}".format(text=item.text())
    self.showMessage(message)
 
def onItemClicked(self, item):
    message = u"kliknuto na prvek: {text}".format(text=item.text())
    self.showMessage(message)

Obrázek 21: Druhá událost vznikne po dvojkliku, tedy po „aktivaci“ prvku.

16. Devátý příklad: reakce na základní události při práci s výběrovým seznamem

Podívejme se nyní, jak lze události popsané v předchozí kapitole propojit s příslušnými handlery. Po spuštění následující aplikace zkuste prvky vybírat myší, podržet stlačené tlačítko myši nad prvkem, vybrat prvky klávesnicí apod:

#!/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, parentWidget):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
        self._parentWidget = parentWidget
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
 
        # seznam prvků
        listWidget = QtGui.QListWidget(self)
        items = [u'jedna',
                 u'dva',
                 u'tři',
                 u'čtyři']
        listWidget.insertItems(listWidget.currentRow(), items)
 
        # události vyvolávané manipulací se seznamem
        listWidget.itemActivated.connect(self.onItemActivated)
        listWidget.itemPressed.connect(self.onItemPressed)
        listWidget.itemClicked.connect(self.onItemClicked)
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(listWidget)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
    def showMessage(self, message):
        self._parentWidget.statusBar().showMessage(message)
 
    def onItemPressed(self, item):
        message = u"tlačítko stisknuto na prvku: {text}".format(text=item.text())
        self.showMessage(message)
 
    def onItemActivated(self, item):
        message = u"aktivován prvek: {text}".format(text=item.text())
        self.showMessage(message)
 
    def onItemClicked(self, item):
        message = u"kliknuto na prvek: {text}".format(text=item.text())
        self.showMessage(message)
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QMainWindow + QListWidget")
 
        # vytvoření stavového řádku
        self.statusBar().showMessage('QMainWindow')
 
        # vložení komponenty do okna
        self.setCentralWidget(MainWindowContent(self))
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

17. Desátý příklad: seznam s ikonami

V dnešním posledním demonstračním příkladu si ukážeme, jakým způsobem je možné k položkám výběrového seznamu přidávat ikony. Ve skutečnosti to není nic složitého, protože použijeme naprosto stejný postup, jaký jsme zvolili u položek hlavního menu – do prvního parametru konstruktoru prvku seznamu předáme objekt s ikonou:

listWidget = QtGui.QListWidget(self)
QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-low.png'), u'0%', listWidget)
QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-040.png'), u'40%', listWidget)
QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-060.png'), u'60%', listWidget)
QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-080.png'), u'80%', listWidget)
QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-100.png'), u'100%', listWidget)

Výsledek můžeme vidět na následujícím screenshotu:

Obrázek 22: Seznam, jehož prvky obsahují ikony.

Opět následuje výpis úplného zdrojového kódu příkladu, který až na předchozích pět řádků nijak zásadně neliší od předchozí dvojice ukázkových aplikací:

#!/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, parentWidget):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
        self._parentWidget = parentWidget
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
 
        # seznam prvků
        listWidget = QtGui.QListWidget(self)
        QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-low.png'), u'0%', listWidget)
        QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-040.png'), u'40%', listWidget)
        QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-060.png'), u'60%', listWidget)
        QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-080.png'), u'80%', listWidget)
        QtGui.QListWidgetItem(QtGui.QIcon('icons/battery-100.png'), u'100%', listWidget)
 
        # události vyvolávané manipulací se seznamem
        listWidget.itemActivated.connect(self.onItemActivated)
        listWidget.itemPressed.connect(self.onItemPressed)
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(listWidget)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
    def showMessage(self, message):
        self._parentWidget.statusBar().showMessage(message)
 
    def onItemPressed(self, item):
        message = u"kliknuto na prvek: {text}".format(text=item.text())
        self.showMessage(message)
 
    def onItemActivated(self, item):
        message = u"aktivován prvek: {text}".format(text=item.text())
        self.showMessage(message)
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QMainWindow + QListWidget")
 
        # vytvoření stavového řádku
        self.statusBar().showMessage('QMainWindow')
 
        # vložení komponenty do okna
        self.setCentralWidget(MainWindowContent(self))
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

Obrázek 23: Výběr druhého prvku seznamu.

18. Obsah dalšího pokračování seriálu

V navazujícím článku se budeme zabývat tím, jak je možné ve frameworku PySide pracovat s grafickými informacemi (2D rastrovými obrázky, vektorovými scénami ve 2D i ve 3D). Jedná se o poměrně rozsáhlé téma, protože možnosti nabízené PySide jsou skutečně široké – možné je pracovat s jednoduchými ikonami (QIcon), existuje rozhraní ke knihovně OpenGL (QtOpenGL), k vektorové grafice ukládané ve formátu SVG (QtSvg) a zapomenout nesmíme ani na možnost vysokoúrovňové práce s grafickými daty s využitím třídy QGraphicsScene a tříd odvozených od QGraphicsItem.

Obrázek 24: Aktivace čtvrtého prvku výběrového seznamu.

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

Zdrojové kódy všech deseti dnes popsaných demonstračních příkladů byly opět, podobně jako tomu bylo i v předchozích článcích, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/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:

20. Odkazy na Internetu

  1. PySide 1.2.1 documentation
    https://pyside.github.io/doc­s/pyside/index.html
  2. Differences Between PySide and PyQt
    https://wiki.qt.io/Differen­ces_Between_PySide_and_PyQt
  3. PySide 1.2.1 tutorials
    https://pyside.github.io/doc­s/pyside/tutorials/index.html
  4. PySide tutorial
    http://zetcode.com/gui/py­sidetutorial/
  5. Qt Core
    https://pyside.github.io/doc­s/pyside/PySide/QtCore/Qt­.html
  6. QLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLa­yout.html
  7. QStackedLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QStac­kedLayout.html
  8. QFormLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QFor­mLayout.html
  9. QBoxLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QBox­Layout.html
  10. QHBoxLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QHBox­Layout.html
  11. QVBoxLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QVBox­Layout.html
  12. QGridLayout
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QGrid­Layout.html
  13. QAction
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QAc­tion.html
  14. QMessageBox
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QMes­sageBox.html
  15. QListWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLis­tWidget.html
  16. Signals & Slots
    http://doc.qt.io/qt-4.8/signalsandslots.html
  17. Signals and Slots in PySide
    http://wiki.qt.io/Signals_an­d_Slots_in_PySide
  18. Intro to PySide/PyQt: Basic Widgets and Hello, World!
    http://www.pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/
  19. QWidget
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QWid­get.html
  20. QMainWindow
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QMa­inWindow.html
  21. QLabel
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QLa­bel.html
  22. QAbstractButton
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QAb­stractButton.html
  23. QCheckBox
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QChec­kBox.html
  24. QRadioButton
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QRa­dioButton.html
  25. QButtonGroup
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QBut­tonGroup.html
  26. QFrame
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QFra­me.html#PySide.QtGui.PySi­de.QtGui.QFrame
  27. QFrame.frameStyle
    https://pyside.github.io/doc­s/pyside/PySide/QtGui/QFra­me.html#PySide.QtGui.PySi­de.QtGui.QFrame.frameStyle
  28. Leo editor
    http://leoeditor.com/
  29. IPython Qt Console aneb vylepšený pseudoterminál
    https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-ipython-a-ipython-notebook/#k06
  30. Vývojová prostředí ve Fedoře (4. díl)
    https://mojefedora.cz/vyvojova-prostredi-ve-fedore-4-dil/
  31. Seriál Letní škola programovacího jazyka Logo
    http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/
  32. Educational programming language
    http://en.wikipedia.org/wi­ki/Educational_programmin­g_language
  33. Logo Tree Project:
    http://www.elica.net/downlo­ad/papers/LogoTreeProject­.pdf
  34. Hra Breakout napísaná v Tkinteri
    https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/
  35. Hra Snake naprogramovaná v Pythone s pomocou Tkinter
    https://www.root.cz/clanky/hra-snake-naprogramovana-v-pythone-s-pomocou-tkinter/
  36. 24.1. turtle — Turtle graphics
    https://docs.python.org/3­.5/library/turtle.html#mo­dule-turtle
  37. TkDND
    http://freecode.com/projects/tkdnd
  38. Python Tkinter Fonts
    https://www.tutorialspoin­t.com/python/tk_fonts.htm
  39. The Tkinter Canvas Widget
    http://effbot.org/tkinter­book/canvas.htm
  40. Ovládací prvek (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Ovl%C3%A1dac%C3%AD_prvek_­%28po%C4%8D%C3%ADta%C4%8D%29
  41. Rezervovaná klíčová slova v Pythonu
    https://docs.python.org/3/re­ference/lexical_analysis.html#ke­ywords
  42. TkDocs: Styles and Themes
    http://www.tkdocs.com/tuto­rial/styles.html
  43. Drawing in Tkinter
    http://zetcode.com/gui/tkin­ter/drawing/
  44. Changing ttk widget text color (StackOverflow)
    https://stackoverflow.com/qu­estions/16240477/changing-ttk-widget-text-color
  45. The Hitchhiker's Guide to Pyhton: GUI Applications
    http://docs.python-guide.org/en/latest/scenarios/gui/
  46. 7 Top Python GUI Frameworks for 2017
    http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/
  47. GUI Programming in Python
    https://wiki.python.org/mo­in/GuiProgramming
  48. Cameron Laird's personal notes on Python GUIs
    http://phaseit.net/claird/com­p.lang.python/python_GUI.html
  49. Python GUI development
    http://pythoncentral.io/introduction-python-gui-development/
  50. Graphic User Interface FAQ
    https://docs.python.org/2/faq/gu­i.html#graphic-user-interface-faq
  51. TkInter
    https://wiki.python.org/moin/TkInter
  52. Tkinter 8.5 reference: a GUI for Python
    http://infohost.nmt.edu/tcc/hel­p/pubs/tkinter/web/index.html
  53. TkInter (Wikipedia)
    https://en.wikipedia.org/wiki/Tkinter
  54. appJar
    http://appjar.info/
  55. appJar (Wikipedia)
    https://en.wikipedia.org/wiki/AppJar
  56. appJar na Pythonhosted
    http://pythonhosted.org/appJar/
  57. appJar widgets
    http://appjar.info/pythonWidgets/
  58. Stránky projektu PyGTK
    http://www.pygtk.org/
  59. PyGTK (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  60. Stránky projektu PyGObject
    https://wiki.gnome.org/Pro­jects/PyGObject
  61. Stránky projektu Kivy
    https://kivy.org/#home
  62. Stránky projektu PyQt
    https://riverbankcomputin­g.com/software/pyqt/intro
  63. PyQt (Wikipedia)
    https://cs.wikipedia.org/wiki/PyGTK
  64. Stránky projektu PySide
    https://wiki.qt.io/PySide
  65. PySide (Wikipedia)
    https://en.wikipedia.org/wiki/PySide
  66. Stránky projektu Kivy
    https://kivy.org/#home
  67. Kivy (framework, Wikipedia)
    https://en.wikipedia.org/wi­ki/Kivy_(framework)
  68. QML Applications
    http://doc.qt.io/qt-5/qmlapplications.html
  69. KDE
    https://www.kde.org/
  70. Qt
    https://www.qt.io/
  71. GNOME
    https://en.wikipedia.org/wiki/GNOME
  72. Category:Software that uses PyGTK
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGTK
  73. Category:Software that uses PyGObject
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_PyGObject
  74. Category:Software that uses wxWidgets
    https://en.wikipedia.org/wi­ki/Category:Software_that_u­ses_wxWidgets
  75. GIO
    https://developer.gnome.or­g/gio/stable/
  76. GStreamer
    https://gstreamer.freedesktop.org/
  77. GStreamer (Wikipedia)
    https://en.wikipedia.org/wi­ki/GStreamer
  78. Wax Gui Toolkit
    https://wiki.python.org/moin/Wax
  79. Python Imaging Library (PIL)
    http://infohost.nmt.edu/tcc/hel­p/pubs/pil/
  80. 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/
Našli jste v článku chybu?