Hlavní navigace

Tvorba GUI v Pythonu s využitím frameworku PySide: widgety pro textový vstup

Pavel Tišnovský

Dnes si popíšeme další používané ovládací prvky. Zaměříme se na prvky pro vstup jednořádkového nebo víceřádkového textu. Jedná se o widgety QLineEdit a QTextEdit, přičemž druhý prvek lze použít mj. i ve funkci HTML prohlížeče.

Doba čtení: 29 minut

Obsah

1. Tvorba GUI v Pythonu s využitím frameworku PySide: widgety pro textový vstup

2. Jednořádkové vstupní textové pole

3. První demonstrační příklad: zobrazení textového pole, čtení zapsaného textu

4. Nastavení výchozího textu

5. Omezení maximálního počtu zapsaných znaků

6. Nastavení zarovnání textu

7. Druhý demonstrační příklad: vylepšené textové pole

8. Definice vstupní masky pro zápis specifických vstupních dat

9. Třetí demonstrační příklad: vylepšené textové pole se vstupní maskou

10. Použití validátorů pro textové pole

11. Čtvrtý demonstrační příklad: validátor typu QIntValidator

12. Pátý demonstrační příklad: validátor typu QRegExpValidator

13. Ovládací prvek pro zápis i zobrazení víceřádkových dokumentů s formátováním

14. Šestý demonstrační příklad: widget QTextEdit ve funkci víceřádkového textového pole

15. Základní zpracování HTML

16. Sedmý demonstrační příklad: widget QTextEdit ve funkci jednoduchého prohlížeče HTML stránek

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

18. Odkazy na Internetu

1. Tvorba GUI v Pythonu s využitím frameworku PySide: widgety pro textový vstup

V dnešním pokračování seriálu o tvorbě aplikací s grafickým uživatelským rozhraním v Pythonu se budeme zabývat popisem dalších ovládacích prvků, které nalezneme v knihovně PySide. Zaměříme se přitom na widgety sloužící pro vstup textu, ať již textu jednořádkového, víceřádkového či dokonce tzv. rich textu, tj. textu, který je naformátován a který může v případě potřeby obsahovat i další objekty. V knihovně PySide nalezneme následující čtyři ovládací prvky, které jsou pro tyto účely připravené:

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

2. Jednořádkové vstupní textové pole

Prvním ovládacím prvkem, s nímž se v dnešním článku seznámíme, je widget nazvaný jednoduše QLineEdit. Jak již jeho název napovídá, je tento prvek určen pro vstup jednořádkového textu a vzhledem k velmi časté potřebě zadat do aplikace jediný údaj (adresa, jméno uživatele, jeho heslo, PIN, název vyhledávaného výrobku atd.) patří tento typ widgetů mezi nejpoužívanější prvky grafického uživatelského rozhraní vůbec. Ovšem aby nedošlo k omylu: QLineEdit je sice skutečně možné použít pro pouhý vstup textu, ale jeho možnosti jsou ve skutečnosti větší, protože je například umožněno specifikovat masku určující, jak má text zadávaný uživatelem vypadat, takže je možné například připravit vstupní textové pole určené pro zápis strukturovaného telefonního čísla, DIČ atd. Dále lze k textovému poli přidat takzvaný validátor, což je objekt kontrolující, zda uživatelem zapsaný text odpovídá nějakým kritériím, například zda se jedná o celé číslo z určeného rozsahu, platné datum apod. Vše si samozřejmě ukážeme v několika demonstračních příkladech.

Obrázek 1: Několik vstupních textových polí v dialogu pro vytvoření nového projektu v IDE Eric.

3. První demonstrační příklad: zobrazení textového pole, čtení zapsaného textu

Ukažme si nyní nejjednodušší formu jednořádkového vstupního textového pole. To vytvoříme snadno konstruktorem QLineEdit, kterému předáme jediný parametr – referenci na kontejner, ve kterém se bude textové pole nacházet:

lineEdit = QtGui.QLineEdit(self)

Obrázek 2: Textové pole se zobrazí zcela běžným způsobem a při práci s textem je možné použít schránku (clipboard), selection buffer atd.

Textové pole umístíme běžným způsobem do kontejneru s využitím správců geometrie. Aby byl příklad trošku složitější, zkombinujeme možnosti dvou správců geometrie: vertikálního a horizontálního:

# vytvoření prvního správce geometrie
topLayout = QtGui.QVBoxLayout()
 
# vytvoření druhého správce geometrie
subLayout = QtGui.QHBoxLayout()
 
# umístění widgetů do okna
topLayout.addWidget(self.lineEdit)
topLayout.addLayout(subLayout)
 
# tlačítka vložíme do druhého správce geometrie
subLayout.addWidget(showTextButton)
subLayout.addWidget(quitButton)
 
# nastavení správce geometrie a vložení všech komponent do okna
self.setLayout(topLayout)

Text zadaný uživatelem do vstupního textového pole přečteme pomocí metody text():

text = self.lineEdit.text()

Obrázek 3: Při práci s textovým polem je plně podporován Unicode, a to jak při zápisu textu, tak i při jeho čtení Pythonovským programem.

Následuje výpis zdrojového kódu prvního demonstračního příkladu, v němž je použito textové pole a po stisku tlačítka „Show text“ se zobrazí dialog s textem, který uživatel do pole zapsal:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        showTextButton = self.prepareShowTextButton()
        self.lineEdit = self.prepareLineEdit()
 
        # vytvoření prvního správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # vytvoření druhého správce geometrie
        subLayout = QtGui.QHBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.lineEdit)
        topLayout.addLayout(subLayout)
 
        # tlačítka vložíme do druhého správce geometrie
        subLayout.addWidget(showTextButton)
        subLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareLineEdit(self):
        # jednořádkové vstupní textové pole
        lineEdit = QtGui.QLineEdit(self)
        return lineEdit
 
    def showTextDialog(self):
        msgBox = QtGui.QMessageBox()
        text = self.lineEdit.text()
        msgBox.setText(u'Text: {t}'.format(t=text))
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("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()

4. Nastavení výchozího textu

Pokud je zapotřebí, aby se v textovém poli už při zobrazení okna nebo dialogu nacházel výchozí text, lze pro tento účel použít metodu nazvanou příhodně setText, které se řetězec předá:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setText(u'příliš žluťoučký kůň')

Poznámka: prefix „u“ je u řetězce uveden kvůli kompatibilitě s Pythonem 2.x.

Alternativně je možné text předat již konstruktoru objektů typu QLineEdit. Jedná se o první parametr, protože reference na kontejner, do kterého se textové pole ukládá, se posune na druhou pozici:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(u'příliš žluťoučký kůň', self)

Obrázek 4: Jednořádkové textové pole s výchozím textem.

5. Omezení maximálního počtu zapsaných znaků

Poměrně často se setkáme s nutností omezit maximální počet znaků, které se do textového pole mohou zadat. Výchozí maximální kapacita je totiž nastavena na hodnotu 32767, což je pro naprostou většinu aplikací příliš mnoho. Omezení maximálního počtu znaků je snadné – stačí zavolat metodu setMaxLength, které se počet znaků předá:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setText(u'příliš žluťoučký kůň')
lineEdit.setMaxLength(20)

Poznámka: zadaná hodnota 20 skutečně odpovídá počtu znaků, nikoli bajtů. Pozor je nutné dát především na to, že například výše použitý řetězec „příliš žluťoučký kůň“ má přesně dvacet znaků, ovšem například při použití UTF-8 je jeho délka 30 bajtů. Na rozdíly narazíte například při použití některých relačních databází, které počítají délku řetězců v bajtech.

Pokud se uživatel pokusí zapsat delší řetězec, nebude tato operace povolena. Ani při snaze zkopírovat delší řetězec přes schránku se nezapíše více, než nastavený maximální počet znaků. Totéž ovšem platí i pro text nastavený přes metodu setText. Ostatně si vyzkoušejte sami, co se stane:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setText(u'tento řetězec je v každém případě delší než 20 znaků')
lineEdit.setMaxLength(20)

6. Nastavení zarovnání textu

V některých případech může být výhodné, aby byl text v jednořádkovém textovém poli zarovnaný doprava či na střed a nikoli doleva. I toho je možné dosáhnout, a to velmi snadno. Podívejme se na následující úryvek kódu, v němž je zarovnání nastaveno s využitím metody nazvané setAlignment:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setText(u'příliš žluťoučký kůň')
lineEdit.setMaxLength(20)
lineEdit.setAlignment(QtCore.Qt.AlignRight)

Obrázek 5: Jednořádkové textové pole s výchozím textem, který je zarovnán doprava.

Pro nastavení zarovnání je možné použít tyto konstanty a jejich kombinace:

Konstanta Význam
Qt.AlignLeft zarovnání doleva (výchozí hodnota)
Qt.AlignRight zarovnání doprava
Qt.AlignHCenter vycentrování textu
Qt.AlignJustify u tohoto widgetu odpovídá Qt.AlignLeft
   
Qt.AlignTop vertikální zarovnání nahoru
Qt.AlignBottom vertikální zarovnání dolů
Qt.AlignVCenter vertikální zarovnání na střed (výchozí hodnota)
   
Qt.AlignCenter horizontální i vertikální zarovnání na střed

7. Druhý demonstrační příklad: vylepšené textové pole

V dnešním druhém demonstračním příkladu je ukázáno několik modifikací textového pole (všechny jsme si popsali v předchozích třech kapitolách):

  1. Je specifikován výchozí text, který je v textovém poli implicitně zobrazen.
  2. Maximální počet znaků, které je možné zapsat, je omezen na 20.
  3. Text je zarovnán doprava a nikoli doleva (horizontální zarovnání na střed zůstalo nezměněno, většinou ani nemá příliš velký význam se ho pokoušet změnit).

Obrázek 6: Po přečtení textu z widgetu QLineEdit získáme plnohodnotný text v Unicode.

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

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        showTextButton = self.prepareShowTextButton()
        self.lineEdit = self.prepareLineEdit()
 
        # vytvoření prvního správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # vytvoření druhého správce geometrie
        subLayout = QtGui.QHBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.lineEdit)
        topLayout.addLayout(subLayout)
 
        # tlačítka vložíme do druhého správce geometrie
        subLayout.addWidget(showTextButton)
        subLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareLineEdit(self):
        # jednořádkové vstupní textové pole
        lineEdit = QtGui.QLineEdit(self)
        lineEdit.setText(u'příliš žluťoučký kůň')
        lineEdit.setMaxLength(20)
        lineEdit.setAlignment(QtCore.Qt.AlignRight)
        return lineEdit
 
    def showTextDialog(self):
        msgBox = QtGui.QMessageBox()
        text = self.lineEdit.text()
        msgBox.setText(u'Text: {t}'.format(t=text))
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("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()

8. Definice vstupní masky pro zápis specifických vstupních dat

Pro jednořádkové textové pole je možné specifikovat i takzvanou masku, která určuje, jaké typy znaků a na jakých pozicích se mohou v poli objevit. Ukažme si jednoduchý příklad. Pokud budeme chtít zajistit, aby uživatel do textového pole mohl zadat pouze devítimístné telefonní číslo (a žádné další znaky), může použít tuto masku:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setMaxLength(9)
lineEdit.setInputMask('999999999')

Obrázek 7: Takto vypadá textové pole, v němž je zadaná pouze vstupní maska, ale žádný text napsaný uživatelem.

Maska však může být i složitější. V případě, že číslice mají být odděleny mezerou (nebo libovolným jiným znakem), lze to opět snadno zařídit:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setMaxLength(11)
lineEdit.setInputMask('999 999 999')

Obrázek 8: Zápis telefonního čísla. Mezery mezi trojicemi číslic jsou do pole vloženy automaticky.

Při definici masky se používají následující zástupné znaky:

Zástupný znak Význam
A znaky velké i malé abecedy
a dtto, ovšem znak(y) nejsou na daném místě povinné
N znaky velké i malé abecedy + číslice
n dtto, ovšem znak(y) nejsou na daném místě povinné
X libovolný znak (povinný)
x libovolný znak (nepovinný)
9 číslice 0–9
0 nepovinná číslice 0–9
D číslice 1–9 (bez nuly)
d nepovinná číslice 1–9
# číslice 0–9 popř. znak +, –
H hexadecimální číslice 0–9, a-f, A-F
h nepovinná hexadecimální číslice 0–9, a-f, A-F
B binární číslice 0 nebo 1
b nepovinná binární číslice 0 nebo 1
> další znaky budou převedeny na velká písmena
< další znaky budou převedeny na malá písmena
! ruší platnost > a <
\

Obrázek 9: Tuto podobu má telefonní číslo přečtení z widgetu. Povšimněte si existencí mezer předepsaných maskou.

Dokonce je možné určit, jaké znaky se v textovém poli zobrazí na těch místech, která mají být uživatelem vyplněna. Tento znak zapište za středník. Pro jednoduchost použijeme podtržítko, ale můžete zkusit použít hvězdičku, otazník atd.:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setMaxLength(11)
lineEdit.setInputMask('999 999 999;_')

Poznámka: podtržítka jsou sice ve vstupním textovém poli viditelná, ale ve skutečnosti nejsou součástí textu vráceného metodou text().

9. Třetí demonstrační příklad: vylepšené textové pole se vstupní maskou

Ve třetím demonstračním příkladu je ukázáno, jak lze použít textové pole se vstupní maskou. Maskou specifikujeme, že textové pole bude akceptovat zápis devítimístného telefonního čísla, v němž jsou vždy trojice číslic od sebe odděleny mezerou. Podívejme se na 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 MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        showTextButton = self.prepareShowTextButton()
        self.lineEdit = self.prepareLineEdit()
 
        # vytvoření prvního správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # vytvoření druhého správce geometrie
        subLayout = QtGui.QHBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.lineEdit)
        topLayout.addLayout(subLayout)
 
        # tlačítka vložíme do druhého správce geometrie
        subLayout.addWidget(showTextButton)
        subLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareLineEdit(self):
        # jednořádkové vstupní textové pole
        lineEdit = QtGui.QLineEdit(self)
        lineEdit.setPlaceholderText(u'telefonní číslo')
        lineEdit.setMaxLength(11)
        lineEdit.setInputMask('999 999 999;_')
        return lineEdit
 
    def showTextDialog(self):
        msgBox = QtGui.QMessageBox()
        text = self.lineEdit.text()
        msgBox.setText(u'Text: {t}'.format(t=text))
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("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()

10. Použití validátorů pro textové pole

Masky specifikované pro textová pole sice umožňují do určité míry zajistit, že uživatel do pole zadá jen správné znaky, ovšem to v mnoha případech nemusí být dostačující kontrola. Například vstupní pole pro zadání rodného čísla by mělo tolerovat pouze takové vstupy, které jsou dělitelné jedenácti (s několika zákonem stanovenými výjimkami). Takovéto složitější podmínky již není možné zajistit pouze pomocí masky a je nutné využít složitější techniku. Jedná se o takzvané validátory, které mohou být k textovému poli přiřazeny metodou setValidator:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setValidator(........)

Validátor je objekt s několika metodami, především s metodami validate a fixup. Metoda validate je průběžně volána při editaci textového pole a může na základě aktuálně zadaného vstupu vracet hodnotu Invalid (vstup je zcela jistě špatný), Intermediate (vstup ještě není dokončen, ale není zcela špatný – například se teprve zapisují první číslice rodného čísla) a Acceptable (vstup je korektní). Naproti tomu metoda fixup může na konci editace provést v textu změny, typicky odmazání bílých znaků ze začátku a konce, vymazání mezer mezi číslicemi atd.

Kromě programátorem deklarovaných validátorů existuje i několik připravených validátorů. S nimi se setkáme v navazujících dvou kapitolách.

11. Čtvrtý demonstrační příklad: validátor typu QIntValidator

Podívejme se nyní na použití validátoru typu QIntValidator. Jak již víme, je možné tento validátor použít ve chvíli, kdy potřebujeme omezit údaje zadávané do textového pole na celá čísla v předem známém rozsahu. Řešení ve chvíli, kdy například vyžadujeme zadání celého čísla od 1 do 15000, je snadné:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setPlaceholderText(u'cena')
lineEdit.setMaxLength(11)
lineEdit.setValidator(QtGui.QIntValidator(1, 15000, self))
return lineEdit

Obrázek 10: Pokud číslo začíná na 9, bude povoleno zadat maximálně čtyři číslice.

Obrázek 11: Pokud číslo začíná na 1, bude povoleno zadat i pět číslic, ale jen do maximální hodnoty 15000.

Zdrojový kód tohoto příkladu vypadá následovně:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        showTextButton = self.prepareShowTextButton()
        self.lineEdit = self.prepareLineEdit()
 
        # vytvoření prvního správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # vytvoření druhého správce geometrie
        subLayout = QtGui.QHBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.lineEdit)
        topLayout.addLayout(subLayout)
 
        # tlačítka vložíme do druhého správce geometrie
        subLayout.addWidget(showTextButton)
        subLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareLineEdit(self):
        # jednořádkové vstupní textové pole
        lineEdit = QtGui.QLineEdit(self)
        lineEdit.setPlaceholderText(u'cena')
        lineEdit.setMaxLength(11)
        lineEdit.setValidator(QtGui.QIntValidator(1, 15000, self))
        return lineEdit
 
    def showTextDialog(self):
        msgBox = QtGui.QMessageBox()
        text = self.lineEdit.text()
        msgBox.setText(u'Text: {t}'.format(t=text))
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("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()

12. Pátý demonstrační příklad: validátor typu QRegExpValidator

Podobně jako validátor QIntValidator můžeme použít i další validátor, který je přímo součástí frameworku PySide. Tento validátor se jmenuje QRegExpValidator a již podle jeho názvu můžeme poznat, že slouží k validaci textu zadaného uživatelem na základě regulárního výrazu. Použití tohoto validátoru je snadné; ukažme si tedy jeho využití pro validaci, zda zadaný text odpovídá výrazu regulárnímu [a-z]{6}[0–9]{2} (šest znaků malé abecedy následované dvěma číslicemi – takto omezeny jsou loginy do mnoha systémů, i když dnes tato omezení většinou postrádají původní význam). Regulární výraz je reprezentován instancí objektu typu QRegExp:

# jednořádkové vstupní textové pole
lineEdit = QtGui.QLineEdit(self)
lineEdit.setPlaceholderText(u'login name')
lineEdit.setMaxLength(8)
regexp = QtCore.QRegExp("[a-z]{6}[0-9]{2}")
lineEdit.setValidator(QtGui.QRegExpValidator(regexp, self))

Obrázek 12: Použití validátoru typu QRegExpValidator.

Opět následuje výpis zdrojového kódu tohoto příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        showTextButton = self.prepareShowTextButton()
        self.lineEdit = self.prepareLineEdit()
 
        # vytvoření prvního správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # vytvoření druhého správce geometrie
        subLayout = QtGui.QHBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.lineEdit)
        topLayout.addLayout(subLayout)
 
        # tlačítka vložíme do druhého správce geometrie
        subLayout.addWidget(showTextButton)
        subLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareLineEdit(self):
        # jednořádkové vstupní textové pole
        lineEdit = QtGui.QLineEdit(self)
        lineEdit.setPlaceholderText(u'login name')
        lineEdit.setMaxLength(8)
        regexp = QtCore.QRegExp("[a-z]{6}[0-9]{2}")
        lineEdit.setValidator(QtGui.QRegExpValidator(regexp, self))
        return lineEdit
 
    def showTextDialog(self):
        msgBox = QtGui.QMessageBox()
        text = self.lineEdit.text()
        msgBox.setText(u'Text: {t}'.format(t=text))
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("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()

13. Ovládací prvek pro zápis i zobrazení víceřádkových dokumentů s formátováním

Další widget, s nímž se dnes seznámíme, slouží pro zobrazení a vkládání víceřádkového textu. Ve skutečnosti dokonce existují dva takové widgety; jeden z nich se jmenuje QPlainTextEdit a druhý QTextEdit. První z těchto ovládacích prvků dobře poslouží v případě, že potřebujeme pracovat s plain textem (zdrojové kódy atd.), druhý widget již umožňuje použití rich textu, tedy formátování znaků, slov i celých odstavců. První widget se vytvoří snadno:

# víceřádkové vstupní textové pole
textEdit = QtGui.QPlainTextEdit(self)

Podobného chování dosáhneme i u druhého typu widgetu:

# víceřádkové vstupní textové pole
textEdit = QtGui.QTextEdit(self)
textEdit.setAcceptRichText(False)

Obrázek 13: Víceřádkový dokument (část zdrojového kódu) zobrazený bez použití rich text formátu.

Pokud potřebujeme získat text zadaný uživatelem, postačuje u obou widgetu zavolat metodu toPlainText, která text vrátí a to včetně znaků pro konec řádku (\n):

text = self.textEdit.toPlainText()

14. Šestý demonstrační příklad: widget QTextEdit ve funkci víceřádkového textového pole

V dnešním předposledním demonstračním příkladu je ukázáno použití widgetu typu QTextEdit pro zobrazení víceřádkového textu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        showTextButton = self.prepareShowTextButton()
        self.textEdit = self.prepareTextEdit()
 
        # vytvoření prvního správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # vytvoření druhého správce geometrie
        subLayout = QtGui.QHBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.textEdit)
        topLayout.addLayout(subLayout)
 
        # tlačítka vložíme do druhého správce geometrie
        subLayout.addWidget(showTextButton)
        subLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareTextEdit(self):
        # víceřádkové vstupní textové pole
        textEdit = QtGui.QTextEdit(self)
        textEdit.setAcceptRichText(False)
        return textEdit
 
    def showTextDialog(self):
        msgBox = QtGui.QMessageBox()
        text = self.textEdit.toPlainText()
        msgBox.setText(u'Text:\n----------------\n{t}\n----------------'.format(t=text))
        msgBox.setIcon(QtGui.QMessageBox.Information)
        msgBox.exec_()
 
 
# nový widget bude odvozen od obecného hlavního okna
class MainWindow(QtGui.QMainWindow):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindow, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        # velikost není potřeba specifikovat
        # self.resize(320, 240)
        self.setWindowTitle("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. Základní zpracování HTML

Podívejme se nyní na způsob, jakým je možné ovládací prvek QTextEdit použít ve funkci jednoduchého zobrazovače HTML stránek (může se například jednat o dokumentaci k aplikaci atd.). Nejprve prvek jednoduše vytvoříme:

textEdit = QtGui.QTextEdit(self)

Dále nastavíme dvě důležité vlastnosti – prvek bude podporovat rich text formát a navíc nebude editovatelný (tj. bude read only). Vlastnost read only je ovšem platná pro vstup od uživatele (ten nebude povolen), zatímco programové změny obsahu textového pole povoleny jsou:

textEdit.setAcceptRichText(True)
textEdit.setReadOnly(True)

V posledním kroku se pokusíme do widgetu načíst obsah HTML stránky:

import io
 
with io.open("test.html", encoding="utf-8") as fin:
    textEdit.setHtml(fin.read())

Poznámka: funkci io.open zde používám z toho důvodu, aby bylo možné specifikovat kódování HTML stránky, a to i v Pythonu 2.x.

Obrázek 14: Na tomto screenshotu si povšimněte, že jsou správně zpracovány i styly.

16. Sedmý demonstrační příklad: widget QTextEdit ve funkci jednoduchého prohlížeče HTML stránek

V sedmém a současně i dnešním posledním příkladu si ukážeme, jakým způsobem je možné vytvořit velmi jednoduchý prohlížeč HTML stránek. Tento prohlížeč dokáže pracovat s většinou základních značek HTML, zpracuje CSS (i když některé typy selektorů nejsou podporovány) a zobrazuje i tabulky a obrázky. Ovšem například na odkazy budete klikat marně – aby fungovaly tak, jak se očekává, bylo by nutné namísto widgetu QTextEdit použít od něj odvozený widget QTextBrowser, s jehož možnostmi se podrobněji seznámíme v navazujícím článku.

Obrázek 15: V dolní části tohoto screenshotu můžete vidět způsob zobrazení tabulek.

Opět se podívejme na výpis zdrojového kódu dnešního posledního demonstračního příkladu:

#!/usr/bin/env python
# vim: set fileencoding=utf-8
 
import sys
import io
 
# import "jádra" frameworku Qt i modulu pro GUI
from PySide import QtCore
from PySide import QtGui
 
 
# nový widget bude odvozen od obecného widgetu
class MainWindowContent(QtGui.QWidget):
 
    def __init__(self):
        # zavoláme konstruktor předka
        super(MainWindowContent, self).__init__()
 
        # konfigurace GUI + přidání widgetu do okna
        self.prepareGUI()
 
    def prepareGUI(self):
        quitButton = self.prepareQuitButton()
        self.textEdit = self.prepareTextEdit()
 
        # vytvoření správce geometrie
        topLayout = QtGui.QVBoxLayout()
 
        # umístění widgetů do okna
        topLayout.addWidget(self.textEdit)
        topLayout.addWidget(quitButton)
 
        # nastavení správce geometrie a vložení všech komponent do okna
        self.setLayout(topLayout)
 
    def prepareShowTextButton(self):
        # druhé tlačítko
        showTextButton = QtGui.QPushButton('Show text', self)
        showTextButton.resize(showTextButton.sizeHint())
 
        # navázání akce na signál
        showTextButton.clicked.connect(self.showTextDialog)
        return showTextButton
 
    def prepareQuitButton(self):
        # tlačítko
        quitButton = QtGui.QPushButton('Quit', self)
        quitButton.resize(quitButton.sizeHint())
 
        # navázání akce na signál
        quitButton.clicked.connect(QtCore.QCoreApplication.instance().quit)
        return quitButton
 
    def prepareTextEdit(self):
        # jednořádkové vstupní textové pole
        textEdit = QtGui.QTextEdit(self)
        textEdit.setAcceptRichText(True)
        textEdit.setReadOnly(True)
        with io.open("test.html", encoding="utf-8") as fin:
            textEdit.setHtml(fin.read())
        return textEdit
 
 
# 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):
        self.resize(640, 480)
        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()

Obrázek 16: Widget QTextEdit dokáže zobrazit i obrázky vložené do HTML pomocí značky <img>.

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

Zdrojové kódy všech sedmi 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:

18. Odkazy na Internetu

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