Hlavní navigace

Tvorba GUI v Pythonu s PySide: další dostupné ovládací prvky

Pavel Tišnovský

Ve třetím článku o frameworku PySide si popíšeme práci s ovládacími prvky grafického uživatelského rozhraní. Tyto prvky totiž mají mnoho zajímavých a v dalších toolkitech neobvyklých vlastností.

Doba čtení: 32 minut

11. Pořadí posílání signálů po stisku tlačítka

12. Zaškrtávací pole (check box)

13. Nastavení a zjišťování stavu zaškrtávacích polí

14. Zaškrtávací pole se třemi stavy (tristate)

15. Nastavení a zjišťování stavu zaškrtávacích polí se třemi možnými stavy

16. Sdružení zaškrtávacích polí do skupin s exkluzivitou výběru

17. Praktická ukázka použití objektu typu QButtonGroup

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

19. Odkazy na Internetu

1. Tvorba GUI v Pythonu s využitím frameworku PySide: další dostupné ovládací prvky

K popisu možností nabízených populární knihovnou PySide se dostáváme již potřetí. Dnes se budeme zabývat těmi ovládacími prvky, které sice na první pohled mohou vypadat jednoduše až primitivně, ovšem knihovna PySide (resp. přesněji řečeno framework Qt, který je knihovnou PySide pouze „obalen“) umožňuje i takto jednoduché prvky používat takovými způsoby, které by si v jiných frameworcích vyžádaly použití mnohem komplikovanějších komponent. Postupně si popíšeme tyto ovládací prvky:

Komponenta Stručný popis
QLabel textové či grafické (obrázek, video) návěští
   
QPushButton klasické tlačítko
QRadioButton přepínací tlačítko
QCheckBox zaškrtávací tlačítko (pole)

Obrázek 1: Třídy představující widgety, kterými se budeme zabývat v navazujících kapitolách.

2. Textový popisek (návěští)

Zdánlivě nejjednodušším ovládacím prvkem mnoha grafických uživatelských rozhraní je textový popisek, nazývaný také (textové) návěští neboli label. Tento ovládací prvek plní v mnohých frameworcích pouze zcela pasivní úlohu, protože dokáže zobrazit jednoduchý neformátovaný text, a to mnohdy na jediném řádku. Ovšem ve frameworku PySide je tomu jinak, protože textová návěští zde mají mnohem širší oblasti použití. Mezi podporované vlastnosti patří zejména:

  1. Možnost zobrazení víceřádkového textu.
  2. Text může být naformátován, přičemž se pro formátování používá podmnožina jazyka HTML.
  3. Součástí formátování může být i odlišná barva jednotlivých znaků.
  4. K textu může být přiřazen i rastrový obrázek (pixmapa).
  5. Návěští může reagovat na klik vybraným tlačítkem myši.
  6. Text návěští je možné vybrat myší či klávesnicí (tato vlastnost se musí nakonfigurovat).
  7. Text návěští je dokonce možné i editovat (i tato vlastnost se musí nakonfigurovat).
  8. Návěští může obsahovat hypertextový odkaz, který se po výběru zobrazí v prohlížeči.
  9. V neposlední řadě si všimněte, že QLabel je odvozen od QFrame, což znamená, že okolo návěští je možné vytvořit různé typy rámečků.

K většině výše uvedených vlastností se postupně dopracujeme v navazujících kapitolách.

Obrázek 2: První typ widgetu už částečně známe z předchozích dvou částí tohoto seriálu. Povšimněte si, že QLabel je odvozen od QFrame.

3. Zobrazení textového návěští zobrazujícího neformátovaný text

Začneme ovšem jen pozvolna, protože si na začátku ukážeme, jak se textové návěští používá pro zobrazení jednoduchého neformátovaného textu. Vzhledem k tomu, že jsme na českém serveru, bude textový popisek obsahovat i znaky s nabodeníčky. PySide podporuje Unicode, takže si jen musíme dát pozor na to, aby byl Unicode použit i ve zdrojovém kódu, což platí především pro Python 2.x.

Na začátku zdrojového kódu nezapomeňte určit kódování (já ho nastavuji současně pro Vim, rozpoznávány jsou ale i jiné možnosti):

# vim: set fileencoding=utf-8

U řetězce předávaného konstruktoru návěští se ujistěte, že je v Unicode, a to i v Pythonu 2.x:

testLabel = QtGui.QLabel(u"Textové návěští")

Výsledek by měl vypadat následovně:

Obrázek 3: Správně zobrazené návěští ve chvíli, kdy všude používáme Unicode.

Pokud vyvíjíte aplikaci přímo v Pythonu 3.x a neuvede se explicitně prefix řetězce v kódování Unicode, může se (většinou až u zákazníka :-) objevit tato hrůza, pokud se aplikace spustí v Pythonu 2.x:

Obrázek 4: Nekorektně zobrazené návěští vinou neuvedeného kódování řetězce.

Podívejme se nyní na zdrojový kód prvního demonstračního příkladu, který byl použit pro vytvoření okna s jednoduchým textovým návěštím a taktéž s tlačítkem sloužícím pro uzavření aplikace. Pro jednoduchost používáme správce rozvržení QVBoxLayout, který jednotlivé komponenty umisťuje pod sebe. Podobnou šablonu budeme používat i u dalších příkladů:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QLabel widget")
 
        # textové návěští
        # pozor na nutnost použití prefixu "u" v Pythonu 2.x
        testLabel = QtGui.QLabel(u"Textové návěští")
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testLabel)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

4. Textový popisek používající vybrané HTML značky pro zformátování textu

Ve druhém příkladu si ukážeme další užitečnou vlastnost textového návěští. Tento ovládací prvek totiž dokáže rozpoznat, že mu předáváme nikoli běžný čistý text (plain text), ale část formátovaného textu s HTML. V tomto případě je HTML interpretováno, čehož je možné využít například pro zobrazení vícebarevného návěští. Mimochodem si opět povšimněte poctivého použití prefixu „u“:

text = u"<font color='black'>černá</font><br />" \
       u"<font color='blue'>modrá</font><br />" \
       u"<font color='red'>čevená</font><br />" \
       u"<font color='magenta'>fialová</font><br />" \
       u"<font color='green'>zelená</font><br />" \
       u"<font color='cyan'>azurová</font><br />" \
       u"<font color='yellow'>žlutá</font><br />" \
       u"<font color='white'>bílá</font><br />"
testLabel = QtGui.QLabel(text)

Takto vytvořené návěští se zobrazí následujícím způsobem:

Obrázek 5: Návěští, jehož text se interpretoval jako HTML.

Jakékoli snahy o interpretaci řetězce můžeme zakázat:

testLabel.setTextFormat(QtCore.Qt.PlainText)

Výsledek potom bude vypadat takto:

Obrázek 6: Návěští, kde se text zobrazil přesně tak, jak byl zapsán ve zdrojovém kódu (okno bylo zkráceno, protože se nevešlo na plochu desktopu).

Úplný zdrojový kód dnešního druhé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 widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QLabel widget")
 
        # textové návěští
        # pozor na nutnost použití prefixu "u" v Pythonu 2.x
        text = u"<font color='black'>černá</font><br />" \
               u"<font color='blue'>modrá</font><br />" \
               u"<font color='red'>čevená</font><br />" \
               u"<font color='magenta'>fialová</font><br />" \
               u"<font color='green'>zelená</font><br />" \
               u"<font color='cyan'>azurová</font><br />" \
               u"<font color='yellow'>žlutá</font><br />" \
               u"<font color='white'>bílá</font><br />"
        testLabel = QtGui.QLabel(text)
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testLabel)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

5. Styly rámců zobrazených okolo popisku i okolo dalších vybraných widgetů

Již ve druhé kapitole jsem se zmínil o tom, že ovládací prvek návěští je reprezentován třídou QLabel, která je odvozena od třídy QFrame. To nám zcela správně napovídá, že se okolo návěští může zobrazit rámeček, jehož styl je možné programově nakonfigurovat tak, aby to co nejvíce vyhovovalo uživatelům. Nabídka stylů je poměrně široká, o čemž se ostatně můžeme přesvědčit i pohledem na následující tabulku ukazující různé styly okrajů kombinované s jejich variabilní šířkou:

Obrázek 7: Různé styly a šířky okrajů podporované všemi ovládacími prvky odvozenými od QFrame
Originál obrázku naleznete na wiki PySide, konkrétně na stránce http://pyside.github.io/doc­s/pyside/PySide/QtGui/QFra­me.html?highlight=qframe#Py­Side.QtGui.QFrame

Styl je možné specifikovat kombinací prvků z následujících dvou množin:

QFrame.NoFrame
QFrame.Box
QFrame.Panel
QFrame.StyledPanel
QFrame.HLine
QFrame.VLine
QFrame.WinPanel

a:

QFrame.Plain
QFrame.Raised
QFrame.Sunken

6. Ukázka změny typu rámce

Ve třetím demonstračním příkladu je ukázáno, jak je možné nastavit typ rámce u šesti návěští:

testLabel2 = QtGui.QLabel("Box")
testLabel3 = QtGui.QLabel("Panel")
testLabel4 = QtGui.QLabel("WinPanel")
testLabel5 = QtGui.QLabel("HLine")
testLabel6 = QtGui.QLabel("VLine")
testLabel7 = QtGui.QLabel("StyledPanel")
 
testLabel2.setFrameStyle(QtGui.QFrame.Box)
testLabel3.setFrameStyle(QtGui.QFrame.Panel)
testLabel4.setFrameStyle(QtGui.QFrame.WinPanel)
testLabel5.setFrameStyle(QtGui.QFrame.HLine)
testLabel6.setFrameStyle(QtGui.QFrame.VLine)
testLabel7.setFrameStyle(QtGui.QFrame.StyledPanel)

Navíc vytvoříme jedno návěští zcela bez textu, ovšem s nastaveným rámečkem na styl HLine, což ve skutečnosti není žádný rámeček, ale horizontální čára procházející přímo středem návěští:

# horizontální oddělovač
horizontalLine = QtGui.QLabel()
horizontalLine.setFrameStyle(QtGui.QFrame.HLine)

Po vložení všech ovládacích prvků do okna získáme takto vypadající aplikaci:

Obrázek 8: Osm textových návěští, každé s jiným rámečkem. Poslední návěští obsahuje jen horizontální čáru, ale žádný text.

Opět si uveďme celý zdrojový kód tohoto příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QLabel widget")
 
        # textová návěští
        testLabel1 = QtGui.QLabel("Normal/Default")
        testLabel2 = QtGui.QLabel("Box")
        testLabel3 = QtGui.QLabel("Panel")
        testLabel4 = QtGui.QLabel("WinPanel")
        testLabel5 = QtGui.QLabel("HLine")
        testLabel6 = QtGui.QLabel("VLine")
        testLabel7 = QtGui.QLabel("StyledPanel")
 
        testLabel2.setFrameStyle(QtGui.QFrame.Box)
        testLabel3.setFrameStyle(QtGui.QFrame.Panel)
        testLabel4.setFrameStyle(QtGui.QFrame.WinPanel)
        testLabel5.setFrameStyle(QtGui.QFrame.HLine)
        testLabel6.setFrameStyle(QtGui.QFrame.VLine)
        testLabel7.setFrameStyle(QtGui.QFrame.StyledPanel)
 
        # horizontální oddělovač
        horizontalLine = QtGui.QLabel()
        horizontalLine.setFrameStyle(QtGui.QFrame.HLine)
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testLabel1)
        layout.addWidget(testLabel2)
        layout.addWidget(testLabel3)
        layout.addWidget(testLabel4)
        layout.addWidget(testLabel5)
        layout.addWidget(testLabel6)
        layout.addWidget(testLabel7)
 
        layout.addWidget(horizontalLine)
 
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

7. Režimy zobrazení trojrozměrného reliéfu rámce

Ve skutečnosti není styl rámců zobrazených okolo návěští určen jedinou hodnotou, ale kombinací většího množství konstant. Podívejme se například na způsob kombinace stylů „Box“, „Panel“ a „WinPanel“ s konstantami „Plain“ (2D zobrazení), „Raised“ (okraje vystupují nad plochu okna) a„Sunkem“ (okraje jsou naopak vyryté do plochy okna):

testLabel11.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Plain)
testLabel21.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Plain)
testLabel31.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Plain)
 
testLabel12.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised)
testLabel22.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
testLabel32.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Raised)
 
testLabel13.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken)
testLabel23.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
testLabel33.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Sunken)

Všech devět kombinací stylů rámců se zobrazí takto:

Obrázek 9: Devět kombinací stylů rámců zobrazených okolo textového návěští.

Samozřejmě nezapomeneme uvést úplný zdrojový kód příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QLabel widget")
 
        # textová návěští
        testLabel11 = QtGui.QLabel("Plain Box")
        testLabel21 = QtGui.QLabel("Plain Panel")
        testLabel31 = QtGui.QLabel("Plain WinPanel")
 
        testLabel12 = QtGui.QLabel("Raised Box")
        testLabel22 = QtGui.QLabel("Raised Panel")
        testLabel32 = QtGui.QLabel("Raised WinPanel")
 
        testLabel13 = QtGui.QLabel("Sunken Box")
        testLabel23 = QtGui.QLabel("Sunken Panel")
        testLabel33 = QtGui.QLabel("Sunken WinPanel")
 
        testLabel11.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Plain)
        testLabel21.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Plain)
        testLabel31.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Plain)
 
        testLabel12.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Raised)
        testLabel22.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Raised)
        testLabel32.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Raised)
 
        testLabel13.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Sunken)
        testLabel23.setFrameStyle(QtGui.QFrame.Panel | QtGui.QFrame.Sunken)
        testLabel33.setFrameStyle(QtGui.QFrame.WinPanel | QtGui.QFrame.Sunken)
 
        # horizontální oddělovač
        horizontalLine = QtGui.QLabel()
        horizontalLine.setFrameStyle(QtGui.QFrame.HLine)
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QGridLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testLabel11, 1, 1)
        layout.addWidget(testLabel21, 2, 1)
        layout.addWidget(testLabel31, 3, 1)
 
        layout.addWidget(testLabel12, 1, 2)
        layout.addWidget(testLabel22, 2, 2)
        layout.addWidget(testLabel32, 3, 2)
 
        layout.addWidget(testLabel13, 1, 3)
        layout.addWidget(testLabel23, 2, 3)
        layout.addWidget(testLabel33, 3, 3)
 
        layout.addWidget(horizontalLine, 4, 2)
 
        layout.addWidget(quitButton, 5, 2)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

8. Textový popisek, jehož text je možné vybrat nebo i editovat

Textové návěští nemusí být představováno pouze neměnným textem, protože programátor může umožnit uživatelům výběr tohoto textu (myší i klávesnicí) a popř. dokonce i editaci zobrazeného textu. Zatímco editace je podle mého názoru spíše technologická zajímavost, možnost výběru textu na návěští je v mnoha případech velmi užitečná (ostatně u webových aplikací lze myší vybrat prakticky libovolný text bez omezení):

Obrázek 10: Zdánlivě obyčejná návěští.

Konfigurace návěští, jehož obsah je možné vybrat:

testLabel1.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)

Obrázek 11: Výběr textu v prvním návěští pomocí myši.

Konfigurace návěští, jehož obsah je možné vybrat i editovat:

testLabel2.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextEditable)

Obrázek 12: Editace textu ve druhém návěští po kliknutí levým tlačítkem myši (povšimněte si textového kurzoru).

Opět si uveďme celý zdrojový kód 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 widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QLabel widget")
 
        # textové návěští
        # pozor na nutnost použití prefixu "u" v Pythonu 2.x
        testLabel1 = QtGui.QLabel(u"tento text je možné vybírat")
        testLabel2 = QtGui.QLabel(u"tento text je možné editovat")
 
        # text v návěští bude možné vybírat
        testLabel1.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse)
 
        # text v návěští bude možné vybírat a editovat
        testLabel2.setTextInteractionFlags(QtCore.Qt.TextSelectableByMouse | QtCore.Qt.TextEditable)
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testLabel1)
        layout.addWidget(testLabel2)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

9. Aktivní textový popisek – zobrazení stránky ve webovém prohlížeči po výběru odkazu

V posledním příkladu, v němž se zabýváme „obyčejným“ textovým návěštím, je na hlavní okno aplikace umístěn odkaz, po jehož výběru (kliknutím levým tlačítkem myši) se otevře cíl odkazu ve webovém prohlížeči. Výchozí webový prohlížeč je vybrán v konfiguraci desktopového prostředí a odkaz (link) se vytvoří poměrně jednoduše a přímočaře:

# textové návěští
# pozor na nutnost použití prefixu "u" v Pythonu 2.x
testLabel = QtGui.QLabel(u"<a href='http://www.root.cz'>Root</a>")
 
# pro jistotu explicitně nastavíme
testLabel.setTextFormat(QtCore.Qt.RichText)
 
# povolení otevření stránky v browseru
testLabel.setOpenExternalLinks(True)

Pozor si musíte dát jen na to, aby byl odkaz skutečně zapsán formou standardního hypertextového odkazu v HTML, jinak nebude link funkční!

Obrázek 13: Okno s funkčním hypertextovým odkazem.

Samozřejmě nezapomeneme uvést úplný zdrojový kód příkladu s návěštím nakonfigurovaným do funkce hypertextového odkazu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QLabel widget")
 
        # textové návěští
        # pozor na nutnost použití prefixu "u" v Pythonu 2.x
        testLabel = QtGui.QLabel(u"<a href='http://www.root.cz'>Root</a>")
 
        # pro jistotu explicitně nastavíme
        testLabel.setTextFormat(QtCore.Qt.RichText)
 
        # povolení otevření stránky v browseru
        testLabel.setOpenExternalLinks(True)
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testLabel)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

10. Ovládací prvek QPushButton a události generované po jeho stisku

S dalším ovládacím prvkem jsme se již setkali v předchozích dvou částech tohoto seriálu, takže si dnes jen řekneme, jaké signály lze společně s ním využít. Jedná se o widget nazvaný QPushButton, který se skutečně používá pro vkládání běžného tlačítka do oken a dialogů. Z diagramu tříd zobrazeného pod tímto odstavcem je patrné, že QPushButton je odvozený od třídy QAbstractButton, z níž dědí své základní chování (ovšem již ne vzhled). Na rozdíl od výše popsaného widgetu QLabel zde však mezi předky nepatří třída QFrame, což mj. znamená, že pokud budeme chtít okolo tlačítka vytvořit nějaký konfigurovatelný okraj, je nutné tlačítko vložit do dalšího widgetu.

Obrázek 14: Hierarchie tříd s vyznačením třídy představující widget QPushButton.

Ve třídě QAbstractButton jsou deklarovány čtyři signály:

Jméno signálu Význam
clicked vyslán po stisku a puštění tlačítka
pressed vyslán ve chvíli, kdy došlo ke stlačení
released vyslán ve chvíli, kdy došlo k puštění tlačítka
toggled vyslán po změně stavu tlačítka (zapnuto/vypnuto)

Ve skutečnosti jsou však společně s widgetem QPushButton používány pouze první tři signály, většinou dokonce pouze signál clicked. Pokud je totiž nutné vložit do okna aplikace přepínací tlačítko (tedy spíše přepínač), je výhodnější použít QToolButton, protože právě u nástrojového pruhu se setkáme s nutností mít jedno z tlačítek zamáčknuté (typickým příkladem je grafický editor, v němž je vybrán vždy jeden z kreslicích nástrojů).

11. Pořadí posílání signálů po stisku tlačítka

Podívejme se nyní na způsob, jakým se používají první tři signály, tedy clicked, pressed a released. V testovací aplikaci vytvoříme běžné tlačítko a zaregistrujeme příjemce těchto tří signálů. Vytvoření tlačítka se provede jednoduše:

# testovací tlačítko
testButton = QtGui.QPushButton("Press me")

Navázání jediné callback funkce na tři signály (ve skutečnosti se zavolá anonymní funkce, která callback funkci předá další parametr):

# navázání akce na signál
testButton.clicked.connect(lambda: buttonEvent('clicked'))
testButton.pressed.connect(lambda: buttonEvent('pressed'))
testButton.released.connect(lambda: buttonEvent('released'))

Samotná callback funkce je primitivní:

def buttonEvent(eventName):
    print("Event " + eventName)

Po spuštění aplikace se podíváme, v jakém pořadí se budou informace o příjmu signálů zobrazovat po stisku (a puštění) tlačítka:

Event pressed
Event released
Event clicked

Informace o stisku je samozřejmě poslána ihned ve chvíli, kdy uživatel na tlačítko klikl. Po dokončení kliku se nejdříve vyšle signál o puštění tlačítka a teprve po něm signál o samotném kliku. To v praxi znamená, že pokud budete chtít reagovat již na první stisk tlačítka, je nutné použít signál pressed, na rozdíl od některých dalších widget toolkitů.

Obrázek 15: Okno s testovacím tlačítkem.

Demonstrační příklad s testovacím tlačítkem 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
 
 
def buttonEvent(eventName):
    print("Event " + eventName)
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QButton signals")
 
        # testovací tlačítko
        testButton = QtGui.QPushButton("Press me")
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(testButton)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # navázání akce na signál
        testButton.clicked.connect(lambda: buttonEvent('clicked'))
        testButton.pressed.connect(lambda: buttonEvent('pressed'))
        testButton.released.connect(lambda: buttonEvent('released'))
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

12. Zaškrtávací pole (check box)

Dalším ovládacím prvkem, který má již složitější chování, než jednoduchý QPushButton, je widget nazvaný QCheckBox. I tento widget je odvozen od třídy QAbstractButton, takže může při změně svého stavu vysílat již zmíněné čtyři typy signálů:

Jméno signálu Význam
clicked vyslán po stisku a puštění tlačítka
pressed vyslán ve chvíli, kdy došlo ke stlačení
released vyslán ve chvíli, kdy došlo k puštění tlačítka
toggled vyslán po změně stavu tlačítka (zapnuto/vypnuto)

Obrázek 16: Hierarchie tříd s vyznačením třídy představující widget QCheckBox.

Widgety QCheckBox mohou být použity různým způsobem:

  1. Každé zaškrtávací tlačítko může pracovat samostatně a mít jen dva možné stavy (zaškrtnuto, nezaškrtnuto).
  2. Každé zaškrtávací tlačítko může pracovat samostatně a mít tři možné stavy (zaškrtnuto, nezaškrtnuto, třetí stav reprezentovaný znakem -, který může znamenat „žádná změna“).
  3. Tlačítka mohou být spojena do skupiny s exkluzivitou výběru jen jediného tlačítka v daný okamžik. Jedná se vlastně o obdobu přepínačů, které si popíšeme o několik kapitol dále.

13. Nastavení a zjišťování stavu zaškrtávacích polí

V prvním příkladu, který je věnován použití zaškrtávacích tlačítek, si ukážeme základní způsob použití těchto prvků GUI. Nejprve vytvoříme dvojici tlačítek a nastavíme jejich stav, tj. zda je ve výchozím nastavení tlačítko zaškrtnuto či nikoli:

# testovací zaškrtávací tlačítka
self.testCheckBox1 = QtGui.QCheckBox("check box 1")
self.testCheckBox2 = QtGui.QCheckBox("check box 2")
self.testCheckBox1.setCheckState(QtCore.Qt.Unchecked)
self.testCheckBox2.setCheckState(QtCore.Qt.Checked)

Při běhu aplikace se stav zaškrtávacích tlačítek může zjistit takto:

state = "checked" if checkbox.isChecked() else "unchecked"
print("Checkbox {name} is {state}".format(name=name, state=state))

Metodu isChecked můžeme použít jen ve chvíli, kdy používáme tlačítka se dvěma možnými stavy!

Obrázek 17: Zaškrtávací tlačítka se dvěma možnými stavy.

Zdrojový kód 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
 
 
def buttonEvent(eventName):
    print("Event " + eventName)
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QButton signals")
 
        # testovací zaškrtávací tlačítka
        self.testCheckBox1 = QtGui.QCheckBox("check box 1")
        self.testCheckBox2 = QtGui.QCheckBox("check box 2")
        self.testCheckBox1.setCheckState(QtCore.Qt.Unchecked)
        self.testCheckBox2.setCheckState(QtCore.Qt.Checked)
 
        # tlačítko pro zjištění stavů checkboxů
        testButton = QtGui.QPushButton("Print state")
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(self.testCheckBox1)
        layout.addWidget(self.testCheckBox2)
        layout.addWidget(testButton)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # po stisku testovacího tlačítka se zavolá metoda
        testButton.clicked.connect(self.printState)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def printState(self):
        print("-" * 50)
        MainWindow.printStateForCheckbox("#1", self.testCheckBox1)
        MainWindow.printStateForCheckbox("#2", self.testCheckBox2)
 
    @staticmethod
    def printStateForCheckbox(name, checkbox):
        state = "checked" if checkbox.isChecked() else "unchecked"
        print("Checkbox {name} is {state}".format(name=name, state=state))
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

14. Zaškrtávací pole se třemi stavy (tristate)

V případě, že je zapotřebí zobrazit tři možné stavy, například „povoleno, zakázáno, beze změny“, lze pro tento účel využít třístavová zaškrtávací pole. Musíme si však uvědomit, že je nutné explicitně povolit použití třetího stavu a navíc se při rozhodování, který stav je aktuálně zvolen, již nemůže použít metoda isChecked s pravdivostní návratovou hodnotou, ale složitější metoda checkState vracející jednu z konstant:

  • QtCore.Qt.CheckState.Unchecked
  • QtCore.Qt.CheckState.Checked
  • QtCore.Qt.CheckState.PartiallyChecked

Obrázek 18: Zaškrtávací pole se třemi možnými stavy.

Třístavová zaškrtávací pole se vytvoří takto:

self.testCheckBox3 = QtGui.QCheckBox("check box 3")
self.testCheckBox4 = QtGui.QCheckBox("check box 4")
self.testCheckBox5 = QtGui.QCheckBox("check box 5")
 
# třístavové checkboxy
self.testCheckBox3.setTristate(True)
self.testCheckBox4.setTristate(True)
self.testCheckBox5.setTristate(True)

Poté je již možné nastavit jejich výchozí stav:

self.testCheckBox3.setCheckState(QtCore.Qt.Unchecked)
self.testCheckBox4.setCheckState(QtCore.Qt.PartiallyChecked)
self.testCheckBox5.setCheckState(QtCore.Qt.Checked)

Zjištění stavu konkrétního zaškrtávacího pole je již snadné:

state = checkbox.checkState()

15. Nastavení a zjišťování stavu zaškrtávacích polí se třemi možnými stavy

V následujícím demonstračním příkladu je ukázána kombinace zaškrtávacích polí se dvěma stavy i se třemi možnými stavy:

#!/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
 
 
def buttonEvent(eventName):
    print("Event " + eventName)
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QButton signals")
 
        # testovací zaškrtávací tlačítka
        self.testCheckBox1 = QtGui.QCheckBox("check box 1")
        self.testCheckBox2 = QtGui.QCheckBox("check box 2")
        self.testCheckBox3 = QtGui.QCheckBox("check box 3")
        self.testCheckBox4 = QtGui.QCheckBox("check box 4")
        self.testCheckBox5 = QtGui.QCheckBox("check box 5")
 
        # dvoustavové checkboxy
        self.testCheckBox1.setCheckState(QtCore.Qt.Unchecked)
        self.testCheckBox2.setCheckState(QtCore.Qt.Checked)
 
        # třístavové checkboxy
        self.testCheckBox3.setTristate(True)
        self.testCheckBox4.setTristate(True)
        self.testCheckBox5.setTristate(True)
        self.testCheckBox3.setCheckState(QtCore.Qt.Unchecked)
        self.testCheckBox4.setCheckState(QtCore.Qt.PartiallyChecked)
        self.testCheckBox5.setCheckState(QtCore.Qt.Checked)
 
        # horizontální oddělovač
        horizontalLine = QtGui.QLabel()
        horizontalLine.setFrameStyle(QtGui.QFrame.HLine)
 
        # tlačítko pro zjištění stavů checkboxů
        testButton = QtGui.QPushButton("Print state")
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(self.testCheckBox1)
        layout.addWidget(self.testCheckBox2)
        layout.addWidget(horizontalLine)
        layout.addWidget(self.testCheckBox3)
        layout.addWidget(self.testCheckBox4)
        layout.addWidget(self.testCheckBox5)
        layout.addWidget(testButton)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # po stisku testovacího tlačítka se zavolá metoda
        testButton.clicked.connect(self.printState)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def printState(self):
        print("-" * 50)
        MainWindow.printStateForCheckbox("#1", self.testCheckBox1)
        MainWindow.printStateForCheckbox("#2", self.testCheckBox2)
        MainWindow.printStateForCheckbox("#3", self.testCheckBox3)
        MainWindow.printStateForCheckbox("#4", self.testCheckBox4)
        MainWindow.printStateForCheckbox("#5", self.testCheckBox5)
 
    @staticmethod
    def printStateForCheckbox(name, checkbox):
        state = checkbox.checkState()
        print("Checkbox {name} is in state {state}".format(name=name, state=state))
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

16. Sdružení zaškrtávacích polí do skupin s exkluzivitou výběru

V některých případech může být vyžadováno, aby se určitá zaškrtávací pole nedala vybrat současně. Tento problém je sice možné řešit programově (reakcí na signály s nastavením stavu ostatních polí), je to však zbytečně komplikované. Elegantnějším řešením je spojení zaškrtávacích polí do jediné skupiny. Ta přitom není nijak vizuálně prezentována, takže taková pole mohou být na dialogu rozmístěna podle potřeb programátora či zákazníka.

Obrázek 19: Skupina zaškrtávacích polí, z nichž může být vybráno jen jedno.

Obrázek 20: Skupina zaškrtávacích polí, z nichž může být vybráno jen jedno.

Skupinu tlačítek je nutné vytvořit explicitně konstruktorem QButtonGroup a následně je nutné nastavit „exkluzivitu výběru“, tj. že lze vybrat maximálně jediné zaškrtávací pole:

self.buttonGroup = QtGui.QButtonGroup()
self.buttonGroup.setExclusive(True)

Jednotlivá zaškrtávací pole vytvoříme obvyklým způsobem:

self.testCheckBox1 = QtGui.QCheckBox("check box 1")
self.testCheckBox2 = QtGui.QCheckBox("check box 2")
self.testCheckBox3 = QtGui.QCheckBox("check box 3")
self.testCheckBox4 = QtGui.QCheckBox("check box 4")
self.testCheckBox5 = QtGui.QCheckBox("check box 5")

Ovšem posléze je musíme přidat do skupiny (nebo více skupin):

self.buttonGroup.addButton(self.testCheckBox1)
self.buttonGroup.addButton(self.testCheckBox2)
self.buttonGroup.addButton(self.testCheckBox3)
self.buttonGroup.addButton(self.testCheckBox4)
self.buttonGroup.addButton(self.testCheckBox5)

Zjištění, které tlačítko bylo zaškrtnuto, je velmi snadné – není zapotřebí (typicky v programové smyčce) procházet všemi poli a volat isChecked, ale použít namísto toho metodu checkedButton:

checked = self.buttonGroup.checkedButton()

Tato metoda vrátí instanci tlačítka/pole, ovšem text na tlačítku taktéž získáme snadno:

print("Checked button: " + self.buttonGroup.checkedButton().text())

17. Praktická ukázka použití objektu typu QButtonGroup

V následujícím demonstračním příkladu je ukázáno vytvoření několika zaškrtávacích polí sdružených do jedné skupiny. Sami si vyzkoušejte, že lze vždy vybrat (zaškrtnout) maximálně jedno pole:

MIF18 tip v článku témata

#!/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
 
 
def buttonEvent(eventName):
    print("Event " + eventName)
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindow(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("QButton signals")
 
        self.buttonGroup = QtGui.QButtonGroup()
        self.buttonGroup.setExclusive(True)
 
        # testovací zaškrtávací tlačítka
        self.testCheckBox1 = QtGui.QCheckBox("check box 1")
        self.testCheckBox2 = QtGui.QCheckBox("check box 2")
        self.testCheckBox3 = QtGui.QCheckBox("check box 3")
        self.testCheckBox4 = QtGui.QCheckBox("check box 4")
        self.testCheckBox5 = QtGui.QCheckBox("check box 5")
 
        self.buttonGroup.addButton(self.testCheckBox1)
        self.buttonGroup.addButton(self.testCheckBox2)
        self.buttonGroup.addButton(self.testCheckBox3)
        self.buttonGroup.addButton(self.testCheckBox4)
        self.buttonGroup.addButton(self.testCheckBox5)
 
        # stav checkboxů
        self.testCheckBox1.setCheckState(QtCore.Qt.Checked)
 
        # tlačítko pro zjištění stavů checkboxů
        testButton = QtGui.QPushButton("Print state")
 
        # tlačítko pro ukončení aplikace
        quitButton = QtGui.QPushButton("Quit")
 
        # vytvoření správce geometrie
        layout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        layout.addWidget(self.testCheckBox1)
        layout.addWidget(self.testCheckBox2)
        layout.addWidget(self.testCheckBox3)
        layout.addWidget(self.testCheckBox4)
        layout.addWidget(self.testCheckBox5)
        layout.addWidget(testButton)
        layout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(layout)
 
        # po stisku testovacího tlačítka se zavolá metoda
        testButton.clicked.connect(self.printState)
 
        # navázání akce na stisk tlačítka pro ukončení aplikace
        quitButton.clicked.connect(self.quit)
 
    def printState(self):
        print("-" * 50)
        MainWindow.printStateForCheckbox("#1", self.testCheckBox1)
        MainWindow.printStateForCheckbox("#2", self.testCheckBox2)
        MainWindow.printStateForCheckbox("#3", self.testCheckBox3)
        MainWindow.printStateForCheckbox("#4", self.testCheckBox4)
        MainWindow.printStateForCheckbox("#5", self.testCheckBox5)
        print("Checked button: " + self.buttonGroup.checkedButton().text())
 
    @staticmethod
    def printStateForCheckbox(name, checkbox):
        state = checkbox.checkState()
        print("Checkbox {name} is in state {state}".format(name=name, state=state))
 
    def run(self, app):
        # zobrazení okna na obrazovce
        self.show()
        # vstup do smyčky událostí (event loop)
        app.exec_()
 
    def quit(self):
        print("Closing...")
        self.close()
 
 
def main():
    app = QtGui.QApplication(sys.argv)
    MainWindow().run(app)
 
 
if __name__ == '__main__':
    main()

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

Zdrojové kódy všech jedenácti dnes popsaných demonstračních příkladů byly opět, podobně jako 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:

Obrázek 21: Skupina přepínacích tlačítek, která bude popsaná příště.

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