Graafisen käyttöliittymän ohjelmointi Syksy 2013
Luento 13
QML
Antti Nieminen
Sisältö
• Johdanto
• QML:n perusteita
• JavaScript QML:ssä
• C++ ja QML
QML
• QML (Qt Meta Language tai Qt Modeling Language) on deklaratiivinen kieli käyttöliittymien tekoon
• Käytetään erityisesti mobiilikäyttöliittymissä
• Qt Quick = ”QML:n standardikirjasto”
• Nämä kalvot käsittelevät QML:n ja Qt Quick:in versiota 2.0 sekä Qt:n versiota 5.0 ellei toisin mainita
QML:n etuja
• Yksinkertainen, deklaratiivinen syntaksi
• Renderöidään OpenGL:llä
– > nopea ja kaunis käyttöliittymä
• JavaScript-tuki
• Helposti liitettävissä C++-koodiin
– Voidaan toteuttaa esim. käyttöliittymä QML:llä ja sovelluslogiikka C++:lla
Esimerkki 1
import QtQuick 2.0 Rectangle { width: 360 height: 360 Text { anchors.centerIn: parent text: "Hello World“ } MouseArea { anchors.fill: parent onClicked: { Qt.quit(); } } }
QML-tiedoston suoritus
• QML-tiedoston voi suorittaa mm.
1. Qt:n mukana tulevalla qmlscene-sovelluksella
• qmlscene tiedostoni.qml
2. Luomalla Qt Creatorilla Qt Quick –projektin
3. Tavallisessa Qt C++ -projektissa
• Tästä lisää kalvojen loppupuolella
QML on deklaratiivinen
• QML on deklaratiivinen kieli
• Deklaratiivisellä kielellä kuvataan millainen lopputulos halutaan
– vs. imperatiivinen kieli: määritellään vaiheet jotka suorittamalla lopputulokseen päästään
• QML-dokumentti voi sisältää myös imperatiivisia osia
– Toteutetaan JavaScript-kielellä
Deklaratiivinen vs. imperatiivinen
Rectangle { id: laatikko color: ”blue” MouseArea { onClicked: { laatikko.color = ”red”; } } }
QML-dokumentti
• QML-dokumentti koostuu olioista, jotka muodostavat puumaisen rakenteen – Yhdessä dokumentissa tasan yksi korkeimman tason olio – Olion vanhempaan voi viitata parent-attribuutin kautta
Rectangle { color: ”red” Rectangle { color: parent.color } }
QML-olio
• QML-oliolle täytyy määritellä sen tyyppi • Lisäksi olio voi sisältää erilaisia attribuutteja sekä
lapsiolioita
<OLIOTYYPPI> { <ATTRIBUUTTI1>: <ARVO1> <ATTRIBUUTTI2>: <ARVO2> … <LAPSIOLIO1> <LAPSIOLIO2> … }
QML-oliotyypit
• Visuaaliset oliot (visual objects) – Rectangle, Image, Text, … – Kaikki periytyvät Item-tyypistä
• Syötteenlukuoliot (user input objects) – MouseArea, Keys, PinchArea, …
• Asemointioliot (positioning objects) – Positioner, Row, Column, …
• Ja paljon muita – http://qt-project.org/doc/qt-5.0/qtquick/qtquick-
qmltypereference.html
• Myös omia tyyppejään voi luoda – Joko QML:llä tai C++:lla
QML-tiedostot
• Samassa hakemistossa oleviin QML-dokumentteihin voidaan viitata suoraan tiedoston nimellä (ilman päätettä) – > näin voidaan luoda omia oliotyyppejä
• Laatikko.qml: Rectangle { width: 100; height: 100 } • Toinen.qml: Row { Laatikko { color: ”blue” } Laatikko { color: ”red”} }
import
• QML-dokumenttiin voi importoida QML-moduuleja, QML-hakemistoja ja JavaScript-tiedostoja
• Oletuksena käytettävissä on kaikki saman hakemiston QML-tiedostot
• import QtQuick 2.0 – Tarvitaan käytännössä aina – Vanhemmat versiot: 1.0, 1.1 – Uudemmat: 2.1, 2.2, …
• http://qt-project.org/doc/qt-5.0/qtqml/qtqml-syntax-imports.html
Attribuutit
• QML-oliot sisältävät erilaisia attribuutteja
– id
– Property-attribuutit (x,y,width,itse määritellyt, …)
– Erilaiset signal ja handler –attribuutit
• http://qt-project.org/doc/qt-5.0/qtqml/qtqml-syntax-objectattributes.html
id-attribuutti
• Oliolle voi asettaa id:n, jolla siihen voi viitata muista olioista
Rectangle { Rectangle { id: laatikko1 color: ”red” } Rectangle { id: laatikko2 color: laatikko2.color } }
Property-attribuutit
• QML-olioiden property-attribuutit ovat tyypitettyjä – Perustyypit: int, real, string, color, …
– QML-oliotyypit: Rectangle, Item, …
– var-tyyppiset propertyt voivat sisältää mitä vain
• Oman propertyn määrittely, esimerkki:
Rectangle {
property string tervehdys: "Moro!"
}
Propertyn arvo
• Property-attribuutit voivat sisältää joko
– staattisen arvon:
• width: 100; color: "red";
– tai dynaamiseen lausekkeen:
• width: parent.width / 2
• color: checkbox1.checked ? "red" : "blue"
• Dynaamisessa tapauksessa propertyn arvo päivittyy automaattisesti lauseekkeen arvon muuttuessa ->
Property binding
• Propertyn arvon ”sitomista” riippumaan jostain muusta/muista property(i)stä kutsutaan nimellä property binding
• Esim: Rectangle { width: box1.width + box2.width + 50 }
• Aina kun jokin lausekkeen oikealla puolella olevista propertyistä muuttuu, muuttuu automaattisesti myös propertyn arvo
Esimerkki 2
import QtQuick 2.0 Rectangle { width: 400; height: 300; Rectangle { width: parent.width / 2 height: parent.height / 2 color: parent.width > parent.height ? ”red” : ”blue” } }
Olion sijainti
• QML-olion visuaalisen sijainnin määrittämiseen on useita tapoja
• x- ja y-attribuutit – suhteessa parent-olioon
• anchors-attribuutti – Asetetaan suhteessa parent- tai sisar-olioon – anchors.top: sisarolio.bottom
• Layoutit – Row, Column, Grid, Flow, …
• http://qt-project.org/doc/qt-5.0/qtquick/qtquick-usecase-layouts.html
State
• QML-oliolle voi määritellä erilaisia tiloja (State) • Olion states-attribuutti sisältää listan State-olioita • State-oliossa määritellään erot olion perustilaan
– Perustila on nimeltään tyhjä merkkijono ””
State { name: “pohjassa”; when: mouseArea.pressed PropertyChanges { target: o1; color: “yellow”} }
Esimerkki 3
Import QtQuick 2.0 Rectangle { id: root width: 400; height: 300; color: "yellow" MouseArea: { id: mouseArea; anchors.fill: parent } states: [ State { name: "pohjassa" when: mouseArea.pressed PropertyChanges { target: root; color: "red"} } ] }
Transitiot ja animaatiot
• Transitioiden avulla voidaan määritellä miten siirrytään propertyn arvosta toiseen tai tilasta toiseen
• Siirtymä voidaan animoida jollakin Animation-oliolla – http://qt-project.org/doc/qt-5.0/qtquick/qtquick-usecase-
animations.html
transitions: [Transition{
from: ””; to: ”pohjassa”
ColorAnimation { duration: 1000 }
}]
Signaalit
• QML-oliotkin lähettelevät signaaleja
• Valmiilla QML:n oliotyypeillä on signaaleja, esim. MouseArea:n clicked
• Signaaleja voi määritellä myös itse
– signal munSignaali(string parametri)
• Signaali lähetetään yksinkertaisesti kutsumalla sitä JavaScriptillä
– munSignaali(”moi”);
Signaalinkäsittelijät
• Signaaleja voi QML:ssä vastaanottaa signaalinkäsittelijöillä (signal handlers)
– kuten Qt:n slotit
• Signaalia nimeltä foo kuunnellaan määrittelemällä olioon käsittelijä nimellä onFoo
• Signaalinkäsittelijä toteutetaan JavaScript-kielellä
Esimerkki 4
import QtQuick 2.0 Rectangle { width: 400; height: 300; signal jotainTapahtui(string jotain) onJotainTapahtui: { teksti.text = ”tapahtui ” + jotain; } MouseArea { anchors.fill: parent onClicked: { jotainTapahtui(”klikkaus”); // lähetetään signaali } } Text { id:teksti, text:”klikkaa”} }
Propertyjen arvojen muutos
• Kun propertyn bar arvo muuttuu, lähtee tästä automaattisesti signaali barChanged
• Muutoksia voi siis kuunnella määrittelemällä käsittelijän onBarChanged
Rectangle { property real arvo onArvoChanged: { // … } }
JavaScript QML:ssä
• JavaScript-kieltä voidaan käyttää monella tapaa QML-dokumenteissa – Property binding –lausekkeet – Signaalinkäsittelijät – Itse määritellyt JavaScript-funktiot – Importoidut JavaScript-kirjastot
• QML:n JavaScript ei ole aivan yhtä salliva kuin webbiselaimissa – Esim. ”globaalia oliota” (global object) ei voi muokata
• http://qt-project.org/doc/qt-5.0/qtqml/qtqml-javascript-expressions.html
JavaScript QML:ssä
• JavaScriptissa voi QML-olioihin viitata niiden id:llä
Text { id: teksti, text: ”moi” } Keys.onPressed: { teksti.text += ”!”; } • Olio nimeltä Qt sisältää joitain QML-erikoisuuksia
– Esim. Qt.quit(); – http://qt-project.org/doc/qt-5.0/qtqml/qml-
qt.html#qmlglobalqtobject
JavaScript ja property binding
• Property binding –lauseke on käytännössä tavallinen JavaScript-lauseke, joka suoritetaan automaattisesti aina tarvittaessa – width: Math.max(box1.width, box2.width)
• Property binding voidaan tehdä myös JavaScript-koodissa – width = Qt.binding(function(){return box1.width;})
• Huom! Pelkkä sijoitus ei sido vaan ainoastaan asettaa arvon kertaalleen – width = box1.width
QtQuick:n moduuleita
• Controls
– ”Tavallisia” käyttöliittymäkomponentteja QML:ssä!
– Qt 5.1, QtQuick 2.1
• Window
– Tukea top-level-ikkunan toteutukseen
• Particles
– Partikkeliefektejä QML:ssä
• Jne.
Controls Gallery
• Demo
– qtquickcontrols/examples/quick/controls/gallery
QML:n toteutuksesta
• QML:n sisäinen toteutus kehittyy/muuttuu jatkuvasti
• Käyttöliittymän renderöinti – OpenGL
– Pyrkii hyödyntämään mahdollisimman paljon näytönohjaimen ominaisuuksia
• JavaScript-moottori – QML:ssä oma JavaScript-moottori
– Pohjana V8 Javascript Engine
– Räätälöity QML:n käyttötapauksiin
– http://blog.qt.digia.com/blog/2013/04/15/evolution-of-the-qml-engine-part-1/
QML ja C++
• QML-dokumentteja voi käsitellä Qt C++ -sovelluksella
• Qt C++:lla voi – luoda ja muutella QML-olioita – vastaanottaa QML-olioiden signaaleja – kutsua QML-olioiden JavaScript-metodeita – tarjota C++-olioiden metodeita QML:n käytettäväksi – määritellä omia QML-oliotyyppejä – jne.
• http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-topic.html
QML:n käyttöönotto Qt C++ -projektissa
• Projektitiedostossa:
QT += qml quick
• C++:ssa esimerkiksi:
QQuickView view;
view.setSource(QUrl::fromLocalFile("file.qml"));
view.show();
QML-oliot C++:ssa
• Kutakin QML-oliotyyppiä vastaa jokin QObject:ista periytyvä luokka
• Visuaaliset oliot periytyvät luokasta QQuickItem
• C++-puolelta voi QML-olioita hakea niiden objectName-attribuutin perusteella
– Ei siis id:n
QML-oliot C++:ssa
• QML: Rectangle { Rectangle { objectName: ”olio1” } } • C++: QQuickView* view = new QQuickView(filename); QQuickItem* olio1 = view->rootObject()-> findChild<QQuickItem*>("olio1"); olio1->setProperty("color", "red");
QML-olioiden signaalit
• QML-olioiden signaaleja voidaan vastaanottaa C++:ssa kuin muitakin signaaleja
QQuickView* view = new QQuickView("view.qml"); QObject::connect(view->rootObject(), SIGNAL(munSignaali()), view, SLOT(close())); view.qml: Rectangle { signal munSignaali … }
JavaScript-funktion kutsuminen
• QML: Rectangle { function foo(s) { return s+”!”; } } • C++: QVariant paluuarvo; QVariant parametri = ”moi”; QMetaObject::invokeMethod(qmlObj, ”foo”, Q_RETURN_ARG(Qvariant, paluuarvo), Q_ARG(QVariant, parametri));
C++-olio QML:ssä
• C++-olioita on mahdollista määritellä QML:ssä käytettäväksi – Lisätään se QML-olion kontekstiin (QQmlContext) jollain
nimellä – Periydyttävä joko QObject- tai QVariant-luokasta
QVariant t = new QVariant(”Moro”); view->rootContext()->setContextProperty(“tervehdys”, t); QML: Text { text: tervehdys }
C++-metodin kutsuminen QML:ssä
• Jotta luokan metodia voi kutsua QML:stä on sen esittelyssä oltava Q_INVOKABLE-makro
class ExampleClass : public QObject { Q_OBJECT public:
Q_INVOKABLE QString exampleMethod(); … • Lisättynä QML-kontekstiin nimellä ”example”: Text { text: example.exampleMethod() }
C++-olioiden propertyt
• C++-olioillekin voi määritellä propertyjä – Q_PROPERTY-makro
Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) public: Qcolor color() const; void setColor(const Qcolor &color); public signals: void colorChanged();
QML Qt-käyttöliittymässä
• QML-dokumentti on mahdollista "upottaa" tavalliseen Qt C++ -käyttöliittymän sisään
• Tätä varten QQuickWindow (tai QQuickView) on käärittävä QWidget:iin – Onnistuu funktiolla QWidget::createWindowContainer (Qt
5.1)
QQuickView* view = new QQuickView(filename); QWidget *container = QWidget::createWindowContainer(view); myLayout->addWidget(container);
Oliotyyppien määrittely C++:lla
• C++:lla voi määritellä myös oliotyyppejä QML:n käyttöön – QQmlEngine::qmlRegisterType
qmlRegisterType<PieChart>(”Charts”, 1, 0, ”PieChart”); QML: import Charts 1.0 PieChart { … }
QML-oliotyyppi C++:lla
• Esimerkki: PieChart
– Periytetty QQuickPaintItem-luokasta
– qtdeclarative/examples/qml/tutorials/extending
• http://qt-project.org/doc/qt-5.0/qtqml/qtqml-cppintegration-definetypes.html
Yhteenveto: QML-olio
• QML-oliolla on kolme rajapintaa
– QML
– JavaScript
– C++ (QObject)
QML-olio
C++ JavaScript
QML