Početak programiranja u QML-u

Dobrodošli u svijet QMLa, opisnog UI jezika. U ovom vodiču kreirat ćemo jednostavni editor teksta upotrebom QMLa. Nakon što završite s čitanjem ovog vodiča, trebali biste biti spremni za razvoj vlastitih aplikacija upotrebom QMLa i C++.

QML u izradi korisničkog sučelja

Aplikacija koju ćemo raditi je jednostavni tekstualni editor koji učitava, snima te izvodi jednostavne funkcije na tekstu. Ovaj vodič sastoji se od dva dijela. U prvom dijelu obrađuju se dizajn i izgled aplikacije te ponašanje iste upotrebom opsinog jezika u QMLu. U drugom dijelu, učitavanje i snimanje datoteke bit će implementirano koriteći Qt C++. Upotrebom Qt Meta-Object System [doc.qt.nokia.com] omogućujemo QML-ovim elementima pristup C++ metodama. Radeći u Qt C++ i QML-u, lako je odvojiti logiku korisničkog sučelja od ostatka aplikacije.

Texteditor

Da bi pokrenuli QML primjer proslijediti QML datoteku qmlviewer [doc.qt.nokia.com] programu. C++ dijelovi ovog vodiča predpostavljaju da čitatelj posjeduje osnovno znanje o kreiranju izvršnih datoteka iz Qt projekata.

Definicija Dugmadi i Menija

Osnovni elementi – dugme

Započet ćemo rad na tekst editoru kreiranjem dugmeta. Funkcionalno, dugme se sastoji od područja osjetljivog na akcije miša i naslov. Dugmad izvršava akcije nakon što korisnik klikne na njega.

U QML-u, osnovni vizualni element je Rectangle [doc.qt.nokia.com]. Rectangle [doc.qt.nokia.com] ima svojstva kojima se određuje njegov izgled i položaj.

  1. import Qt 4.7
  2. Rectangle{
  3.   id:simplebutton
  4.   color: "grey"
  5.   width: 150
  6.   height: 80
  7.   Text{
  8.     id: buttonLabel
  9.     text: "button label"
  10.    anchors.centerIn: parent;
  11.    anchors.verticalCenterOffset: -1
  12.   }
  13. }

Prvo, linija koda import Qt 4.7 omogućuje qmlviewer [doc.qt.nokia.com] alatom da uveze QML element koje ćemo kasnije koristiti. Ova linija je neophodna za svaku QML datoteku. Primjetite da koristimo i verziju Qt-a pri tome.

Ovaj jednostavi element ima unikatni naziv, simplebutton koji je vezan za svojstvo id. Svojstva elementa Rectangle [doc.qt.nokia.com] vežu se za vrijednosti, navođenjem svojstva iza kojeg bi uslijedila dvotočka a zatim vrijednost. U primjeru izvornog koda, siva boje postavljenja je za vrijednost boje(color) Rectangle [doc.qt.nokia.com] elementa. Na isti način postavljena su svojstva za visinu(height) i širinu(width) elementa.

Text [doc.qt.nokia.com] element je nepromjenjivo tekstualno polje. U primjeru ćemo ga nazvati buttonLabel. Da bi postavili sadržaj Text [doc.qt.nokia.com] polja, potrebno je postaviti svojstvo text. Naziv se nalazi unutar elementa Rectangle [doc.qt.nokia.com] i da bi centrirali potrebno je povezati lokaciju Text [doc.qt.nokia.com] elementa s njegovim parent elementom, koji je u ovom slucaju <i>simplebutton</i>.

Ovaj ćemo izvorni kod snimiti u datoteku SimpleButton.qml. Pokrenut ćemo qmlviewer [doc.qt.nokia.com] program s parametrom SimpleButton.qml i prikazat će nam se sivi pravokutnik s upisanim tekstom.

Da bismo implementirali interakciju s dugmetom, upotrijebiti ćemo QML-ov sistem za obradu događaja. Obrada događaja u QML-u je prilično slično sustavu signala i slotova u QT-u. Signali se emitiraju i pozivaju povezani slot.

  1. Rectangle{
  2.   id:simplebutton
  3.   ...
  4.  
  5.   MouseArea{
  6.     id: buttonMouseArea
  7.  
  8.     anchors.fill: parent //anchor all sides of the mouse area to the rectangle's anchors
  9.     //onClicked handles valid mouse button clicks
  10.     onClicked: console.log(buttonLabel.text + " clicked" )
  11.   }
  12. }

Dodajemo MouseArea [doc.qt.nokia.com] našem simplebutton elementu. MouseArea [doc.qt.nokia.com] element opisuje interaktivno područje unutar kojeg se detektiraju korinički pomaci miša. Za naše dugme, povezali smo cijeli MouseArea [doc.qt.nokia.com] za područje dugmeta. Dio koda anchors.fill omogućuje pritup svojstvu fill unutar grupe svojstva anchors. QML koristi predloške (layout) bazirane na principu sidra (<i>anchor</i>) koji omogućavaju povezivanje sidra jednog elementa s drugim elementima kreirajući pri tome robusna sučelja.

Za MouseArea [doc.qt.nokia.com] postoji mnogo signala koji se aktiviraju pomicanjem miša unutar MouseArea [doc.qt.nokia.com] granica. Jedan od njih je onClicked i on se poziva svaki put kad se pritisne tipka miša, po defaultu lijeva. Akciju ćemo zatim povezati s onClicked signalom. U našem primjeru console.log() ispisuje tekst svaki put kad bi se tipka miša pritisnula unutar granica MouseArea [doc.qt.nokia.com]. Metoda console.log() je izuzetno korisna za potrebe traženja i ispravljanja grešaka u kodu kao i ispis teksta.

Izvorni kod u SimpleButton.qml dovoljan je za prikaz dugmeta na ekranu te ispis teksta svaki put kad bi kliknuli na njega mišem.

  1. Rectangle {
  2.   id:Button
  3.   ...
  4.  
  5.   property color buttonColor: "lightblue"
  6.   property color onHoverColor: "gold"
  7.   property color borderColor: "white"
  8.  
  9.   signal buttonClick()
  10.   onButtonClick: {
  11.       console.log(buttonLabel.text + " clicked" )
  12.   }
  13.  
  14.   MouseArea {
  15.       onClicked: buttonClick()
  16.       hoverEnabled: true
  17.       onEntered: parent.border.color = onHoverColor
  18.       onExited:  parent.border.color = borderColor
  19.   }
  20.  
  21.   // determines the color of the button by using the conditional operator
  22.   color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor
  23. }

U datoteci Button.qml nalazi se potpuno funkcionalno dugme. Izvorni kod uz ovaj vodič je djelomično skraćen s obzirom da se ti dijelovi kod nalaze u prijašnjim primjerima ili nisu relevantne za ovu temu.

Proizvoljna svojstva deklariraju se upotrebom “property type name” sintakse . U primjeru izvornog koda, svojstvo buttonColor, tip color je deklarirano i vezano uz vrijednost “lightblue”. Svojstvo buttonColor kasnije ćemo upotrijebiti u kondicionaloj operaciji kojom ćemo utvrditi boji dugmeta. Bitno je za primjetiti da je svojstvu vrijednost moguće dodijeliti upotrebom ”=” operatora uz mogućnost dodijeljivanja vrijednosti upotrebom znaka ”:”. Proizvoljna svojstva omogućuju pristup internim elementima izvan Rectangle [doc.qt.nokia.com] objekta. Osnovni tipovi podatka [doc.qt.nokia.com] s kojima QML radi su int, string, real kao i variant

Povezivanjem onEntered i onExited signala s bojama, okvir dugmeta na ekranu promijenit će boju u žuto dok se pokazivač nađe unutar njegovih granica .

Signal buttonClick() deklariran je u <i>Button.qml</i> datoteci postavljanjem ključne riječi ispred naziva signala. Svim signalim automatski se kreiraju vezane metode koje nose isti naziv kao signal. Kao rezultat dobijemo metodu onButtonClick() vezanu za signal buttonClick. Na metodu onButtonClick() zatim se veže akcija koja će se izvršiti.

U našem primjeru, onClicked signal aktivirat će metodu onButtonClick koja će prikazati tekst. Metoda onButtonClick omogućuje vanjskim objektima pristup području dugmeta. Primjerice, elementi na sučelju mogu imati više od jedne deklaracije MouseArea [doc.qt.nokia.com] a buttonClick signal će odrediti koja će vezana metoda bolje odraditi akciju vezanu na signal.

Do sada smo svladali osnove implementacije elemenata u QMLu za obradu osnovnih pokreta mišem. Kreirali smo tekstualni element unutar objekta Rectangle [doc.qt.nokia.com], prilagodli njegova svojstva i implementirali ponašanje koje odgovarta pokretima mišem. Koncept kreiranja elemenata unutar elemenata raširen je kroz cijelu aplikaciju.

Ovo dugme je beskorisno ukoliko nije upotrebljen kao komponenta koja će izvršti neku akciju. U sljedećem dijelu vodiča kreirat ćemo meni koji će sadržavati neke od dugmadi.

Kreiranje izborničke (MENU) stranice

Do ovog tgrenutka pokrili smo kreiranje elemenata i pripadajućih akcija unutar jedne QML datoteke. U ovom dijelu vodića proći ćemo uvoz QML elemenata te ponovno korištenje postojećih elemenata u izgradnji drugih.

Izbornici prikazuju sadržaj liste s time da svaki od njih ima mogućnost izvršavanja akcije. U QMLu, izbornik se može kreirati na više načina. Prvo, kreirat ćemo izbornik koji sadrži dugmad koja će eventulano izvršavati različite akcije. Izvorni kod za izbornike nalazi se u datoteci FileMenu.qml.

  1. import Qt 4.7                  \\ import the main Qt QML module
  2. import "folderName"            \\ import the contents of the folder
  3. import "script.js" as Script   \\ import a Javascript file and name it as Script

Izvorni kod iznad pokazuje kako koristiti import ključnu riječ. Ona je neophodna ukoliko želimo koristiti JavaScript datoteke, ili QML datoteke a koje se ne nalaze unutaristog direktorija. S obzirom da se Button.qml nalazi u istom direktoriju kao i FileMenu.qml, za Button.qml nije potrebno koristiti import da bi ga upotrijebili. Button element možemo kreirati deklaracijom Button{}, slično kao što smo radili deklaraciju Rectangle{} elementa.

  1. Izvorni kod <code>FileMenu.qml</code>:
  2.  
  3.      Row{
  4.          anchors.centerIn: parent
  5.          spacing: parent.width/6
  6.  
  7.          Button{
  8.              id: loadButton
  9.              buttonColor: "lightgrey"
  10.              label: "Load"
  11.          }
  12.          Button{
  13.              buttonColor: "grey"
  14.              id: saveButton
  15.              label: "Save"
  16.          }
  17.          Button{
  18.              id: exitButton
  19.              label: "Exit"
  20.              buttonColor: "darkgrey"
  21.  
  22.              onButtonClick: Qt.quit()
  23.          }
  24.      }

U datoteci FileMenu.qml deklarirali smo tri Button elementa. Njih smo postavili unutar Row elementa, koji sve elemente koji se nalazu unutar njega postavlja u okomiti red. Deklaracija Button elementa nalazi se u Button.qml datoteci koja je ista ona datoteka koju smo koritili u prethodnom primjeru. Na svojstva elementa Button mogu se vezati nove vrijednosti i time prepisati osnovna svojstva elementa postavljena u Button.qml. Klikom na dugme exitButton aplikacije će se zatvoriti. Treba uzeti u obzir da će se uz metodu onButtonClick vezanu na exitButton dugme istovremno aktivirati i metoda onButtonClick koja se nalazi unutar Button.qml datoteke.

Izbornik

Row se deklarira unutar deklaracije Rectangle time kreirajući Rectangle koji sadrži u sebi red dugmadi. Ovaj dodatni Rectangle element indirektno utječe na organizaciju reda dugmadi unutar menija.

Deklaracija izbornika Edit je u ovoj fazi prilično slična. Izbornik sadrži dugmad s nazivima: Cut, Paste i Select All

Oboružani znanjem o uvozu i prilagođavanju od prije postojećih elemenata, sad možemo spojiti izborničke stranice u izborničku traku, koja će se sastojati od dugmadi za izbor menija i dobiti dobar primjer strukturiranja podataka upotrebom QML-a.

Implementacija izborničke trake

Naš tekst editor treba prikazivati izbornik upotrebom izborničke trake. Izbornička traka izmjenjivat će različite menije omogućujući koriniku izbor željene akcije. Izmjena izbornika podrazumjeva da su izbornicima treba malo više strukturiranja od običnog prikaza u redu. QML koristi modele i predloške za pregled strukturiranih podataka.

Upotreba podatkovnih modela i predložaka

QML dolazi s različitim podatkovim modelima [doc.qt.nokia.com] i predlošcima za prikaz istih. Naša izbornička traka prikazivati će izbornike u listi, sa zaglavljem u kojem će se nalaziti nazivi redova. Lista izbornika deklarira se unutar VisualItemModel [doc.qt.nokia.com] elementa. VisualItemModel [doc.qt.nokia.com] element sadrži elemente koji u sebi već sadrže Rectangle elemente kao i UI elemente koje smo uvezi. Druge tipove modele kao što je ListModel [doc.qt.nokia.com] moraju koristiti delegate da bi prikazali svoje podatke.

Deklariramo dva vizualna elementa unutar menuListModel, FileMenu i EditMenu. Prilagođujemo dva menija i prikazujemo ih upotrebom ListView. MenuBar.qml datoteka sadrži QML deklaracije a EditMenu.qml swadrži jednostavni Edit izbornik.

  1. VisualItemModel {
  2.     id: menuListModel
  3.     FileMenu{
  4.         width: menuListView.width
  5.         height: menuBar.height
  6.         color: fileColor
  7.     }
  8.     EditMenu{
  9.         color: editColor
  10.         width:  menuListView.width
  11.         height: menuBar.height
  12.     }
  13. }

ListView [doc.qt.nokia.com] element prikazuje model prema delegatu. Delagat mode deklarirati da se elementi modela prikazuju unutar Row elementa ili da ih se prikaže unutar mrežnog prikaza. Naš menuListModel već ima vidljive elemente te nije potrebno deklarirati delegata.

  1. ListView {
  2.     id: menuListView
  3.  
  4.     //Anchors are set to react to window anchors
  5.     anchors.fill:parent
  6.     anchors.bottom: parent.bottom
  7.     width:parent.width
  8.     height: parent.height
  9.  
  10.     //the model contains the data
  11.     model: menuListModel
  12.  
  13.     //control the movement of the menu switching
  14.     snapMode: ListView.SnapOneItem
  15.     orientation: ListView.Horizontal
  16.     boundsBehavior: Flickable.StopAtBounds
  17.     flickDeceleration: 5000
  18.     highlightFollowsCurrentItem: true
  19.     highlightMoveDuration:240
  20.     highlightRangeMode: ListView.StrictlyEnforceRange
  21. }

U to ListView nasljeđuje Flickable i time reagira na pomake miša. Zasdnji dio koda iznad postavlja Flickable svojstva da reagiraju na pokrete unutar našeg programa. PReciznije, svojstvo highlightMoveDuration određuje vrijeme izmjene između dva izbornika. Veća vrijednost, highlightMoveDuration uzrokovat će sporiju izmjenu izbornika.

ListView sadržava sve elemente po indeksima i svaki vizualni element je dostupan po tom indeksu, soritano po redu deklaracije. Izmjena currentIndex izmjenjuje označeni element unutar ListView elementa. Ovaj efekt dobvro je vidljiv na zaglavlju našeg izbornika. U redu se nalaze dva dugmeta koji kad se kliken na njih mijenjaju trenutno odabrani izbornik. Dugme fileButton izmijenit će trenbutno odabrani izbornik na File izbornik, s indeksom 0 pošto je FileMenu prvi deklariran unutar menuListModel elementa. Slično tome, editButton će promijeniti trenutni izbornik na EditMenu.

Rectangle objekt labelList imna svojstvo <i>z</i> postavljenmo na 1, što znači da će biti prikazan ispred izborničke trake. ELementi s nižom <i>z</i> vrijednosti bit će prikazane ispred elementa s višom <i>z</i> vrijednoti. Osnovna vrijednost <i>z</i> je 0.

  1. Rectangle{
  2.     id: labelList
  3.     ...
  4.     z: 1
  5.     Row{
  6.         anchors.centerIn: parent
  7.         spacing:40
  8.         Button{
  9.             label: "File"
  10.             id: fileButton
  11.             ...
  12.             onButtonClick: menuListView.currentIndex = 0
  13.         }
  14.         Button{
  15.             id: editButton
  16.             label: "Edit"
  17.             ...
  18.             onButtonClick:    menuListView.currentIndex = 1
  19.         }
  20.     }
  21. }

The menu bar we just created can be flicked to access the menus or by clicking on the menu names at the top. Switching menu screens feel intuitive and responsive.
Izbornička traka koju smo upravo kreirali može biti manipulirana da bi se izbornicima pristupalo klikajući po nazivu izbornika na vrhu. Izmjena izborničkih ekrana djeluje intuitivno i ima brzi odaziv.

Izrada Text Editora

Deklaracija Text Area

Naš Tekst editor ne bi bio tekst editor a da nema u sebi površinu na kojoj možemo raditi izmjene na tekstu. QML ima TextEdit [doc.qt.nokia.com] element koji omogućuje deklaraciju područja za prikaz i izmjene teksta. TextEdit [doc.qt.nokia.com] se razlikuje od običnog Text [doc.qt.nokia.com] koji nema mogućnost izmjene teksta.

  1.      TextEdit{
  2.          id: textEditor
  3.          anchors.fill:parent
  4.          width:parent.width; height:parent.height
  5.          color:"midnightblue"
  6.          focus: true
  7.  
  8.          wrapMode: TextEdit.Wrap
  9.  
  10.          onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)
  11.      }