Obsah
1. Specializované jazyky pro popis grafického uživatelského rozhraní
2. Jazyk QML (Qt Modeling Language)
3. První demonstrační příklad – jednoduchý obdélník
4. Načtení a použití popisu GUI v aplikaci využívající PySide
5. Úplný zdrojový kód prvního demonstračního příkladu
6. Nepatrně složitější příklad – obdélníkové okno s textem
7. Určení vzájemné (relativní) polohy jednotlivých prvků grafického uživatelského rozhraní
8. Třetí demonstrační příklad – pozice tří čtverců v okně
9. Naprogramování reakcí na akce prováděné uživatelem
10. Reakce na stisk tlačítka myši
12. Vylepšení předchozího příkladu – fokus nastavený na hlavní okno
13. Specifikace většího množství kroků při vzniku události
14. Šestý demonstrační příklad – dvě reakce na stisk tlačítka myši
16. Nastavení pořadí objektů v Z-ové ose
18. Obsah dalšího pokračování seriálu
19. Repositář s demonstračními příklady
1. Specializované jazyky pro popis grafického uživatelského rozhraní
V dnešním článku si řekneme základní informace o jazyku QML určeného pro popis designu i chování grafického uživatelského rozhraní. Prozatím se zaměříme na základní vlastnosti QML, ale v dalších článcích si již ukážeme napojení GUI části na skripty naprogramované v Pythonu s využitím PySide.
V minulosti vzniklo poměrně velké množství doménově specifických jazyků určených pro popis grafického uživatelského rozhraní. Ostatně se stačí podívat na tabulku zobrazenou pod tímto odstavcem, ve které jsou některé tyto jazyky zmíněny (zdaleka se ovšem nejedná o vyčerpávající seznam!):
Zkratka | Význam |
---|---|
FXML | (pravděpodobně Form XML) |
HMVCUL | Hierarchical Model View Controller User Interface Language |
MARIA | Model-based lAnguage foR Interactive Applications |
MXML | součást Adobe Flex |
LZX | Laszlo XML |
QML | Qt Modeling Language |
SVG | Scalable Vector Graphics |
UIML | User Interface Markup Language |
UsiXML | User Interface Extensible Markup Language |
WasabiXML | deklarace GUI pro Wasabi |
XAL | eXtensible Application Language |
XAML | Extensible Application Markup Language |
XFD | XML Form Definition |
XUL | XML User Interface Language |
Tyto jazyky můžeme rozdělit zhruba do tří skupin:
- Jazyky, v nichž je možné popsat pouze design grafického uživatelského rozhraní, tj. jednotlivých oken, dialogů a ovládacích prvků v nich. Návaznost na systém pro správu událostí se řeší jinými prostředky a přitom se typicky používají ID přiřazené jednotlivým prvkům GUI. Toto zásadní omezení má výhodu v tom, že design GUI zůstává přísně deklarativní.
- Jazyky, ve kterých je možné specifikovat callback funkce/metody volané při vzniku různých událostí (žádost o vykreslení, klik tlačítkem myši, stisk klávesy, drag and drop atd.)
- Jazyky kombinující jak popis designu grafického uživatelského rozhraní, tak i zpracování událostí. Například je možné přímo do popisu GUI vkládat programový kód napsaný v JavaScriptu atd.
2. Jazyk QML (Qt Modeling Language)
Jazyk QML, jehož naprosté základy si vysvětlíme v navazujících kapitolách, patří do třetí skupiny. Obsahuje tedy jak deklarativní, tak i imperativní části, přičemž reakce na události, řízení animací atd. je možné naprogramovat buď v JavaScriptu nebo s využitím callback funkcí/metod naprogramovaných například v C++ nebo v Pythonu. V tomto článku nás bude zajímat především spojení PySide+QML, tj. poslední možnost zahrnující použití Pythonu.
Poměrně důležité je, že jazyk QML není, na rozdíl od mnoha jiných jazyků určených pro popis GUI, založen na XML, což s sebou přináší některé přednosti, ale i zápory. Díky použití složených závorek pro definici a oddělení jednotlivých elementů je zápis čitelnější a kratší, než při použití nějaké aplikace XML (ostatně i zápis JavaScriptu uvnitř QML je přirozenější, než například kombinace HTML+JavaScript). Na druhou stranu však není možné (alespoň ne jednoduše) použít běžné nástroje pro zpracování XML, tj. xpath atd.
Zajímavé jsou i možnosti popisu vzájemné pozice prvků grafického uživatelského rozhraní. Programátor popř. návrhář GUI má k dispozici několik možností popisu rozmístění prvků:
- Použití absolutních souřadnic.
- Umístění prvků do jednoho sloupce (samotný sloupec je možné vložit do dalšího prvku)
- Umístění prvků do jednoho řádku
- Umístění prvků do pravidelné mřížky (grid)
- Použití takzvaných kotevních přímek (přesnější český termín pravděpodobně není rozšířen)
3. První demonstrační příklad – jednoduchý obdélník
Dnešní první demonstrační příklad je pojat minimalisticky. V jazyku QML deklarujeme obdélník představující plochu hlavního okna aplikace. U tohoto obdélníku specifikujeme pouze jeho rozměry (šířku, výšku); žádné další údaje pro takto jednoduchý příklad nejsou zapotřebí. Obsah souboru pojmenovaného 165_load_qml1.qml vypadá následovně:
import QtQuick 1.0 Rectangle { width: 320 height: 240 }
První řádek s příkazem import má formát:
import <jmenný prostor> <verze>
Ve skutečnosti se však dá import použít i v dalších situacích, například pro načtení programového kódu napsaného v JavaScriptu nebo pro načtení obsahu s definicemi typů apod.
Na dalších řádcích můžeme vidět deklaraci objektu, zde konkrétně objektu typu Rectangle i s naplněním jeho dvou atributů. Každý atribut je uveden na samostatném řádku:
Rectangle { width: 320 height: 240 }
Atributy můžeme uvést i na stejném řádku, ovšem tehdy je nutné je oddělit středníky:
Rectangle { width: 320; height: 240 }
Specifikace GUI je prozatím čistě deklarativní – vytváříme v něm objekty (Rectangle, Text) a nastavujeme jejich atributy. Objekty mohou obsahovat i další objekty, takže výsledkem bude stromová struktura.
4. Načtení a použití popisu GUI v aplikaci využívající PySide
Deklaraci grafického uživatelského rozhraní velmi jednoduché aplikace již máme připravenou, takže se podívejme, jak ji načteme do skriptu napsaného v Pythonu. K tomuto účelu se používá třída QDeclarativeView z modulu QtDeclarative (v Qt 5 ovšem došlo k přejmenování třídy QQuickView!). Po importu modulu QtDeclarative:
# modul pro práci s QML from PySide import QtDeclarative
budeme moci využít následující běžné třídy i třídy abstraktní:
ListProperty |
QDeclarativeComponent |
QDeclarativeContext |
QDeclarativeEngine |
QDeclarativeError |
QDeclarativeExpression |
QDeclarativeExtensionInterface |
QDeclarativeExtensionPlugin |
QDeclarativeImageProvider |
QDeclarativeItem |
QDeclarativeListReference |
QDeclarativeNetworkAccessManagerFactory |
QDeclarativeParserStatus |
QDeclarativeProperty |
QDeclarativePropertyMap |
QDeclarativePropertyValueSource |
QDeclarativeScriptString |
QDeclarativeView |
Od třídy QDeclarativeView totiž můžeme odvodit uživatelskou třídu a použít metodu setSource() pro načtení QML. Dále pomocí metody setResizeMode() zajistíme změnu velikosti okna aplikace takovým způsobem, aby odpovídalo ploše deklarované v QML:
# nový widget bude odvozen od QDeclarativeView class MainWindow(QtDeclarative.QDeclarativeView): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle("QML Example") # načtení souboru QML self.setSource(QtCore.QUrl.fromLocalFile(QML_FILE)) # necháme QML změnit velikost okna self.setResizeMode(QtDeclarative.QDeclarativeView.SizeRootObjectToView)
Takto deklarovanou třídu představující hlavní okno aplikace použijeme naprosto stejným způsobem jako jakékoli jiné hlavní okno:
def main(): # vytvoření Qt aplikace app = QtGui.QApplication(sys.argv) # vytvoření hlavního okna window = MainWindow() # zobrazení hlavního okna window.show() # spuštění aplikace sys.exit(app.exec_())
Obrázek 1: První demonstrační příklad po svém spuštění.
5. Úplný zdrojový kód prvního demonstračního příkladu
Úplný zdrojový kód dnešního první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 # modul pro práci s QML from PySide import QtDeclarative QML_FILE = "165_load_qml_1.qml" # nový widget bude odvozen od QDeclarativeView class MainWindow(QtDeclarative.QDeclarativeView): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) self.setWindowTitle("QML Example") # načtení souboru QML self.setSource(QtCore.QUrl.fromLocalFile(QML_FILE)) # necháme QML změnit velikost okna self.setResizeMode(QtDeclarative.QDeclarativeView.SizeRootObjectToView) def main(): # vytvoření Qt aplikace app = QtGui.QApplication(sys.argv) # vytvoření hlavního okna window = MainWindow() # zobrazení hlavního okna window.show() # spuštění aplikace sys.exit(app.exec_()) if __name__ == '__main__': main()
Bez použití QML by příklad mohl vypadat například následovně:
# tento import je zapotřebí kvůli nutnosti zpracování parametrů # předávaných přes příkazový řádek import sys # prozatím budeme využívat jen modul QtGui 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): self.resize(320, 240) self.setWindowTitle("Window and label") # návěští label = QtGui.QLabel("Hello world!", self) # posun v rámci nadřazeného widgetu label.move(100, 100) def run(self, app): # zobrazení okna na obrazovce self.show() # vstup do smyčky událostí (event loop) sys.exit(app.exec_()) def main(): app = QtGui.QApplication(sys.argv) MainWindow().run(app) if __name__ == '__main__': main()
6. Nepatrně složitější příklad – obdélníkové okno s textem
Na předchozím příkladu postavíme i všechny další demonstrační příklady. První úprava (nebo vylepšení) spočívá v tom, že budeme specifikovat barvu pozadí plochy okna. K tomu slouží atribut color, kterému je možné předat řetězec se jménem barvy, kód barvy ve formátu #rrggbb (hexa triplet) nebo ve formátu #rrggbbAA (hexa triplet s průhledností). Jména všech podporovaných barev naleznete na stránce https://www.w3.org/TR/SVG/types.html#ColorKeywords:
import QtQuick 1.0 Rectangle { width: 320 height: 240 color: "lightgray" }
Dále na plochu okna přidáme další prvek grafického uživatelského rozhraní. Bude se jednat o text představovaný objektem typu Text. Mezi nastavované atributy bude patřit vlastní řetězec a taktéž režim uchycení objektu na plochu:
import QtQuick 1.0 Rectangle { width: 320 height: 240 color: "lightgray" Text { text: "Hello World" anchors.centerIn: parent } }
Obrázek 2: Druhý demonstrační příklad po svém spuštění.
Režimy uchycení jsou specifické pro QML a vzhledem k jejich důležitosti pro tvorbu grafického uživatelského rozhraní si je popíšeme v navazující kapitole.
7. Určení vzájemné (relativní) polohy jednotlivých prvků grafického uživatelského rozhraní
V předchozím demonstračním příkladu jsme si mj. ukázali, jak je možné specifikovat umístění nějakého prvku GUI (zde se konkrétně jednalo o text) v rámci plochy okna aplikace nebo libovolného formuláře. Možnosti QML jsou ovšem v tomto ohledu mnohem širší, neboť je možné nastavit jak absolutní pozice prvků, tak i pozice relativní, a to vůči libovolnému jinému prvku. Například můžeme zapsat, že dva prvky GUI (například tlačítka) mají být zobrazeny vedle sebe, tj. pravý okraj levého tlačítka bude shodný s levým okrajem tlačítka pravého a současně budou shodné i jejich y-ové souřadnice. Způsob zápisu relativních pozic prvků GUI je v QML poměrně intuitivní. Vše je založeno na šesti pomyslných přímkách, které jsou automaticky vytvořeny pro každý prvek GUI:
Obrázek 3: Pomyslné přímky, ke kterým je možné vztahovat pozice jednotlivých komponent.
Zdroj: http://doc.qt.io/archives/qt-4.8/images/edges_qml.png
Jak se tyto přímky využijí při určování vzájemné pozice prvků? Podívejme se na příklad, v němž je všem prvkům GUI přiřazen jednoznačný identifikátor, takže se na ně můžeme odkázat. Dále stanovíme, které kotevní přímky mají mít prvky společné. Je již věcí správce geometrie, aby našel korektní řešení zadaného problému :-):
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 100 height: 100 color: "red" anchors.verticalCenter: main.verticalCenter } Rectangle { id: r2 width: 100 height: 100 color: "blue" anchors.left: r1.right } }
Příklad je samozřejmě možné různými způsoby upravit a dosáhnout tak odlišného rozmístění prvků na ploše. Kromě explicitního použití ID prvků můžeme použít i označení parent pro předka (ne ve smyslu hierarchie tříd, ale umístění objektů do stromu GUI widgetů):
import QtQuick 1.0 Rectangle { width: 320 height: 240 color: "lightgray" Rectangle { width: 160 height: 160 color: "red" anchors.left: parent.left anchors.bottom: parent.bottom } Rectangle { width: 160 height: 160 color: "green" anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top } Rectangle { width: 160 height: 160 color: "blue" anchors.right: parent.right anchors.bottom: parent.bottom } }
8. Třetí demonstrační příklad – pozice tří čtverců v okně
Ve třetím demonstračním příkladu budou na plochu okna vloženy tři různobarevné čtverce. První čtverec bude v okně vertikálně (svisle) vycentrován (anchors.verticalCenter: main.verticalCenter), další na něj bude navazovat (budou se dotýkat hranami), ovšem y-ová pozice bude nulová. A konečně třetí čtverec bude svou spodní hranou zarovnán se spodním okrajem okna:
Obrázek 4: Třetí demonstrační příklad po svém spuštění.
Následuje ukázka QML skriptu, který toto GUI popisuje:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 100 height: 100 color: "red" anchors.verticalCenter: main.verticalCenter } Rectangle { id: r2 width: 100 height: 100 color: "blue" anchors.left: r1.right } Rectangle { id: r3 width: 100 height: 100 color: "yellow" anchors.left: r2.right anchors.top: r2.bottom } }
9. Naprogramování reakcí na akce prováděné uživatelem
Všechny příklady, které jsme si až doposud ukázali, popisují pouze statický design grafického uživatelského rozhraní. Nyní se podívejme na to, jakým způsobem je možné naprogramovat alespoň minimální reakce na akce, které uživatel s GUI prvky provádí. Základ je velmi jednoduchý – nadeklarujeme kód (handler) vybrané události, která nad nějakým prvkem GUI vznikne. Může se jednat například o kliknutí tlačítkem myši. Použijeme přitom nový prvek nazvaný příhodně MouseArea. Ten je zcela neviditelný a je možné ho zvětšit takovým způsobem, že svou plochou pokryje libovolný viditelný prvek GUI. MouseArea je specifický tím, že může přijímat a zpracovávat události, které souvisí s použitím myši, tj. přesunutí kurzoru myši nad plochy prvku, opuštění plochy prvku, kliknutí tlačítkem, stisk či puštění tlačítka i akce typu drag and drop. Práce s myší je v určitém ohledu nejjednodušší, protože (na rozdíl od práce s klávesnicí) není nutné řešit nastavení fokusu atd.
Obrázek 5: Výchozí barvy čtverců.
Obrázek 6: Barvy čtverců po kliknutí tlačítkem myši.
10. Reakce na stisk tlačítka myši
Ukažme si tedy jednoduchý příklad, v němž bude možné kliknutím měnit barvy jednotlivých čtverců zobrazených v hlavním okně aplikace. Povšimněte si především způsobu zápisu reakce na událost, a to přímo v jazyku QML, bez nutnosti volat kód v Pythonu (ovšem ne vše je samozřejmě možné naprogramovat takto jednoduchým způsobem):
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 100 height: 100 color: "gray" anchors.verticalCenter: main.verticalCenter MouseArea { anchors.fill: parent onClicked: r1.color = "red" } } Rectangle { id: r2 width: 100 height: 100 color: "gray" anchors.left: r1.right MouseArea { anchors.fill: parent onClicked: parent.color = "blue" } } Rectangle { id: r3 width: 100 height: 100 color: "gray" anchors.left: r2.right anchors.top: r2.bottom MouseArea { anchors.fill: parent onClicked: parent.color = "yellow" } } }
Vidíme, že přímo v handleru události je možné měnit (prakticky) libovolný atribut libovolného prvku GUI.
11. Reakce na stisk klávesy
Dalším způsobem ovládání aplikací s grafickým uživatelským rozhraním je samozřejmě použití klávesnice. Zde ovšem narazíme na jeden problém – události, které vznikají při stisku jednotlivých kláves, přijímá pouze ten element GUI, který má nastavený fokus. Ostatní elementy nebudou tuto událost získávat a tedy na ni ani nedokáží zareagovat. Ostatně si sami můžeme vyzkoušet, co se stane ve chvíli, kdy spustíme následující demonstrační příklad, v němž (teoreticky) všechny čtverce budou reagovat na stisk kláves 1, 2 nebo 3:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 100 height: 100 color: "gray" anchors.verticalCenter: main.verticalCenter Item { anchors.fill: parent focus: true Keys.onDigit1Pressed: parent.color = "red" } MouseArea { anchors.fill: parent onClicked: parent.color = "#ffff00" } } Rectangle { id: r2 width: 100 height: 100 color: "gray" anchors.left: r1.right Item { anchors.fill: parent Keys.onDigit2Pressed: parent.color = "blue" } MouseArea { anchors.fill: parent onClicked: parent.color = "#00ffff" } } Rectangle { id: r3 width: 100 height: 100 color: "gray" anchors.left: r2.right anchors.top: r2.bottom Item { anchors.fill: parent Keys.onDigit3Pressed: parent.color = "yellow" } MouseArea { anchors.fill: parent onClicked: parent.color = "#ff00ff" } } }
12. Vylepšení předchozího příkladu – fokus nastavený na hlavní okno
Jakým způsobem je tedy možné problém s fokusem vyřešit? Ve skutečnosti existuje hned několik způsobů, z nichž nejjednodušší spočívá v tom, že události vytvořené po stisku klávesy budou zpracovávány (nebo chcete li akceptovány) prvkem typu Rectangle, který představuje celou plochu okna aplikace. V handlerech událostí použijeme jednoznačná ID čtverců, kterým budeme nastavovat jejich barvy. Samozřejmě nesmíme zapomenout na to, aby byl fokus skutečně přesunut na plochu okna aplikace (focus: true), jinak nebudou události zpracovány (pokud totiž systém nezjistí, že se událost zpracovala, jednoduše ji zahodí):
Keys.onDigit1Pressed: r1.color = "red" Keys.onDigit2Pressed: r2.color = "cyan" Keys.onDigit3Pressed: r3.color = "yellow"
Úplný kód tohoto příkladu vypadá následovně:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Item { anchors.fill: parent focus: true Keys.onDigit1Pressed: r1.color = "red" Keys.onDigit2Pressed: r2.color = "cyan" Keys.onDigit3Pressed: r3.color = "yellow" } Rectangle { id: r1 width: 100 height: 100 color: "gray" anchors.verticalCenter: main.verticalCenter } Rectangle { id: r2 width: 100 height: 100 color: "gray" anchors.left: r1.right } Rectangle { id: r3 width: 100 height: 100 color: "gray" anchors.left: r2.right anchors.top: r2.bottom } }
Oba dva přístupy je samozřejmě možné zkombinovat a reagovat tak jak na stisk kláves, tak i na klik tlačítkem myši:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" anchors.fill: parent focus: true Keys.onDigit1Pressed: r1.color = "red" Keys.onDigit2Pressed: r2.color = "cyan" Keys.onDigit3Pressed: r3.color = "yellow" Rectangle { id: r1 width: 100 height: 100 color: "gray" anchors.verticalCenter: main.verticalCenter MouseArea { anchors.fill: parent onClicked: parent.color = "magenta" } } Rectangle { id: r2 width: 100 height: 100 color: "gray" anchors.left: r1.right MouseArea { anchors.fill: parent onClicked: parent.color = "blue" } } Rectangle { id: r3 width: 100 height: 100 color: "gray" anchors.left: r2.right anchors.top: r2.bottom MouseArea { anchors.fill: parent onClicked: parent.color = "green" } } }
13. Specifikace většího množství kroků při vzniku události
V případě, že je zapotřebí v handleru události provést větší množství kroků, musíme použít příkazové závorky. Syntaxe zápisu je jednoduchá. V případě, že by se kroky zapisovaly na stejný řádek, musíme opět použít středníky, jinak nejsou nutné:
onClicked: { parent.color = "magenta" txt.text = "r1 clicked" }
Obrázek 7: Screenshot dalšího příkladu, v němž se používá složitější handler událostí.
14. Šestý demonstrační příklad – dvě reakce na stisk tlačítka myši
Šestý příklad vychází z příkladů předchozích, ovšem je do něj přidáno zobrazení zpráv o akcích prováděných uživatelem. Z tohoto důvodu je to do plochy okna přidán textový widget s unikátním identifikátorem a v handlerech událostí měníme atribut text tohoto widgetu:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" anchors.fill: parent focus: true Keys.onDigit1Pressed: r1.color = "red" Keys.onDigit2Pressed: r2.color = "cyan" Keys.onDigit3Pressed: r3.color = "yellow" Text { id: txt text: "Click" font.pixelSize: 16 anchors.horizontalCenter: parent.horizontalCenter anchors.bottom: parent.bottom } Rectangle { id: r1 width: 100 height: 100 color: "gray" anchors.verticalCenter: main.verticalCenter MouseArea { anchors.fill: parent onClicked: { parent.color = "magenta" txt.text = "r1 clicked" } } } Rectangle { id: r2 width: 100 height: 100 color: "gray" anchors.left: r1.right MouseArea { anchors.fill: parent onClicked: { parent.color = "blue" txt.text = "r2 clicked" } } } Rectangle { id: r3 width: 100 height: 100 color: "gray" anchors.left: r2.right anchors.top: r2.bottom MouseArea { anchors.fill: parent onClicked: { parent.color = "green" txt.text = "r3 clicked" } } } }
15. Specifikace průhlednosti
Na závěr dnešního článku si ještě ukážeme, jakým způsobem je možné nastavit průhlednost jednotlivých prvků GUI a také pořadí prvků v Z-ové ose ve chvíli, kdy se nějaké prvky překrývají. Nastavení průhlednosti je snadné, protože stačí nastavit atribut opacity. Hodnotou tohoto atributu by mělo být reálné číslo v rozsahu od 0.0 do 1.0. Samozřejmě se opět podívejme na demonstrační příklad, v němž je jednotlivým čtvercům vloženým do plochy okna aplikace přiřazena různá průhlednost:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 160 height: 160 color: "red" opacity: 0.5 anchors.left: parent.left anchors.bottom: parent.bottom } Rectangle { id: r2 width: 160 height: 160 color: "yellow" opacity: 0.5 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top } Rectangle { id: r3 width: 160 height: 160 color: "blue" opacity: 0.5 anchors.right: parent.right anchors.bottom: parent.bottom } }
16. Nastavení pořadí objektů v Z-ové ose
Ve chvíli, kdy se nějaké prvky překrývají, je většinou nutné explicitně nastavit jejich pořadí. To lze udělat velmi snadno nastavením z-ové souřadnice jednotlivých prvků, a to prakticky stejným způsobem, jakým se tato vlastnost nastavuje ve většině vektorových editorů popř. v HTML či v CSS. Vše bude patrné z následujícího příkladu:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 160 height: 160 color: "red" opacity: 0.5 anchors.left: parent.left anchors.bottom: parent.bottom } Rectangle { id: r2 width: 160 height: 160 color: "yellow" opacity: 0.5 z: 1 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top } Rectangle { id: r3 width: 160 height: 160 color: "blue" opacity: 0.5 anchors.right: parent.right anchors.bottom: parent.bottom } }
Obrázek 8: Nastavení průhlednosti a překryvu prvků grafického uživatelského rozhraní.
Jednoduchou úpravou předchozího zdrojového kódu můžeme dosáhnout toho, že prvky budou překryty v opačném pořadí:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 160 height: 160 color: "red" opacity: 0.5 z: 3 anchors.left: parent.left anchors.bottom: parent.bottom } Rectangle { id: r2 width: 160 height: 160 color: "yellow" opacity: 0.5 z: 2 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top } Rectangle { id: r3 width: 160 height: 160 color: "blue" opacity: 0.5 z: 1 anchors.right: parent.right anchors.bottom: parent.bottom } }
17. Rotace prvků GUI
Na úplný závěr si ukážeme rotaci prvků:
Obrázek 9: Rotace vybraných prvků grafického uživatelského rozhraní.
Rotace se provádí snadno nastavením atributu rotation na hodnotu odlišnou od nuly:
import QtQuick 1.0 Rectangle { id: main width: 320 height: 240 color: "lightgray" Rectangle { id: r1 width: 160 height: 160 color: "red" opacity: 0.5 rotation: 45 anchors.left: parent.left anchors.bottom: parent.bottom } Rectangle { id: r2 width: 160 height: 160 color: "yellow" opacity: 0.5 z: 1 anchors.horizontalCenter: parent.horizontalCenter anchors.top: parent.top } Rectangle { id: r3 width: 160 height: 160 color: "blue" opacity: 0.5 rotation: 45 anchors.right: parent.right anchors.bottom: parent.bottom } }
18. Obsah dalšího pokračování seriálu
V navazující části tohoto seriálu se seznámíme s dalšími možnostmi, které programátorům nabízí jazyk QML. Především si ukážeme odlišné způsoby rozmístění prvků grafického uživatelského rozhraní v okně či formuláři s využitím objektů typu Grid, Row a Column, což je alternativa k dnes zmíněným kotevním přímkám. Také si ukážeme reálné možnosti propojení QML se skripty naprogramovanými v Pythonu s využitím frameworku PySide.
19. Repositář s demonstračními příklady
Zdrojové kódy všech dnes popsaných demonstračních příkladů byly, podobně jako tomu bylo i v předchozích článcích, uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/presentations. Pokud nechcete klonovat celý repositář, můžete namísto toho použít odkazy na jednotlivé příklady, které naleznete v následující tabulce:
Následuje tabulka s odkazy na soubory QML s popisem grafického uživatelského rozhraní, které taktéž budete potřebovat:
20. Odkazy na Internetu
- QML Tutorial
https://pyside.github.io/docs/pyside/tutorials/qmltutorial/index.html - QML Advanced Tutorial
https://pyside.github.io/docs/pyside/tutorials/qmladvancedtutorial/index.html - User interface markup language
https://en.wikipedia.org/wiki/User_interface_markup_language - UsiXML
https://en.wikipedia.org/wiki/UsiXML - Anchor-based Layout in QML
https://het.as.utexas.edu/HET/Software/html/qml-anchor-layout.html#anchor-layout - PySide.QtDeclarative
https://pyside.github.io/docs/pyside/PySide/QtDeclarative/index.html - PySide and Qt Quick/QML Playground
https://wiki.qt.io/PySide-and-QML-Playground - Hand Coded GUI Versus Qt Designer GUI
https://stackoverflow.com/questions/387092/hand-coded-gui-versus-qt-designer-gui - Qt Creator Manual
http://doc.qt.io/qtcreator/ - Qt Designer Manual
http://doc.qt.io/qt-5/qtdesigner-manual.html - Qt Creator (Wikipedia)
https://en.wikipedia.org/wiki/Qt_Creator - QIODevice
https://pyside.github.io/docs/pyside/PySide/QtCore/QIODevice.html#PySide.QtCore.QIODevice - QFile
https://pyside.github.io/docs/pyside/PySide/QtCore/QFile.html#PySide.QtCore.QFile - QUiLoader
https://pyside.github.io/docs/pyside/PySide/QtUiTools/QUiLoader.html#PySide.QtUiTools.PySide.QtUiTools.QUiLoader.load - QSvgWidget
https://pyside.github.io/docs/pyside/PySide/QtSvg/QSvgWidget.html - QByteArray
https://pyside.github.io/docs/pyside/PySide/QtCore/QByteArray.html - Python Bytes, Bytearray
https://www.w3resource.com/python/python-bytes.php - psep-0101.txt (mj. popis mapování typů Pythonu na třídy v PySide)
https://github.com/techtonik/pseps/blob/master/psep-0101.txt - QSvgRenderer
https://pyside.github.io/docs/pyside/PySide/QtSvg/QSvgRenderer.html - QSvgGenerator
https://pyside.github.io/docs/pyside/PySide/QtSvg/QSvgGenerator.html - QIcon
https://pyside.github.io/docs/pyside/PySide/QtGui/QIcon.html - PySide 1.2.1 documentation
https://pyside.github.io/docs/pyside/index.html - QStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QStyle.html - QCommonStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QCommonStyle.html - QPlastiqueStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QPlastiqueStyle.html - QMacStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QMacStyle.html - QCleanlooksStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QCleanlooksStyle.html - QGtkStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QGtkStyle.html - QCDEStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QCDEStyle.html - QMotifStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QMotifStyle.html - QWindowsStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QWindowsStyle.html - QStyleFactory
https://pyside.github.io/docs/pyside/PySide/QtGui/QStyleFactory.html - QStyleOptionHeader
https://pyside.github.io/docs/pyside/PySide/QtGui/QStyleOptionHeader.html - QAbstractSlider
https://pyside.github.io/docs/pyside/PySide/QtGui/AbstractSlider.html - QScrollBar
https://pyside.github.io/docs/pyside/PySide/QtGui/ScrollBar.html - QSlider
https://pyside.github.io/docs/pyside/PySide/QtGui/Slider.html - QDial
https://pyside.github.io/docs/pyside/PySide/QtGui/Dial.html - QImage
https://pyside.github.io/docs/pyside/PySide/QtGui/QImage.html - QPixmap
https://pyside.github.io/docs/pyside/PySide/QtGui/QPixmap.html - QBitmap
https://pyside.github.io/docs/pyside/PySide/QtGui/QBitmap.html - QPaintDevice
https://pyside.github.io/docs/pyside/PySide/QtGui/QPaintDevice.html - QPicture
https://pyside.github.io/docs/pyside/PySide/QtGui/QPicture.html - QPainter
https://pyside.github.io/docs/pyside/PySide/QtGui/QPainter.html - QPainterPath
https://pyside.github.io/docs/pyside/PySide/QtGui/QPainterPath.html - QGradient
https://pyside.github.io/docs/pyside/PySide/QtGui/QGradient.html - QLinearGradient
https://pyside.github.io/docs/pyside/PySide/QtGui/QLinearGradient.html - QRadialGradient
https://pyside.github.io/docs/pyside/PySide/QtGui/QRadialGradient.html - QTableWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QTableWidget.html - QTableWidgetItem
https://pyside.github.io/docs/pyside/PySide/QtGui/QTableWidgetItem.html - QTreeWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QTreeWidget.html - QTreeWidgetItem
https://pyside.github.io/docs/pyside/PySide/QtGui/QTreeWidgetItem.html - Afinní zobrazení
https://cs.wikipedia.org/wiki/Afinn%C3%AD_zobrazen%C3%AD - Differences Between PySide and PyQt
https://wiki.qt.io/Differences_Between_PySide_and_PyQt - PySide 1.2.1 tutorials
https://pyside.github.io/docs/pyside/tutorials/index.html - PySide tutorial
http://zetcode.com/gui/pysidetutorial/ - Drawing in PySide
http://zetcode.com/gui/pysidetutorial/drawing/ - Qt Core
https://pyside.github.io/docs/pyside/PySide/QtCore/Qt.html - QLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QLayout.html - QValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QValidator.html - QStackedLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QStackedLayout.html - QFormLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QFormLayout.html - QBoxLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QBoxLayout.html - QHBoxLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QHBoxLayout.html - QVBoxLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QVBoxLayout.html - QGridLayout
https://pyside.github.io/docs/pyside/PySide/QtGui/QGridLayout.html - QAction
https://pyside.github.io/docs/pyside/PySide/QtGui/QAction.html - QDialog
https://pyside.github.io/docs/pyside/PySide/QtGui/QDialog.html - QMessageBox
https://pyside.github.io/docs/pyside/PySide/QtGui/QMessageBox.html - QErrorMessage
https://pyside.github.io/docs/pyside/PySide/QtGui/QErrorMessage.html - QInputDialog
https://pyside.github.io/docs/pyside/PySide/QtGui/QInputDialog.html - QColorDialog
https://pyside.github.io/docs/pyside/PySide/QtGui/QColorDialog.html - QListWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QListWidget.html - Signals & Slots
http://doc.qt.io/qt-4.8/signalsandslots.html - Signals and Slots in PySide
http://wiki.qt.io/Signals_and_Slots_in_PySide - Intro to PySide/PyQt: Basic Widgets and Hello, World!
http://www.pythoncentral.io/intro-to-pysidepyqt-basic-widgets-and-hello-world/ - QLineEdit
https://pyside.github.io/docs/pyside/PySide/QtGui/QLineEdit.html - QTextEdit
https://pyside.github.io/docs/pyside/PySide/QtGui/QTextEdit.html - QValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QValidator.html - QIntValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QIntValidator.html - QRegExpValidator
https://pyside.github.io/docs/pyside/PySide/QtGui/QRegExpValidator.html - QWidget
https://pyside.github.io/docs/pyside/PySide/QtGui/QWidget.html - QMainWindow
https://pyside.github.io/docs/pyside/PySide/QtGui/QMainWindow.html - QLabel
https://pyside.github.io/docs/pyside/PySide/QtGui/QLabel.html - QAbstractButton
https://pyside.github.io/docs/pyside/PySide/QtGui/QAbstractButton.html - QCheckBox
https://pyside.github.io/docs/pyside/PySide/QtGui/QCheckBox.html - QRadioButton
https://pyside.github.io/docs/pyside/PySide/QtGui/QRadioButton.html - QButtonGroup
https://pyside.github.io/docs/pyside/PySide/QtGui/QButtonGroup.html - QFrame
https://pyside.github.io/docs/pyside/PySide/QtGui/QFrame.html#PySide.QtGui.PySide.QtGui.QFrame - QFrame.frameStyle
https://pyside.github.io/docs/pyside/PySide/QtGui/QFrame.html#PySide.QtGui.PySide.QtGui.QFrame.frameStyle - Leo editor
http://leoeditor.com/ - IPython Qt Console aneb vylepšený pseudoterminál
https://mojefedora.cz/integrovana-vyvojova-prostredi-ve-fedore-ipython-a-ipython-notebook/#k06 - Vývojová prostředí ve Fedoře (4. díl)
https://mojefedora.cz/vyvojova-prostredi-ve-fedore-4-dil/ - Seriál Letní škola programovacího jazyka Logo
http://www.root.cz/serialy/letni-skola-programovaciho-jazyka-logo/ - Educational programming language
http://en.wikipedia.org/wiki/Educational_programming_language - Logo Tree Project:
http://www.elica.net/download/papers/LogoTreeProject.pdf - Hra Breakout napísaná v Tkinteri
https://www.root.cz/clanky/hra-breakout-napisana-v-tkinteri/ - Hra Snake naprogramovaná v Pythone s pomocou Tkinter
https://www.root.cz/clanky/hra-snake-naprogramovana-v-pythone-s-pomocou-tkinter/ - 24.1. turtle — Turtle graphics
https://docs.python.org/3.5/library/turtle.html#module-turtle - TkDND
http://freecode.com/projects/tkdnd - Python Tkinter Fonts
https://www.tutorialspoint.com/python/tk_fonts.htm - The Tkinter Canvas Widget
http://effbot.org/tkinterbook/canvas.htm - Ovládací prvek (Wikipedia)
https://cs.wikipedia.org/wiki/Ovl%C3%A1dac%C3%AD_prvek_%28po%C4%8D%C3%ADta%C4%8D%29 - Rezervovaná klíčová slova v Pythonu
https://docs.python.org/3/reference/lexical_analysis.html#keywords - TkDocs: Styles and Themes
http://www.tkdocs.com/tutorial/styles.html - Drawing in Tkinter
http://zetcode.com/gui/tkinter/drawing/ - Changing ttk widget text color (StackOverflow)
https://stackoverflow.com/questions/16240477/changing-ttk-widget-text-color - The Hitchhiker's Guide to Pyhton: GUI Applications
http://docs.python-guide.org/en/latest/scenarios/gui/ - 7 Top Python GUI Frameworks for 2017
http://insights.dice.com/2014/11/26/5-top-python-guis-for-2015/ - GUI Programming in Python
https://wiki.python.org/moin/GuiProgramming - Cameron Laird's personal notes on Python GUIs
http://phaseit.net/claird/comp.lang.python/python_GUI.html - Python GUI development
http://pythoncentral.io/introduction-python-gui-development/ - Graphic User Interface FAQ
https://docs.python.org/2/faq/gui.html#graphic-user-interface-faq - TkInter
https://wiki.python.org/moin/TkInter - Tkinter 8.5 reference: a GUI for Python
http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html - TkInter (Wikipedia)
https://en.wikipedia.org/wiki/Tkinter - appJar
http://appjar.info/ - appJar (Wikipedia)
https://en.wikipedia.org/wiki/AppJar - appJar na Pythonhosted
http://pythonhosted.org/appJar/ - appJar widgets
http://appjar.info/pythonWidgets/ - Stránky projektu PyGTK
http://www.pygtk.org/ - PyGTK (Wikipedia)
https://cs.wikipedia.org/wiki/PyGTK - Stránky projektu PyGObject
https://wiki.gnome.org/Projects/PyGObject - Stránky projektu Kivy
https://kivy.org/#home - Stránky projektu PyQt
https://riverbankcomputing.com/software/pyqt/intro - PyQt (Wikipedia)
https://cs.wikipedia.org/wiki/PyGTK - Stránky projektu PySide
https://wiki.qt.io/PySide - PySide (Wikipedia)
https://en.wikipedia.org/wiki/PySide - Stránky projektu Kivy
https://kivy.org/#home - Kivy (framework, Wikipedia)
https://en.wikipedia.org/wiki/Kivy_(framework) - QML Applications
http://doc.qt.io/qt-5/qmlapplications.html - KDE
https://www.kde.org/ - Qt
https://www.qt.io/ - GNOME
https://en.wikipedia.org/wiki/GNOME - Category:Software that uses PyGTK
https://en.wikipedia.org/wiki/Category:Software_that_uses_PyGTK - Category:Software that uses PyGObject
https://en.wikipedia.org/wiki/Category:Software_that_uses_PyGObject - Category:Software that uses wxWidgets
https://en.wikipedia.org/wiki/Category:Software_that_uses_wxWidgets - GIO
https://developer.gnome.org/gio/stable/ - GStreamer
https://gstreamer.freedesktop.org/ - GStreamer (Wikipedia)
https://en.wikipedia.org/wiki/GStreamer - Wax Gui Toolkit
https://wiki.python.org/moin/Wax - Python Imaging Library (PIL)
http://infohost.nmt.edu/tcc/help/pubs/pil/ - Why Pyjamas Isn’t a Good Framework for Web Apps (blogpost z roku 2012)
http://blog.pyjeon.com/2012/07/29/why-pyjamas-isnt-a-good-framework-for-web-apps/ - PySide na PyPi
https://pypi.org/project/PySide/