Be Qt: Vývoj mobilních aplikací v Qt (2) – QML a Qt Quick

By Řezza - Last updated: Tuesday, March 27, 2012 - Save & Share - Leave a Comment

V minulém dílu seriálu o vývoji aplikací v QML jsme si ukázali, jak nainstalovat vývojové prostředí, vytvořit projekt a přeložit jednoduchou ukázkovou aplikaci napsanou právě v jazyce QML, a to s využitím Qt Components. Hello World prostě k životu programátora tak nějak patří. V pokračování se dostaneme více do teoretické roviny – představíme si jazyk QML, Qt Quick, možnosti jeho využití a prvky pro tvorbu uživatelského rozhraní. Ať neskončíme jako akademici, vše bude doprovázeno názornými příklady. Povíme si také, proč vyvíjet aplikace v QML a jaký je vztah QML, potažmo celého Qt Quick ke klasickému desktopovému Qt a jeho primárnímu jazyku C++. V příštím pokračování se pak dostaneme k tvorbě větší aplikace pro MeeGo Harmattan a Symbian a projdeme si podrobněji komponenty používané na těchto platformách – Qt Components.

Proč použít jazyk QML a Qt Quick?

Začněme tedy od konce. Proč se zaobírat jazykem QML a celým Qt Quick? Když samotné Qt jako toolkit pro vývoj grafických aplikací existuje již notnou řádku let, C++ je oblíbený jazyk, který zná spousta vývojářů a vzniklo tak moře aplikací. To je ovšem důvod číslo jedna – celý svět Qt je hodně zaměřený na programátory – a ti, jak je známo, nejsou vždy nejlepší, co se týče interakce s uživatelem. Jedním z cílů Qt Quick je zlepšit spolupráci designerů a programátorů, pokud možno oddělením logiky (která může být v právě v jazyce C++) od vzhledu aplikace. Ani v QML nedosáhneme tohoto snu o oddělení logiky od vzhledu zadarmo, ale při správném použití se dá dojít k cíli mnohem snadněji než v čistém Qt s C++.

Dalším důvodem je i požadavek na interaktivitu aplikace a její grafický projev, doprovázený spoustou animací a nejrůznějších udělátek – hlavní to požadavek dnešní doby našich uživatelů. Ano, i samotné Qt obsahovalo velmi dobrou podporu například pro animace – a tady narážíme na hlavní vztah Qt a QML. Na první pohled se totiž může zdát, že QML nemá s původním Qt nic společného. Jedná se o vlastní jazyk, nepoužívají se běžné komponenty pro návrh uživatelského rozhraní a i celá logika aplikace se dá bez větších problémů napsat v JavaScriptu, jak si později ukážeme. Qt je ve světě QML a Qt Quick totiž použito pouze jako nástroj, který se důmyslně schovává vespod této technologie. V QML pak víceméně zadarmo získáme právě podporu animací, skriptování, renderování obsahu (v Qt Quick 1 pomocí QGraphicsView), síťovou transparentnost atd. Standardní Qt a QML se tedy více navzájem doplňují, než si konkurují.

Na některých mobilních platformách (jako je MeeGo Harmattan) jsou pak standardní QWidget komponenty úplně ignorovány, případně jejich použití přináší mnohé problémy, příkladem je neexistence kinetického skrolování atd.

Jazyk QML

QML je ve své podstatě jednoduchý (ačkoliv celá definice zní hodně tajuplně) deklarativní vysokoúrovňový skriptovací jazyk určený jak k popisu vzhledu samotné aplikace, tak i jejího chování. Uživatelské rozhraní aplikace je pak popsáno ve stromové struktuře objektů a jejich vlastností. Jazyk QML získává na síle především možností využít v dnešní době oblíbeného JavaScriptu. Z toho taky svou syntaxí vychází. Dokonce přináší i část HTML5 API.

Základní prvky jazyka a tzv. property bindings

Základní struktura jazyka QML je velmi jednoduchá – skládá se z objektů a jejich vlastností. Nejlépe si jeho možnosti ukážeme na jednoduchém příkladu, který vykreslí modrý obdélník o rozměrech 400 pixelů na 200 pixelů a do něj umístí text Hello World. Tento text bude vertikálně zarovnaný na střed a zprava zarovnaný na pravý okraj obdélníku, ve vzdálenosti 50 pixelů. Výška textu se bude dynamicky měnit podle rodičovského objektu, a to na jednu osminu jeho výšky. Příklad je pak spustitelný jak v editoru QtCreator (na základní QML bez Qt Components stačí i běžný desktopový projekt, není potřeba zakládat speciální Harmattan/Symbian projekt), tak i z aplikace qmlviewer. Tu najdete ve výchozí instalaci Qt ve vaší distribuci.

1   import QtQuick 1.0
2
3   Rectangle {
4       width: 400
5       height: 200
6       color: "blue"
7
8       Text {
9           id: helloText
10          anchors { verticalCenter: parent.verticalCenter; right: parent.right; rightMargin: 50 }
11          text: "Hello World"; color: "white"; opacity: 0.0
12          font.pixelSize: parent.height / 8
13       }
14
15      Component.onCompleted: { helloText.opacity = 1.0 }
16  }

Na prvním řádku si naimportujeme základní elementy Qt Quick, v našem případě verzované (a to ve verzi 1.0). Příkaz import je možné využít jak pro import vlastních elementů/komponent, tak i k natažení separátních zdrojových kódů v JavaScriptu. Následně v našem příkladu využijeme základního vizuálního elementu Rectangle – obdélníku. Říká se, že v QML je možné zobrazit úplně vše, pokud je to právě obdélník (ukážeme si časem, že to není tak úplná pravda). Všimněte si, že za názvem elementu se nachází složená závorka, které pak s uzavírací složenou závorkou obaluje všechny objekty potomků (children) – zde to je právě jeden objekt Text. Vztah rodič-potomek je v QML velmi hojně využíván a tvoří tak výše zmíněnou stromovou strukturu.

Oba objekty pak obsahují několik vlastností. Např. šířku (width) a výšku (height) v případě elementu Rectangle. Dvojtečka před hodnotou pak symbolizuje tzv. binding – deklarativní způsob vyjádření obsahu vlastnosti. Hodnotou může být jak některý ze základních typů QML (např. int, real, string), tak jiný QML element. Od chvíle vytvoření bindingu dojde ke svázání hodnoty s hodnotou přiřazeného elementu. To je nejlépe vidět na řádku č. 12, kde výška textu v pixelech je svázaná s výškou rodičovského prvku (a k tomu ještě rozšířena o JavaScriptový výraz). Ve chvíli, kdy se změní výška rodiče, dojde k automatické propagaci nové hodnoty i na výšku našeho textu a k vyhodnocení výrazu. Dále je potřeba rozlišovat, kdy se jedná o binding a kdy o prosté přiřazení v JavaScriptu (řádek č. 15). To navíc odstraní původní binding a nemá jeho vlastnosti!

Jednou ze speciálních vlastností je vlastnost id (na řádku č. 9) a slouží k identifikaci a přístupu k danému objektu. V rámci QML komponenty musí být id unikátní. Po prvotním nastavení je navíc vlastnost id neměnná. Na jednom řádku je možné uvést více vlastností, které jsou oddělené pomocí středníku (řádek č. 11). Na předchozím řádku 10 (odmyslíme si zatím, jak funguje pozicování v QML) najdeme tzv. skupinovou notaci zápisu skupinových vlastností (group properties). Jedná se většinou o logické sdružení vybraných vlastností. Ekvivalentní zápis řádku 10 bez použití group properties by vypadal takto:

10          anchors.verticalCenter: parent.verticalCenter
10a         anchors,right: parent.right
10b         anchors.rightMargin: 50

Rychlý průlet QML pak zakončíme zpracováním signálů na řádku 15 kódu. Jazyk umožňuje v reakci na emitovaný signál vykonat blok JavaScriptového kódu – v našem případě přiřadí neprůhlednosti (opacity) hodnotu 1.0 typu real. Více kódu si ukážeme později v textu na názorných příkladech.

Grafické uživatelské rozhraní

Základním stavebním kamenem v QML je element Item. Jedná se o nevizuální element, který však obsahuje všechny základní vlastnosti vizuálních elementů, jako je šířka, výška, kotvy (anchors) atd. a je jejich přímým předkem v hierarchii objektů. Možné využití je například pro seskupování prvků uživatelského rozhraní. Takže se i Item používá velmi často a jedná se o celkem užitečný element.

Přehled základních elementů pro tvorbu UI

Jeden z dalších základních elementů, Rectangle, jsme si už představili v příkladu výše, kde k Item přidával jen vizuální formu. Pojdme se tedy podívat, jaké základní elementy QML/Qt Quick dále nabízí.

Text, TextEdit a TextInput

Pro výstup textu je v QML určen element Text. Ten jednak dědí základní vlastnosti elementu Item a také dovoluje většinu běžných operací s textem. Od změny stylu (sdružená vlastnost font – velikost textu, tučné písmo atd.) až po rich text, ve formátu HTML (vlastnost textFormat). Zajímavou vlastností je i elide, která nahradí dlouhý text třemi tečkami a tak zabrání přetečení textu a uživatele informuje o jeho neúplném zobrazení. Samozřejmostí je možnost nastavení zalamování textu.

Text { text: "First"; font.pixelSize: 48; }
Text { text: "Second"; color: "red"; font.pixelSize: 24; }
Text { text: "Third"; color: "white"; font.pixelSize: 64; font.bold: true; font.strikeout: true; }

Elementy TextInput a TextEdit pak slouží ke vstupu textu. TextInput je editovatelný řádek textu, TextEdit rozšiřuje řádek editovatelného textu na víceřádkový editor. Oba elementy nabízí stejné možnosti formátování jako základní text a přidávají možnost validace vstupu, případně vstup omezený maskou, označení textu a základní metody pro práci s textem.

Image

Element Image, jak už název napovídá, se používá k zobrazení obrázků. Zdroj se definuje ve vlastnosti source jako URL a může se jednat jak o lokální soubor (absolutně i relativně adresovatelný), tak i soubor ze síťového zdroje (protokol HTTP), případně Qt Resource (handler qrc:). Důležitou vlastností je fillMode, to je způsob, jakým se vyplní plocha elementu. Výchozím nastavením je roztáhnutí obrázku na jeho plochu. Dále pak roztáhnutí s ořezem a vyplnění dlaždicemi.

Image {
    width: parent.width 
    height: 100
    source: "http://openclipart.org/image/200px/svg_to_png/28818/purzen_Stone_slabs_with_cracks.png"
}

Image {
    width: parent.width
    height: 100 
    source: "http://openclipart.org/image/200px/svg_to_png/28818/purzen_Stone_slabs_with_cracks.png" 
    fillMode: Image.Tile
}

MouseArea

TextInput a TextEdit samozřejmě nejsou jediné vstupní elementy v QML. QML podporuje vstup z klávesnice (ten přeskočíme, dnešní mobilní systémy většinou klávesnice ignorují), polohovacího zařízení (myš, dotykové plochy) a umí zpracovat i základní vícedotyková gesta (GestureArea).

Použití MouseArea je velmi jednoduché – například vyplněním rodičovského prvku a definováním reakce na vybrané signály – např. kliknutí (onClicked), stisk a podržení (onPressAndHold) atd.

Rectangle {
    id: rect  ...
    Text { text: "Click me"; ... }

    MouseArea {
        anchors.fill: parent

        onClicked: console.log("Clicked at [" + mouseX + ", " + mouseY + "]")     }
}

Ve výše uvedeném přehledu samozřejmě nejsou uvedeny všechny elementy Qt Quick 1. Zbylé elementy jsou k dispozici v dokumentaci, která obsahuje spoustu příkladů využití. Seznámili jsme se však se základy jejich použití, které jsou ve zbylých elementech velmi podobné.

Umisťování prvků

QML nabízí tři základní možnosti pozicování prvků. Je možné pozicovat absolutně s využitím vlastností x a y, ovšem tenhle přístup by měl být v QML tabu a využíván co nejméně. Protože QML přináší mnohem chytřejší a flexibilnější možnosti. Důvodem je využití v mobilních zařízeních, které mají rozličné velikosti displejů, různá rozlišení atd. Proto QML přináší takzvaný anchoring, neboli ukotvení. Nejedná se o odkaz (link), jako je to v HTML, ale o možnost ukotvit různé prvky k okolním prvkům (ve stejné úrovni stromu objektů). Pro názornost si vypůjčíme nákres z dokumentace.

Rectangle { id: rect1; width: 100; height: 100; color: "red" }
Rectangle { id: rect2; anchors.left: rect1.right; width: 100; height: 100; color: "blue" }

Dalši možností jsou předpřipravené kontejnery Row, Column, Flow a Grid. Jejich názvy jsou samovysvětlující. Více v následujícím příkladu.

Rectangle {
    id: rect
    anchors.fill: parent
    Column {
        Row {
            Rectangle { width: rect.width / 2; height: rect.height / 2; color: "red"; }
            Rectangle { width: rect.width / 2; height: rect.height / 2; color: "blue"; }
        }
        Row {
            Rectangle { width: rect.width / 2; height: rect.height / 2; color: "yellow"; }
            Rectangle { width: rect.width / 2; height: rect.height / 2; color: "green"; }
        }
    }
}

Model/View architektura

Valná většina dnešních mobilních aplikací (tedy oblast, na kterou především míří vývoj v QML/Qt Quick) je postavena na principu zobrazování seznamů informací. Jedná se např. o RSS feed, seznam kuchařských receptů, kurzovní lístek nebo statusy uživatelů sociálních sítí, jako je Facebook a Twitter. A ty chceme zobrazit pokud možno v co nejvíce uživatelsky přívětivé formě. Při tvorbě uživatelských rozhraní v QML se k tomu v hojné míře využívá klasická architektura model/view. Jednoduše česky řečeno: seznam informací zde slouží jako zdroj dat (model) pro nezávislý pohled (či více pohledů – view) na data. O vykreslení informací jednotlivých prvků se pak stará tzv. delegát.

Model a Repeater

Nejjednodušším modelem v QML je prostý celočíselný model – viz následující příklad. Ten využívá výše uvedeného pozicování do mříže (gridu) ve spojení s neméně zajímavým elementem jazyka QML – Repeaterem, tedy elementem, který umí automaticky opakovat vybrané komponenty (potomky elementu Item). V našem příkladu to budou číslice od jedné do devíti v mřížce 3×3.

    Grid {
        id: grid
        anchors.fill: parent 
        columns: 3
        rows: 3

        Repeater {
            model: 9 
            delegate: Rectangle {
                width: parent.width / grid.columns 
                height: parent.height / grid.rows 
                Text {
                    anchors.centerIn: parent
                    text: modelData + 1                 }
            }
        }
    }

Obsahem vlastnosti model pak může být i seznam řetězců a objektů. Proměnná index pak obsahuje pořadí komponenty v repeateru a modelData pak její obsah. Pokud je jako model použit buď vlastní model exportovaný z jazyka C++ nebo např. element QML ListModel, má Repeater přístup ke všem jeho vlastnostem. ListModel si hned představíme.

ListModel a ListView

ListModel je jednoduchý kontejner, obsahující jednotlivé prvky seznamu – ListElementy. Ty mají definováno datové role namísto vlastností. Syntaxe jejich zápisu je však stejná. ListModel může být jak zapsán přímo v QML, tak vytvořen dynamicky za běhu aplikace. To se hodí například na zpracování dat, která jsou stahována ze sítě.

ListView je element, který doplňuje výše uvedený ListMode a slouží k zobrazení obsahu modelu. Na rozdíl od Repeateru se jedná o hotovou komponentu, která celý proces zobrazení dat zjednodušuje. Přidává kinetické skrolování, umisťování prvků, sekce, výběr jednotlivých prvků atd.

V následujícím příkladu vytvoříme model, který bude obsahovat jako jednotlivé prvky druh ovoce, jejich počet a obrázek (tedy tři role – name, fruits a image). Na rozdíl od příkladu s Repeaterem jsme komponentu použitou v delegátovi nadefinovali mimo tělo ListView.

    ListModel {
        id: fruitModel

        ListElement {
            name: "Apples" 
            fruits: 3 
            image: "images/matou_apple.png"
        }    

        ListElement {
            name: "Pears" 
            fruits: 5 
            image: "images/matou_pear.png"         }
    }

    ListView {
        anchors.fill: parent

        model: fruitModel
        delegate: fruitDelegate
    }

    Component {
        id: fruitDelegate

        Row {
            width: parent.width
            height: 100

            Text {
	        width: parent.width / 3
                text: name
            }

            Repeater {
                model: fruits

                delegate: Row {
		    Image {
		        source: image
		    }
		}
            }
        }
    }

Závěr

V této části seriálu jsme vám představili základy práce v QML/Qt Quick, stále nám ovšem chybí jedna důležitá věc pro tvorbu uživatelských rozhraní, a to jeho komponenty, jako jsou tlačítka, menu a jiné prvky, které jsme si ukázali již v předchozí části. Samotné QML žádné hotové komponenty neobsahuje a je na vývojáři, aby si vytvořil vlastní. Svět Qt Quick ovšem není tak zlý, jak se zdá, a pro vybrané platformy existují komponenty již předpřipravené. Usnadňují jak vývoj, tak především zaručují jistou jednotnost aplikací na dané platformě. Pro MeeGo Harmattan a Symbian existují Qt Components a v rámci vývoje první skutečné aplikace vám je podrobněji představíme v následujícím dílu.

Be Qt: Soutěž

Pokud jste se rozhodli soutěžit se sdružením Openmobility a Nokií, tak máte za sebou první skutečné seznámení s QML/Qt Quick a nastává ideální doba k odeslání registrace vašich aplikací, na které již netrpělivě čekáme!

Seriál vychází ve spolupráci se serverem AbcLinuxu.cz. Zároveň slouží jako podpora souteže Be Qt: vývoj mobilních aplikacích v Qt pro platformy MeeGo Harmattan a Symbian sponzorované společností Nokia. Hlavní cenou pro nejlepší aplikaci bude linuxový smartphone Nokia N9. V případně neočekávaného zájmu budou speciální cenou dvě vývojářské Nokia N950!

Sdílejte:

Share this:

Posted in MeeGo, Openmobility, Vývoj • Tags: , , , , Top Of Page

Write a comment


Yandex Mail.ru Google LiveJournal myOpenId Flickr claimId Blogger Wordpress OpenID Yahoo Technorati Vidoop Verisign AOL