Getting Started Programming with QML/hu: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
<sub>Az alant olvasható leírás rev. 0.2 verziót visel, ezzel is jelezve, hogy a jövőben szeretnénk még csiszolni rajta</sub> <span class="smiley">:)</span>
<sub>Az alant olvasható leírás rev. 0.2 verziót visel, ezzel is jelezve, hogy a jövőben szeretnénk még csiszolni rajta</sub> :)


=Bevezetés a <span class="caps">QML</span> programozásba=
= Bevezetés a QML programozásba =


Üdvözöllek a <span class="caps">QML</span> világában, mely egy UI leíró nyelv! Ebben a bevezetőben egy egyszerű szövegszerkesztő alkalmazást fogunk létrehozni a <span class="caps">QML</span> segítségével. Ezen útmutató olvasása után már készen fogsz állni, hogy kifejleszd a saját alkalmazásaidat a <span class="caps">QML</span> és a Qt keretrendszer segítségével.
Üdvözöllek a QML világában, mely egy UI leíró nyelv! Ebben a bevezetőben egy egyszerű szövegszerkesztő alkalmazást fogunk létrehozni a QML segítségével. Ezen útmutató olvasása után már készen fogsz állni, hogy kifejleszd a saját alkalmazásaidat a QML és a Qt keretrendszer segítségével.


==Felhasználói felület létrehozása <span class="caps">QML</span> nyelven==
== Felhasználói felület létrehozása QML nyelven ==


Példa alkalmazásunk egy egyszerű szövegszerkesztő lesz, amely alkalmas egyszerű szövegfájlok megnyitására illetve alapvető szerkesztési műveletek elvégzésére. A leírás első részében a program felhasználói felületét tervezzük meg a <span class="caps">QML</span> leírónyelv segítségével. A második részben a fájlok betöltése és elmentése lesz implementálva C++ nyelven. A Qt [http://doc.qt.nokia.com/4.7/metaobjects.html Meta-Object System] ''[doc.qt.nokia.com]'' segítségével a C++ függvényeket olyan tulajdonságokként ábrázolhatjuk, melyeket a <span class="caps">QML</span> elemek is képesek használni. <span class="caps">QML</span> és Qt C++ használatával hatékonyan szétválaszthatjuk a kezelői felület felépítését és a program logikáját.
Példa alkalmazásunk egy egyszerű szövegszerkesztő lesz, amely alkalmas egyszerű szövegfájlok megnyitására illetve alapvető szerkesztési műveletek elvégzésére. A leírás első részében a program felhasználói felületét tervezzük meg a QML leírónyelv segítségével. A második részben a fájlok betöltése és elmentése lesz implementálva C++ nyelven. A Qt &quot;Meta-Object System&amp;quot;:http://doc.qt.nokia.com/4.7/metaobjects.html segítségével a C++ függvényeket olyan tulajdonságokként ábrázolhatjuk, melyeket a QML elemek is képesek használni. QML és Qt C++ használatával hatékonyan szétválaszthatjuk a kezelői felület felépítését és a program logikáját.


[[Image:qml-texteditor5_editmenu.png|qml-texteditor5_editmenu.png]]
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png|qml-texteditor5_editmenu.png]]


<span class="caps">QML</span> példakódunk futtatásához csupán adjuk meg argumentumként a [http://doc.qt.nokia.com/4.7/qmlviewer.html qmlviewer] ''[doc.qt.nokia.com]'' programnak a <span class="caps">QML</span> fájlunkat. Ezen útmutató C++ része feltételezi, hogy az olvasó le tud fordítani egy Qt-ban írt programot.
QML példakódunk futtatásához csupán adjuk meg argumentumként a &quot;qmlviewer&amp;quot;:http://doc.qt.nokia.com/4.7/qmlviewer.html programnak a QML fájlunkat. Ezen útmutató C++ része feltételezi, hogy az olvasó le tud fordítani egy Qt-ban írt programot.


Az útmutató fejezetei:
Az útmutató fejezetei:
Line 19: Line 19:
# Szövegszerkesztő létrehozása
# Szövegszerkesztő létrehozása
# A szövegszerkesztő küllemének megteremtése
# A szövegszerkesztő küllemének megteremtése
# <span class="caps">QML</span> kibővítése Qt C++ segítségével
# QML kibővítése Qt C++ segítségével


==Nyomógomb és menü létrehozása==
== Nyomógomb és menü létrehozása ==


===Alapelemek – a gomb===
=== Alapelemek – a gomb ===


Szövegszerkesztőnket egy gomb létrehozásával kezdjük. Ha funkcionálisan nézzük, akkor a gomb rendelkezik egy egér számára érzékeny területtel és egy felirattal. A gombok akkor hajtják végre a feladatokat, ha a felhasználó rájuk klikkel. <span class="caps">QML</span>-ben a legalapvetőbb vizuális elem a [http://doc.qt.nokia.com/4.7/qml-rectangle.html Rectangle] ''[doc.qt.nokia.com]''. ''A Rectangle'' elem tulajdonságokkal rendelkezik, hogy beállíthassunk az elem megjelenését és elhelyezkedését.
Szövegszerkesztőnket egy gomb létrehozásával kezdjük. Ha funkcionálisan nézzük, akkor a gomb rendelkezik egy egér számára érzékeny területtel és egy felirattal. A gombok akkor hajtják végre a feladatokat, ha a felhasználó rájuk klikkel. QML-ben a legalapvetőbb vizuális elem a &quot;Rectangle&amp;quot;:http://doc.qt.nokia.com/4.7/qml-rectangle.html. ''A Rectangle'' elem tulajdonságokkal rendelkezik, hogy beállíthassunk az elem megjelenését és elhelyezkedését.


Először az ''import Qt 4.7'' sor engedélyezi a qmlviewer eszköznek, hogy betöltse azokat a <span class="caps">QML</span> elemeket, melyeket később használni fogunk. Ennek a sornak szerepelnie kell minden <span class="caps">QML</span> fájlban! Figyeljük meg, hogy a Qt modulok verzióját az import utasítás már tartalmazza!
Először az ''import Qt 4.7'' sor engedélyezi a qmlviewer eszköznek, hogy betöltse azokat a QML elemeket, melyeket később használni fogunk. Ennek a sornak szerepelnie kell minden QML fájlban! Figyeljük meg, hogy a Qt modulok verzióját az import utasítás már tartalmazza!


Ez az egyszerű ''Rectangle'' rendelkezik egy egyedi azonosítóval, ''simplebutton'', amely az ''id'' tulajdonsághoz kötődik. A ''Rectangle'' elem tulajdonságaihoz értékeket rendelünk a tulajdonság kilistázásakor, ekkor a kettőspont után áll az érték. A mintakódban a grey (szürke) színt rendeltük a ''Rectangle'' ''color'' tulajdonságához. Hasonlóan járunk el a ''Rectangle'' ''width'' és ''height'' tulajdonságainak esetében.
Ez az egyszerű ''Rectangle'' rendelkezik egy egyedi azonosítóval, ''simplebutton'', amely az ''id'' tulajdonsághoz kötődik. A ''Rectangle'' elem tulajdonságaihoz értékeket rendelünk a tulajdonság kilistázásakor, ekkor a kettőspont után áll az érték. A mintakódban a grey (szürke) színt rendeltük a ''Rectangle'' ''color'' tulajdonságához. Hasonlóan járunk el a ''Rectangle'' ''width'' és ''height'' tulajdonságainak esetében.
Line 35: Line 35:
Most mentsük el a kódot ''SimpleButton.qml'' néven. Futtassuk a ''qmlviewer''-t a fájlunkat argumentumként megadva. Egy szürke téglalapot fogunk látni, benne a feliratunkkal.
Most mentsük el a kódot ''SimpleButton.qml'' néven. Futtassuk a ''qmlviewer''-t a fájlunkat argumentumként megadva. Egy szürke téglalapot fogunk látni, benne a feliratunkkal.


A gombnyomás funkciójának implementálására használhatjuk a <span class="caps">QML</span> eseménykezelő metódusát. A <span class="caps">QML</span> esemény kezelése nagyon hasonlít a Qt signal and slot mechanizmusára. Példánkban az onClicked handlerben kezeljük le az eseményt.
A gombnyomás funkciójának implementálására használhatjuk a QML eseménykezelő metódusát. A QML esemény kezelése nagyon hasonlít a Qt signal and slot mechanizmusára. Példánkban az onClicked handlerben kezeljük le az eseményt.


Létrehozunk egy [[qml-mousearea.html|MouseArea]] elemet a ''simplebutton''-on belül. A ''MouseArea'' elem meghatározza azt az interaktív területet, ahol érzékelni fogjuk majd az egérkattintásokat. Gombunk esetében az egész ''MouseArea''-t a szülőjéhez kapcsoljuk, ami most a ''simplebutton''. Az ''anchors.fill'' szintaktika is egy mód, hogy elérjünk egy bizonyos tulajdonságot (''fill''), az ''anchors'' tulajdonságokon belül. A <span class="caps">QML</span> kapocs alapú vázat használ, ahol az egyes elemek más elemekhez kapcsolhatók, így robosztus vázakat hozhatunk létre.
<code><br />Rectangle{<br /> id:simplebutton<br /> …
 
MouseArea{<br /> id: buttonMouseArea
 
anchors.fill: parent //anchor all sides of the mouse area to the rectangle&amp;amp;#8217;s anchors<br /> //onClicked handles valid mouse button clicks<br /> onClicked: console.log(buttonLabel.text + &amp;#8221; clicked&amp;amp;#8221; )<br /> }<br /> }<br /></code>
 
Létrehozunk egy &quot;MouseArea&amp;quot;:qml-mousearea.html elemet a ''simplebutton''-on belül. A ''MouseArea'' elem meghatározza azt az interaktív területet, ahol érzékelni fogjuk majd az egérkattintásokat. Gombunk esetében az egész ''MouseArea''-t a szülőjéhez kapcsoljuk, ami most a ''simplebutton''. Az ''anchors.fill'' szintaktika is egy mód, hogy elérjünk egy bizonyos tulajdonságot (''fill''), az ''anchors'' tulajdonságokon belül. A QML kapocs alapú vázat használ, ahol az egyes elemek más elemekhez kapcsolhatók, így robosztus vázakat hozhatunk létre.


A ''MouseArea''-nak sok jelfeldolgozója ún. handler-je van, amelyek a meghatározott ''MouseArea'' határain belül történő egér események hatására hívódnak meg. Ezek közül az egyik az ''onClicked'', amely a gomb megnyomásakor hívódik meg, alapértelmezésben ez itt a bal gomb. Műveleteket is köthetünk az ''onClicked'' handler-jéhez. A példánkban, a ''console.log()'' szöveget ír a kimenetre, akárhányszor ráklikkelünk a ''MouseArea'' területére. ''A console.log()'' függvény egy nagyon hasznos eszköz hibakeresésre, segítségével bármit kiírathatunk a konzolba.
A ''MouseArea''-nak sok jelfeldolgozója ún. handler-je van, amelyek a meghatározott ''MouseArea'' határain belül történő egér események hatására hívódnak meg. Ezek közül az egyik az ''onClicked'', amely a gomb megnyomásakor hívódik meg, alapértelmezésben ez itt a bal gomb. Műveleteket is köthetünk az ''onClicked'' handler-jéhez. A példánkban, a ''console.log()'' szöveget ír a kimenetre, akárhányszor ráklikkelünk a ''MouseArea'' területére. ''A console.log()'' függvény egy nagyon hasznos eszköz hibakeresésre, segítségével bármit kiírathatunk a konzolba.


A ''SimpleButton.qml'' kódja már képes arra, hogy megjelenítsen egy gombot és szöveget írjon képernyőre klikkeléskor.
A ''SimpleButton.qml'' kódja már képes arra, hogy megjelenítsen egy gombot és szöveget írjon képernyőre klikkeléskor.
<code><br />Rectangle {<br /> id: button<br /> …
property color buttonColor: &amp;#8220;lightblue&amp;amp;#8221;<br /> property color onHoverColor: &amp;#8220;gold&amp;amp;#8221;<br /> property color borderColor: &amp;#8220;white&amp;amp;#8221;
signal buttonClick()<br /> onButtonClick: {<br /> console.log(buttonLabel.text + &amp;#8221; clicked&amp;amp;#8221; )<br /> }
MouseArea{<br /> id: buttonMouseArea<br /> onClicked: buttonClick()<br /> hoverEnabled: true<br /> onEntered: parent.border.color = onHoverColor<br /> onExited: parent.border.color = borderColor<br /> }
//determines the color of the button by using the conditional operator<br /> color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> }<br /></code>


Egy teljesen működő gomb a ''Button.qml'' fájlban található. Ebben a leírásban szereplő kódrészlet mellőz néhány részletet, mert azokat már vagy tárgyaltuk az előzőekben vagy irreleváns a kód értelmezése szempontjából.
Egy teljesen működő gomb a ''Button.qml'' fájlban található. Ebben a leírásban szereplő kódrészlet mellőz néhány részletet, mert azokat már vagy tárgyaltuk az előzőekben vagy irreleváns a kód értelmezése szempontjából.


Egyedi tulajdonságokat a ''tulajdonság típus név'' szintaktikával tudunk deklarálni. Kódunkban a ''color'' típusú ''buttonColor'' tulajdonsághoz a „lightblue”-t rendeljük. A ''buttonColor'' később lesz használva egy kiegészítő műveletben, hogy meghatározzuk a gomb kitöltési színét. Megemlítendő, hogy értékadás az = jellel is történhet a kettőspont helyett. Az egyedi tulajdonságok lehetővé teszik, hogy belső elemek kívülről hozzáférhetőek legyenek, a ''Rectangle'' hatósugarán kívül is. A <span class="caps">QML</span>-nek megvannak a maga alaptípusai, mint az ''int'', a ''real'', a ''string'', vagy az általános konténertípus a ''variant''.
Egyedi tulajdonságokat a ''tulajdonság típus név'' szintaktikával tudunk deklarálni. Kódunkban a ''color'' típusú ''buttonColor'' tulajdonsághoz a „lightblue”-t rendeljük. A ''buttonColor'' később lesz használva egy kiegészítő műveletben, hogy meghatározzuk a gomb kitöltési színét. Megemlítendő, hogy értékadás az = jellel is történhet a kettőspont helyett. Az egyedi tulajdonságok lehetővé teszik, hogy belső elemek kívülről hozzáférhetőek legyenek, a ''Rectangle'' hatósugarán kívül is. A QML-nek megvannak a maga alaptípusai, mint az ''int'', a ''real'', a ''string'', vagy az általános konténertípus a ''variant''.


Színeket hozzáadva az ''onEntered'' és az ''onExited'' jelkezelőkhöz, a gomb szegélye sárgává fog válni, amikor az egér a gomb fölé ér, és visszaáll az eredeti színre, ha a kurzor távozik a területéről.
Színeket hozzáadva az ''onEntered'' és az ''onExited'' jelkezelőkhöz, a gomb szegélye sárgává fog válni, amikor az egér a gomb fölé ér, és visszaáll az eredeti színre, ha a kurzor távozik a területéről.
Line 51: Line 67:
Egy ''buttonClick()'' signalt is deklarálunk a ''Button.qml''-ben a signal neve elé tett signal kulcsszóval. Minden signal-nak automatikusan létrejön a handler-je, „on”-al kezdődő nevekkel. Így értelemszerűen az ''onButtonClicked'' a ''buttonClicked'' handler-je. Ezután az ''onButtonClicked''-edet összekötjük egy művelettel, hogy az megfelelően működhessen. A mi gomb-példánkban egérkattintásra az ''onClicked'' handlerje szimplán meg fogja hívni az ''onButtonClick'' függvényt, mely megjelenít egy szöveget. Az ''onButtonClick'' lehetővé teszi, hogy külső objektumok könnyedén hozzáférjenek a ''Button'' klikkelési területéhez. Például egy elemnek több ''MouseArea'' deklarációja is van és a ''ButtonClick'' signal jobban el tudja végezni a megkülönböztetést a több ''MouseArea'' handler között.
Egy ''buttonClick()'' signalt is deklarálunk a ''Button.qml''-ben a signal neve elé tett signal kulcsszóval. Minden signal-nak automatikusan létrejön a handler-je, „on”-al kezdődő nevekkel. Így értelemszerűen az ''onButtonClicked'' a ''buttonClicked'' handler-je. Ezután az ''onButtonClicked''-edet összekötjük egy művelettel, hogy az megfelelően működhessen. A mi gomb-példánkban egérkattintásra az ''onClicked'' handlerje szimplán meg fogja hívni az ''onButtonClick'' függvényt, mely megjelenít egy szöveget. Az ''onButtonClick'' lehetővé teszi, hogy külső objektumok könnyedén hozzáférjenek a ''Button'' klikkelési területéhez. Például egy elemnek több ''MouseArea'' deklarációja is van és a ''ButtonClick'' signal jobban el tudja végezni a megkülönböztetést a több ''MouseArea'' handler között.


Most már megvan az alaptudásunk, hogy implementáljunk olyan elemeket <span class="caps">QML</span>-ben, melyek képesek lekezelni alap egérműveleteket. Hozzunk létre egy ''Text'' feliratot egy ''Rectangle''-ben, szabjuk testre a tulajdonságait és implementáljuk az egérmozgásokra válaszoló műveleteit. Ez az alapelv, hogy elemeket hozunk létre más elemeken belül, végig fogja kísérni a szövegszerkesztő programunkat. Ám ez a gomb haszontalan, amíg nem műveletek ellátására szolgáló komponensként használjuk. A következő részben létrehozunk egy menüt, mely több ilyen gombot is tartalmazni fog.
Most már megvan az alaptudásunk, hogy implementáljunk olyan elemeket QML-ben, melyek képesek lekezelni alap egérműveleteket. Hozzunk létre egy ''Text'' feliratot egy ''Rectangle''-ben, szabjuk testre a tulajdonságait és implementáljuk az egérmozgásokra válaszoló műveleteit. Ez az alapelv, hogy elemeket hozunk létre más elemeken belül, végig fogja kísérni a szövegszerkesztő programunkat. Ám ez a gomb haszontalan, amíg nem műveletek ellátására szolgáló komponensként használjuk. A következő részben létrehozunk egy menüt, mely több ilyen gombot is tartalmazni fog.
 
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_button.png|qml-texteditor1_button]]
 
=== Menü létrehozása ===


[[Image:qml-texteditor1_button.png|qml-texteditor1_button]]
Eddig a részig áttekintettük, hogyan hozzunk létre elemeket és kössünk hozzájuk műveleteket egy QML fájlon belül. Ebben a fejezetben megtanuljuk, hogyan importáljunk QML elemeket és hogyan használjuk fel ezeket a komponenseket újra, hogy újabb komponenseket hozzunk létre.


===Menü létrehozása===
Egy menü egy lista tartalmát jeleníti meg, mindegyik elemnek megvan a lehetősége, hogy végrehajtson egy feladatot. QML-ben sokféleképpen hozhatunk létre menüket. Először egy, a gombokat tartalmazó menüt fogunk készíteni, melyek különböző műveleteket hajtanak majd végre. A menü kódja a ''FileMenu.qml''-ben található.


Eddig a részig áttekintettük, hogyan hozzunk létre elemeket és kössünk hozzájuk műveleteket egy <span class="caps">QML</span> fájlon belül. Ebben a fejezetben megtanuljuk, hogyan importáljunk <span class="caps">QML</span> elemeket és hogyan használjuk fel ezeket a komponenseket újra, hogy újabb komponenseket hozzunk létre.
<code><br />import Qt 4.7 import the main Qt QML module<br />import &amp;#8220;folderName&amp;amp;#8221; import the contents of the folder<br />import &amp;#8220;script.js&amp;amp;#8221; as Script import a Javascript file and name it as Script<br /></code>


Egy menü egy lista tartalmát jeleníti meg, mindegyik elemnek megvan a lehetősége, hogy végrehajtson egy feladatot. <span class="caps">QML</span>-ben sokféleképpen hozhatunk létre menüket. Először egy, a gombokat tartalmazó menüt fogunk készíteni, melyek különböző műveleteket hajtanak majd végre. A menü kódja a ''FileMenu.qml''-ben található.
A fent használt szintaktika megmutatja, hogyan használjuk az import parancsot. Olyan JavaScript vagy QML fájlok használatakor van szükségünk rá, melyek nem ugyanabban a mappában vannak. Mivel a ''Button.qml'' ugyanabban a mappában van, mint a ''FileMenu.qml'', így nem kell importálnunk a ''button.qml''-t, hogy használhassuk. Azonnal létrehozhatunk egy ''Button'' elemet a ''Button { }'' függvényt deklarálva, hasonlóan a ''Rectangle { }''-hoz.


A fent használt szintaktika megmutatja, hogyan használjuk az import parancsot. Olyan JavaScript vagy <span class="caps">QML</span> fájlok használatakor van szükségünk rá, melyek nem ugyanabban a mappában vannak. Mivel a ''Button.qml'' ugyanabban a mappában van, mint a ''FileMenu.qml'', így nem kell importálnunk a ''button.qml''-t, hogy használhassuk. Azonnal létrehozhatunk egy ''Button'' elemet a ''Button { }'' függvényt deklarálva, hasonlóan a ''Rectangle { }''-hoz.
<code><br />In FileMenu.qml:


A ''FileMenu.qml''-ben deklaráljunk egy ''Row'' elemen belül 3 ''Button'' elemet. A ''Row'' egy pozícionáló elem, ami egy vízszintes sorban rendezi el a gyerekeit.
Row{<br /> anchors.centerIn: parent<br /> spacing: parent.width/6


A ''Button'' deklarációja a ''Button.qml''-ben van, ami ugyan az a ''Button.qml'', amit mi az előző fejezetben használtunk. Új tulajdonságkötéseket deklarálhatunk az újonnan létrehozott gombokban, hatékonyan felülírva a ''Button.qml''-ben beállított tulajdonságokat. Az Exit gomb megnyomásának hatására ki fog lépni a program és bezárja az ablakot. Gondoljuk végig, hogy a ''Button.qml''-ben lévő ''onButtonClick'' signal handler is meg lesz hívva az ''exitButton''-ban lévő ''onButtonClick'' handleren kívül.
Button{<br /> id: loadButton<br /> buttonColor: &amp;#8220;lightgrey&amp;amp;#8221;<br /> label: &amp;#8220;Load&amp;amp;#8221;<br /> }<br /> Button{<br /> buttonColor: &amp;#8220;grey&amp;amp;#8221;<br /> id: saveButton<br /> label: &amp;#8220;Save&amp;amp;#8221;<br /> }<br /> Button{<br /> id: exitButton<br /> label: &amp;#8220;Exit&amp;amp;#8221;<br /> buttonColor: &amp;#8220;darkgrey&amp;amp;#8221;


[[Image:qml-texteditor1_filemenu.png|qml-texteditor1_filemenu]]
onButtonClick: Qt.quit()<br /> }<br /> }<br /></code>


A ''Row''.t a ''Rectangle''.en belül deklaráljuk, ezzel létrehozunk egy ''Rectangle- tárolót a gombok sorának. A második _Rectangle'' létrehozása a menü gombjainak egy sorban történő tárolására indirekt módon történik. A Edit menü nagyon hasonló ebben a fázisban. Ez a menu is 3 gombot fog tartalmazni a következő nevekkel: Copy, Paste, Select All.
A ''FileMenu.qml''-ben deklaráljunk egy ''Row'' elemen belül 3 ''Button'' elemet. A ''Row'' egy pozícionáló elem, ami egy vízszintes sorban rendezi el a gyerekeit.


[[Image:qml-texteditor1_editmenu.png|qml-texteditor1_editmenu]]
A ''Button'' deklarációja a ''Button.qml''-ben van, ami ugyan az a ''Button.qml'', amit mi az előző fejezetben használtunk. Új tulajdonságkötéseket deklarálhatunk az újonnan létrehozott gombokban, hatékonyan felülírva a ''Button.qml''-ben beállított tulajdonságokat. Az Exit gomb megnyomásának hatására ki fog lépni a program és bezárja az ablakot. Gondoljuk végig, hogy a ''Button.qml''-ben lévő ''onButtonClick'' signal handler is meg lesz hívva az ''exitButton''<s>ban lévő ''onButtonClick'' handleren kívül.
<br />p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_filemenu.png|qml-texteditor1_filemenu]]
<br />A ''Row''.t a ''Rectangle''.en belül deklaráljuk, ezzel létrehozunk egy _Rectangle</s> tárolót a gombok sorának. A második ''Rectangle'' létrehozása a menü gombjainak egy sorban történő tárolására indirekt módon történik. A Edit menü nagyon hasonló ebben a fázisban. Ez a menu is 3 gombot fog tartalmazni a következő nevekkel: Copy, Paste, Select All.


Most, hogy tudjuk hogyan importáljuk és szabjuk testre az előzőleg már létrehozott komponenseiket, már elkészíthetjük a menüsorunkat, mely a menüpontok kiválasztására szolgáló gombokból fog állni. Nézzük meg, hogyan rendszerezzük adatainkat a <span class="caps">QML</span>-ben!
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_editmenu.png|qml-texteditor1_editmenu]]


==A menüsor implementálása==
Most, hogy tudjuk hogyan importáljuk és szabjuk testre az előzőleg már létrehozott komponenseiket, már elkészíthetjük a menüsorunkat, mely a menüpontok kiválasztására szolgáló gombokból fog állni. Nézzük meg, hogyan rendszerezzük adatainkat a QML-ben!
 
== A menüsor implementálása ==


Szövegszerkesztőnknek meg kell tudni jelenítenie a menüket a menüsorból. A menüsoron kiválaszthatja a felhasználó, hogy melyik menüt jelenítse meg a program. A menük közötti váltásból következik, hogy az egy sorba rendezésnél bonyolultabb struktúrával fog rendelkezni a menünk.
Szövegszerkesztőnknek meg kell tudni jelenítenie a menüket a menüsorból. A menüsoron kiválaszthatja a felhasználó, hogy melyik menüt jelenítse meg a program. A menük közötti váltásból következik, hogy az egy sorba rendezésnél bonyolultabb struktúrával fog rendelkezni a menünk.


===Adatmodellek (''Data Models'') és adatnézetek (''Data Views'') használata:===
=== Adatmodellek (''Data Models'') és adatnézetek (''Data Views'') használata: ===


Különböző [http://doc.qt.nokia.com/4.7/qdeclarativemodels.html Data View] ''[doc.qt.nokia.com]'' -kal rendelkezik a <span class="caps">QML</span> a [http://doc.qt.nokia.com/4.7/qdeclarativemodels.html Data Model] ''[doc.qt.nokia.com]'' -ek megjelenítésére. Menüsorunk listaként fogja megjeleníteni a kiválasztott menüt egy fejléccel, ahol többi menü nevét soroljuk fel vízszintesen. A menülistánk egy [http://doc.qt.nokia.com/4.7/qml-visualitemmodel.html VisualItemModel] ''[doc.qt.nokia.com]'' -ben lesz deklarálva, mely olyan elemeket tartalmaz, melyek már eleve rendelkeznek valamilyen megjelenéssel, mint például egy ''Rectangle'' vagy egy importált UI elem. Más modell típusoknak, mint például a [http://doc.qt.nokia.com/4.7/qml-listmodel.html ListModel] ''[doc.qt.nokia.com]'', egy megbízott kell, hogy megjelenítse az adatait. Két vizuális elemet deklarálunk a menuListModel-ünkben, a ''FileMenu''-t és az ''EditMenu''-t. Testreszabjuk a két menüt és megjelenítjük őket a [http://doc.qt.nokia.com/4.7/qml-listview.html ListView] ''[doc.qt.nokia.com]'' -val. A ''Menubar.qml'' fájlunk tartalmazza a <span class="caps">QML</span> deklarálását és egy egyszerű szerkesztői menüt, melyet az ''EditMenu.qml''-ben hoztunk létre.
Különböző &quot;Data View&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html -kal rendelkezik a QML a &quot;Data Model&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html -ek megjelenítésére. Menüsorunk listaként fogja megjeleníteni a kiválasztott menüt egy fejléccel, ahol többi menü nevét soroljuk fel vízszintesen. A menülistánk egy &quot;VisualItemModel&amp;quot;:http://doc.qt.nokia.com/4.7/qml-visualitemmodel.html -ben lesz deklarálva, mely olyan elemeket tartalmaz, melyek már eleve rendelkeznek valamilyen megjelenéssel, mint például egy ''Rectangle'' vagy egy importált UI elem. Más modell típusoknak, mint például a &quot;ListModel&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listmodel.html, egy megbízott kell, hogy megjelenítse az adatait. Két vizuális elemet deklarálunk a menuListModel-ünkben, a ''FileMenu''-t és az ''EditMenu''-t. Testreszabjuk a két menüt és megjelenítjük őket a &quot;ListView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listview.html -val. A ''Menubar.qml'' fájlunk tartalmazza a QML deklarálását és egy egyszerű szerkesztői menüt, melyet az ''EditMenu.qml''-ben hoztunk létre.
 
<code><br />VisualItemModel{<br /> id: menuListModel<br /> FileMenu{<br /> width: menuListView.width<br /> height: menuBar.height<br /> color: fileColor<br /> }<br /> EditMenu{<br /> color: editColor<br /> width: menuListView.width<br /> height: menuBar.height<br /> }<br /> }<br /></code>


A ''ListView'' elem egy megbízotton keresztül fogja megjeleníteni a modellünket. A megbízott lehet hogy meghatározza, hogy például egy sorban vagy egy hálóban jelenítse meg az elemeket. A mi ''menuListModel''-ünknek már vannak látható elemei, így nekünk nem kell megbízottat deklarálnunk hozzá.
A ''ListView'' elem egy megbízotton keresztül fogja megjeleníteni a modellünket. A megbízott lehet hogy meghatározza, hogy például egy sorban vagy egy hálóban jelenítse meg az elemeket. A mi ''menuListModel''-ünknek már vannak látható elemei, így nekünk nem kell megbízottat deklarálnunk hozzá.


A [http://doc.qt.nokia.com/4.7/qml-flickable.html Flickable] ''[doc.qt.nokia.com]'' -ből örököljük a ''ListView''-unkat, ezzel a listánk reagálhat majd az egérmozdulatokra és más gesztusokra. Fenti kódunk utolsó része beállítja a ''Flickable'' tuljadonságait, hogy létrehozzunk a nézetünk kívánt kinetikus mozgását. A ''highLightMovementDuration'' tuljadonság meghatározza, hogy meddig tartson a kinetikus transzformáció. Egy nagyobb ''highLightMovementDuration'' érték lassabb menüváltást fog eredményezni. A ''ListView'' a modell minden egyes elemét egy indexszel látja el a deklarálásuk sorrendjében, melyeket ezeken az indexeken keresztül érhetünk el. A ''currentIndex'' értékének megváltoztatásával a ''ListView'' egy másik elemét jelöljük ki. A menüsor fejlécére is hatással lesz ez az effektus. Két gomb van egy sorban, melyek mindketten megváltozatják a megjelenített menüt, ha rájuk klikkelünk. A ''filebutton''-ra kattintva megjelenik a fálj menü, az index pedig 0 lesz, mivel a ''FileMenu''-t deklaráltuk először. A ''labelList'' ''rectangle''-jének van egy z értéke, mely itt 1, ezzel jelölve, hogy ezt a menüsor előtt jelenítjük meg. Minél nagyobb a z értéke, annál előrébb foglal helyet a képernyőre merőleges síkban. A z alapértelmezett értéke 0.
<code><br />ListView{<br /> id: menuListView
 
//Anchors are set to react to window anchors<br /> anchors.fill:parent<br /> anchors.bottom: parent.bottom<br /> width:parent.width<br /> height: parent.height
 
//the model contains the data<br /> model: menuListModel
 
//control the movement of the menu switching<br /> snapMode: ListView.SnapOneItem<br /> orientation: ListView.Horizontal<br /> boundsBehavior: Flickable.StopAtBounds<br /> flickDeceleration: 5000<br /> highlightFollowsCurrentItem: true<br /> highlightMoveDuration:240<br /> highlightRangeMode: ListView.StrictlyEnforceRange<br /> }<br /></code>
 
A &quot;Flickable&amp;quot;:http://doc.qt.nokia.com/4.7/qml-flickable.html -ből örököljük a ''ListView''-unkat, ezzel a listánk reagálhat majd az egérmozdulatokra és más gesztusokra. Fenti kódunk utolsó része beállítja a ''Flickable'' tuljadonságait, hogy létrehozzunk a nézetünk kívánt kinetikus mozgását. A ''highLightMovementDuration'' tuljadonság meghatározza, hogy meddig tartson a kinetikus transzformáció. Egy nagyobb ''highLightMovementDuration'' érték lassabb menüváltást fog eredményezni. A ''ListView'' a modell minden egyes elemét egy indexszel látja el a deklarálásuk sorrendjében, melyeket ezeken az indexeken keresztül érhetünk el. A ''currentIndex'' értékének megváltoztatásával a ''ListView'' egy másik elemét jelöljük ki. A menüsor fejlécére is hatással lesz ez az effektus. Két gomb van egy sorban, melyek mindketten megváltozatják a megjelenített menüt, ha rájuk klikkelünk. A ''filebutton''-ra kattintva megjelenik a fálj menü, az index pedig 0 lesz, mivel a ''FileMenu''-t deklaráltuk először. A ''labelList'' ''rectangle''-jének van egy z értéke, mely itt 1, ezzel jelölve, hogy ezt a menüsor előtt jelenítjük meg. Minél nagyobb a z értéke, annál előrébb foglal helyet a képernyőre merőleges síkban. A z alapértelmezett értéke 0.
 
<code><br /> Rectangle{<br /> id: labelList<br /> …<br /> z: 1<br /> Row{<br /> anchors.centerIn: parent<br /> spacing:40<br /> Button{<br /> label: &amp;#8220;File&amp;amp;#8221;<br /> id: fileButton<br /> …<br /> onButtonClick: menuListView.currentIndex = 0<br /> }<br /> Button{<br /> id: editButton<br /> label: &amp;#8220;Edit&amp;amp;#8221;<br /> …<br /> onButtonClick: menuListView.currentIndex = 1<br /> }<br /> }<br /> }<br /></code>


A létrehozott menüsorunkon vagy a felette lévő két gomb valamelyikére klikkelve megjeleníthetjük a menüket. Így egy intuitív és interaktív menüválasztó képernyőt alkottunk.
A létrehozott menüsorunkon vagy a felette lévő két gomb valamelyikére klikkelve megjeleníthetjük a menüket. Így egy intuitív és interaktív menüválasztó képernyőt alkottunk.


[[Image:qml-texteditor3_texteditor.png|qml-texteditor3_texteditor]]
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor3_texteditor.png|qml-texteditor3_texteditor]]
 
== A szövegszerkesztő megalkotása ==
 
=== TextArea deklarálása ===
 
Szövegszerkesztőnk mindaddig nem szövegszerkesztő, amíg nem tartalmaz egy szerkeszthető szövegmezőt.<br />A QML &quot;TextEdit&amp;quot;:http://doc.qt.nokia.com/4.7/qml-textedit.html eleme egy többsoros szövegmező létrehozását teszi lehetővé. A ''TextEdit'' különbözik a &quot;Text&amp;quot;:http://doc.qt.nokia.com/4.7/qml-text.html elemtől, melyet a felhasználó nem szerkeszthet direkt módon.
 
<code><br /> TextEdit{<br /> id: textEditor<br /> anchors.fill:parent<br /> width:parent.width; height:parent.height<br /> color:&amp;#8221;midnightblue&amp;amp;#8221;<br /> focus: true


==A szövegszerkesztő megalkotása==
wrapMode: TextEdit.Wrap


===TextArea deklarálása===
onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)<br /> }<br /></code>


Szövegszerkesztőnk mindaddig nem szövegszerkesztő, amíg nem tartalmaz egy szerkeszthető szövegmezőt.<br /> A <span class="caps">QML</span> [http://doc.qt.nokia.com/4.7/qml-textedit.html TextEdit] ''[doc.qt.nokia.com]'' eleme egy többsoros szövegmező létrehozását teszi lehetővé. A ''TextEdit'' különbözik a [http://doc.qt.nokia.com/4.7/qml-text.html Text] ''[doc.qt.nokia.com]'' elemtől, melyet a felhasználó nem szerkeszthet direkt módon.
A szerkesztőnek megvan a saját betűszín tulajdonsága is. A ''TextArea'' egy ''flickable'' mezőn belül van, mely görgetni fogja a szöveget, ha a szövegkurzor a látható mezőn kívül van. Az ''ensureVisibility()'' függvény fogja leellenőrizni, hogy a kurzor ''rectangle''-je kívül van-e a látható szegélyeken, és ha igen, akkor ennek megfelelően fogja mozgatni a szövegmezőt. A QML JavaScript szintaktikát használ a kódjaihoz, és ahogy már korábban említettük, importálhatunk és használhatunk is Javascript fájlokat egy QML fájlon belül.


A szerkesztőnek megvan a saját betűszín tulajdonsága is. A ''TextArea'' egy ''flickable'' mezőn belül van, mely görgetni fogja a szöveget, ha a szövegkurzor a látható mezőn kívül van. Az ''ensureVisibility()'' függvény fogja leellenőrizni, hogy a kurzor ''rectangle''-je kívül van-e a látható szegélyeken, és ha igen, akkor ennek megfelelően fogja mozgatni a szövegmezőt. A <span class="caps">QML</span> JavaScript szintaktikát használ a kódjaihoz, és ahogy már korábban említettük, importálhatunk és használhatunk is Javascript fájlokat egy <span class="caps">QML</span> fájlon belül.
<code><br /> function ensureVisible&amp;amp;#174;{<br /> if (contentX &gt;= r.x)<br /> contentX = r.x;<br /> else if (contentX+width &lt;= r.x+r.width)<br /> contentX = r.x+r.width-width;<br /> if (contentY &gt;= r.y)<br /> contentY = r.y;<br /> else if (contentY+height &lt;= r.y+r.height)<br /> contentY = r.y+r.height-height;<br /> }<br /></code>


===Komponensek kombinálása a szövegszerkesztőhöz===
=== Komponensek kombinálása a szövegszerkesztőhöz ===


Most már készen állunk, hogy létrehozzuk szövegszerkesztőnket a <span class="caps">QML</span> segítségével. Programunk két fő komponensből áll, az általunk létrehozott menüsorból és egy szövegmezőből. A <span class="caps">QML</span> lehetővé teszi, hogy újrafelhasználjuk komponenseinket azok importálásával és testreszabásával ha szükséges, ezzel is egyszerűbbé téve a kódunkat. A szövegszerkesztőnk egyharmadát a menüsor, kétharmadát a szövegmez fogja elfoglalni. A menüsor minden más elem előtt fog megjelenni.
Most már készen állunk, hogy létrehozzuk szövegszerkesztőnket a QML segítségével. Programunk két fő komponensből áll, az általunk létrehozott menüsorból és egy szövegmezőből. A QML lehetővé teszi, hogy újrafelhasználjuk komponenseinket azok importálásával és testreszabásával ha szükséges, ezzel is egyszerűbbé téve a kódunkat. A szövegszerkesztőnk egyharmadát a menüsor, kétharmadát a szövegmez fogja elfoglalni. A menüsor minden más elem előtt fog megjelenni.
 
<code><br /> Rectangle{
 
id: screen<br /> width: 1000; height: 1000
 
//the screen is partitioned into the MenuBar and TextArea. 1/3 of the screen is assigned to the MenuBar<br /> property int partition: height/3
 
MenuBar{<br /> id:menuBar<br /> height: partition<br /> width:parent.width<br /> z: 1<br /> }
 
TextArea{<br /> id:textArea<br /> anchors.bottom:parent.bottom<br /> y: partition<br /> color: &amp;#8220;white&amp;amp;#8221;<br /> height: partition*2<br /> width:parent.width<br /> }<br /> }<br /></code>


Újrafelhasznált komponenseikkel sokkal egyszerűbbnek tűnik a ''TextEditor'' forráskódja. Ezután testreszabhatjuk a fő alkalmazásunkat anélkül, hogy az előre definiál tulajdonságok miatt kellene aggódnunk. Ezzel a módszerrel könnyedén hozhatunk létre programvázakat és interfészeket.
Újrafelhasznált komponenseikkel sokkal egyszerűbbnek tűnik a ''TextEditor'' forráskódja. Ezután testreszabhatjuk a fő alkalmazásunkat anélkül, hogy az előre definiál tulajdonságok miatt kellene aggódnunk. Ezzel a módszerrel könnyedén hozhatunk létre programvázakat és interfészeket.


[[Image:qml-texteditor3_texteditor.png|qml-texteditor3_texteditor]]
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor3_texteditor.png|qml-texteditor3_texteditor]]
 
== Szövegszerkesztőnk megjelenésének testreszabása ==
 
=== A Drawer Interface implementálása ===
 
A szövegszerkesztőnk egyszerűen néz ki, most már a megjelenését is testre kellene szabnunk. A QML-t használva átmeneteket és animációkat deklarálhatunk a szövegszerkesztőnkhöz. Menüsorunk elfoglalja az ablak egyharmadát, így jó lenne, ha csak akkor jelenne meg, ha mi akarjuk.<br />Hozzáadhatunk egy rajzoló interfészt, amely összecsukja illetve megjeleníti a menüsort klikkeléskor. Jelen esetben egy kis ''rectange''.t használtunk, mely reagál az egérkattintásokra. A ''drawer'', akárcsak az maga az alkalmazás, két állapottal rendelkezik, egy nyitottal és egy zárttal. A ''drawer'' elem egy kis magasságú rectangle, amihez kapcsolunk egy &quot;Image&amp;quot;:ttp://doc.qt.nokia.com/4.7/qml-image.html elemet, egy kis nyíl ikont jelenítve meg középen a ''rectangle''-ön belül. A ''drawer'' meghatározza az program állapotát, ahogy a felhasználó rákattint a kis nyílra.
 
<code><br />Rectangle{<br /> id:drawer<br /> height:15
 
Image{<br /> id: arrowIcon<br /> source: &amp;#8220;images/arrow.png&amp;amp;#8221;<br /> anchors.horizontalCenter: parent.horizontalCenter<br /> }
 
MouseArea{<br /> id: drawerMouseArea<br /> anchors.fill:parent<br /> onClicked:{<br /> if (screen.state &amp;#34;DRAWER&amp;amp;#95;CLOSED&amp;amp;#34;){<br /> screen.state &amp;#61; &amp;#34;DRAWER&amp;amp;#95;OPEN&amp;amp;#34;<br /> }<br /> else if (screen.state &amp;#8220;DRAWER_OPEN&amp;amp;#8221;){<br /> screen.state = &amp;#8220;DRAWER_CLOSED&amp;amp;#8221;<br /> }<br /> }<br /> …<br /> }<br /> }<br /></code>
 
Ez az állapot egy sor konfigurációs beállítás, melyeket &quot;State&amp;quot;:http://doc.qt.nokia.com/4.7/qml-state.html elemeken keresztül deklarálunk. A különböző állapotok a ''state'' tulajdonsághoz kötődnek és kilistázhatjuk őket onnan. Az alkalmazásunkban két állapot, a ''DRAWER_CLOSED'' és a ''DRAWER_OPEN'' lesz. Az elemek konfigurációja a &quot;PropertyChanges&amp;quot;:http://doc.qt.nokia.com/4.7/qml-propertychanges.html elemben lesznek deklarálva. A DRAWER_OPEN állapotban 4 elem tulajdonsága fog megváltozni. A ''menuBar'' y tulajdonsága 0-ra fog változni. Hasonlóképpen, a ''textArea'' pozíciója lejjebb fog kerül, ha a ''DRAWER_OPEN'' állapot az aktív. A ''textArea'', a ''drawer'' és a ''drawer'' ikonja fog változáson keresztülmenni, hogy elérje a megfelelő állapotot.
 
<code><br /> states:[<br /> State {<br /> name: &amp;#8220;DRAWER_OPEN&amp;amp;#8221;<br /> PropertyChanges { target: menuBar; y: 0}<br /> PropertyChanges { target: textArea; y: partition + drawer.height}<br /> PropertyChanges { target: drawer; y: partition}<br /> PropertyChanges { target: arrowIcon; rotation: 180}<br /> },<br /> State {<br /> name: &amp;#8220;DRAWER_CLOSED&amp;amp;#8221;<br /> PropertyChanges { target: menuBar; y:-height; }<br /> PropertyChanges { target: textArea; y: drawer.height; height: screen.height &amp;#8211; drawer.height }<br /> PropertyChanges { target: drawer; y: 0 }<br /> PropertyChanges { target: arrowIcon; rotation: 0 }<br /> }<br /> ]<br /></code>
 
Az állapotváltozások azonnaliak, ám az átmenetnek ennél finomabbaknak kell lenniük. A &quot;Transition&amp;quot;:http://doc.qt.nokia.com/4.7/qml-transition.html elemben határozzuk meg a különböző állapotok közötti átmeneteket, amelyet ezután az elem ''transitions'' tulajdonságához rendelhetjük. A szövegszerkesztőnknek állapotátmenete lesz, akár ''DROWER_OPEN''-re akár ''DROWER_CLOSED''-ra módosul az állapota. Fontos, hogy az átmeneteknek rendelkezniük kell egy ''from'' (honnan) és egy ''to'' (hová) állapottal, de jelen esetben használhatunk csillagot * is, jelölve, hogy ez itt minden átmenetre vonatkozik. Az átmenetek során animációkat rendelhetünk a tulajdonság változásokhoz. A menüsorunk y : 0-ból y : x helyre ugrik, de ezt a mozgást leanimálhatjuk a &quot;NumberAnimation&amp;quot;:http://doc.qt.nokia.com/4.7/qml-numberanimation.html elem használatával. A cél elem tulajdonságait úgy állítjuk be, hogy annak mozgása egy meghatározott idő alatt, egy előre meghatározott csillapított görbe mentén animálódjon. Ez a csillapított görbe fogja szabályozni az animáció tulajdonságait az állapotváltozások között. Ez az ún. easing curve most az &quot;Easing.OutQuint&amp;quot;:http://doc.qt.nokia.com/4.7/qml-propertyanimation.html#easing.type-prop lesz, amely lelassítja az elem mozgását az animáció vége felé. Bővebb információért érdemes elolvasni a &quot;QML's Animation&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html c. leírást.
 
<code><br />transitions: [<br /> Transition {<br /> to: &amp;#8221;*&amp;#8221;<br /> NumberAnimation { target: textArea; properties: &amp;#8220;y, height&amp;amp;#8221;; duration: 100; easing.type:Easing.OutExpo }<br /> NumberAnimation { target: menuBar; properties: &amp;#8220;y&amp;amp;#8221;; duration: 100; easing.type: Easing.OutExpo }<br /> NumberAnimation { target: drawer; properties: &amp;#8220;y&amp;amp;#8221;; duration: 100; easing.type: Easing.OutExpo }<br /> }<br /> ]<br /></code>


==Szövegszerkesztőnk megjelenésének testreszabása==
Egy másik módja a tulajdonságváltozások animálásnak egy &quot;Behavior&amp;quot;:http://doc.qt.nokia.com/4.7/qml-behavior.html elem deklarálása. Egy átmenet csak állapotváltozások alatt működik, míg a ''Behavior'' hozzárendelhető egy egyszerű tulajdonságváltozáshoz is. A szövegszerkesztőnkben a nyílnak van egy ''NumberAnimation-ja'', mely leanimálja annak ''rotation'' tulajdonságát valahányszor megváltozik az.


===A Drawer Interface implementálása===
<code><br />In TextEditor.qml:


A szövegszerkesztőnk egyszerűen néz ki, most már a megjelenését is testre kellene szabnunk. A <span class="caps">QML</span>-t használva átmeneteket és animációkat deklarálhatunk a szövegszerkesztőnkhöz. Menüsorunk elfoglalja az ablak egyharmadát, így jó lenne, ha csak akkor jelenne meg, ha mi akarjuk.<br /> Hozzáadhatunk egy rajzoló interfészt, amely összecsukja illetve megjeleníti a menüsort klikkeléskor. Jelen esetben egy kis ''rectange''.t használtunk, mely reagál az egérkattintásokra. A ''drawer'', akárcsak az maga az alkalmazás, két állapottal rendelkezik, egy nyitottal és egy zárttal. A ''drawer'' elem egy kis magasságú rectangle, amihez kapcsolunk egy [ttp://doc.qt.nokia.com/4.7/qml-image.html Image] ''[doc.qt.nokia.com]'' elemet, egy kis nyíl ikont jelenítve meg középen a ''rectangle''-ön belül. A ''drawer'' meghatározza az program állapotát, ahogy a felhasználó rákattint a kis nyílra.
Behavior{<br /> NumberAnimation{property: &amp;#8220;rotation&amp;amp;#8221;;easing.type: Easing.OutExpo }<br /> }<br /></code>


Ez az állapot egy sor konfigurációs beállítás, melyeket [http://doc.qt.nokia.com/4.7/qml-state.html State] ''[doc.qt.nokia.com]'' elemeken keresztül deklarálunk. A különböző állapotok a ''state'' tulajdonsághoz kötődnek és kilistázhatjuk őket onnan. Az alkalmazásunkban két állapot, a ''<span class="caps">DRAWER</span>_CLOSED'' és a ''<span class="caps">DRAWER</span>_OPEN'' lesz. Az elemek konfigurációja a [http://doc.qt.nokia.com/4.7/qml-propertychanges.html PropertyChanges] ''[doc.qt.nokia.com]'' elemben lesznek deklarálva. A <span class="caps">DRAWER</span>_OPEN állapotban 4 elem tulajdonsága fog megváltozni. A ''menuBar'' y tulajdonsága 0-ra fog változni. Hasonlóképpen, a ''textArea'' pozíciója lejjebb fog kerül, ha a ''<span class="caps">DRAWER</span>_OPEN'' állapot az aktív. A ''textArea'', a ''drawer'' és a ''drawer'' ikonja fog változáson keresztülmenni, hogy elérje a megfelelő állapotot.
Térjünk vissza a komponenseinkhez az állapotokról és az animációkról megszerzett tudásunkkal, most már szebbé tehetjük azok megjelenését. A ''Button.qml''-ben a gomb lenyomásához ''color'' és ''scale'' tulajdonságokat adhatunk. A szín típusokat a &quot;ColorAnimation&amp;quot;:http://doc.qt.nokia.com/4.7/qml-coloranimation.html fogja animálni, míg a számokat a ''NumberAnimation''. Az alant látható ''on propertyName'' szintakszis hasznos lehet, ha csak egyetlen tulajdonságra akarunk utalni.


Az állapotváltozások azonnaliak, ám az átmenetnek ennél finomabbaknak kell lenniük. A [http://doc.qt.nokia.com/4.7/qml-transition.html Transition] ''[doc.qt.nokia.com]'' elemben határozzuk meg a különböző állapotok közötti átmeneteket, amelyet ezután az elem ''transitions'' tulajdonságához rendelhetjük. A szövegszerkesztőnknek állapotátmenete lesz, akár ''<span class="caps">DROWER</span>_OPEN''-re akár ''<span class="caps">DROWER</span>_CLOSED''-ra módosul az állapota. Fontos, hogy az átmeneteknek rendelkezniük kell egy ''from'' (honnan) és egy ''to'' (hová) állapottal, de jelen esetben használhatunk csillagot * is, jelölve, hogy ez itt minden átmenetre vonatkozik. Az átmenetek során animációkat rendelhetünk a tulajdonság változásokhoz. A menüsorunk y : 0-ból y : x helyre ugrik, de ezt a mozgást leanimálhatjuk a [http://doc.qt.nokia.com/4.7/qml-numberanimation.html NumberAnimation] ''[doc.qt.nokia.com]'' elem használatával. A cél elem tulajdonságait úgy állítjuk be, hogy annak mozgása egy meghatározott idő alatt, egy előre meghatározott csillapított görbe mentén animálódjon. Ez a csillapított görbe fogja szabályozni az animáció tulajdonságait az állapotváltozások között. Ez az ún. easing curve most az [http://doc.qt.nokia.com/4.7/qml-propertyanimation.html#easing.type-prop Easing.OutQuint] ''[doc.qt.nokia.com]'' lesz, amely lelassítja az elem mozgását az animáció vége felé. Bővebb információért érdemes elolvasni a [http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html <span class="caps">QML</span>’s Animation] ''[doc.qt.nokia.com]'' c. leírást.
<code><br />In Button.qml:<br />


Egy másik módja a tulajdonságváltozások animálásnak egy [http://doc.qt.nokia.com/4.7/qml-behavior.html Behavior] ''[doc.qt.nokia.com]'' elem deklarálása. Egy átmenet csak állapotváltozások alatt működik, míg a ''Behavior'' hozzárendelhető egy egyszerű tulajdonságváltozáshoz is. A szövegszerkesztőnkben a nyílnak van egy ''NumberAnimation-ja'', mely leanimálja annak ''rotation'' tulajdonságát valahányszor megváltozik az.
color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> Behavior on color { ColorAnimation{ duration: 55} }


Térjünk vissza a komponenseinkhez az állapotokról és az animációkról megszerzett tudásunkkal, most már szebbé tehetjük azok megjelenését. A ''Button.qml''-ben a gomb lenyomásához ''color'' és ''scale'' tulajdonságokat adhatunk. A szín típusokat a [http://doc.qt.nokia.com/4.7/qml-coloranimation.html ColorAnimation] ''[doc.qt.nokia.com]'' fogja animálni, míg a számokat a ''NumberAnimation''. Az alant látható ''on propertyName'' szintakszis hasznos lehet, ha csak egyetlen tulajdonságra akarunk utalni.
scale: buttonMouseArea.pressed ? 1.1 : 1.00<br /> Behavior on scale { NumberAnimation{ duration: 55} }<br /></code>


Még mutatósabbá tehetjük <span class="caps">QML</span> komponenseinket, ha olyan effektusokat adunk hozzájuk, mint a gradiens vagy az átlátszóság. Egy [http://doc.qt.nokia.com/4.7/qml-gradient.html Gradient] ''[doc.qt.nokia.com]'' elem deklarálásával felülírhatjuk az elem ''color'' tulajdonságát. A [http://doc.qt.nokia.com/4.7/qml-gradientstop.html GradientStop] ''[doc.qt.nokia.com]'' elemmel színeket is deklarálhatunk a gradiensünkön belül, melyet egy 0.0 és 1.0 közötti skálával adunk meg.
Még mutatósabbá tehetjük QML komponenseinket, ha olyan effektusokat adunk hozzájuk, mint a gradiens vagy az átlátszóság. Egy &quot;Gradient&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gradient.html elem deklarálásával felülírhatjuk az elem ''color'' tulajdonságát. A &quot;GradientStop&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gradientstop.html elemmel színeket is deklarálhatunk a gradiensünkön belül, melyet egy 0.0 és 1.0 közötti skálával adunk meg.
 
<code><br />In MenuBar.qml<br /> gradient: Gradient {<br /> GradientStop { position: 0.0; color: &amp;#8221;#8C8F8C&amp;amp;#8221; }<br /> GradientStop { position: 0.17; color: &amp;#8221;#6A6D6A&amp;amp;#8221; }<br /> GradientStop { position: 0.98;color: &amp;#8221;#3F3F3F&amp;amp;#8221; }<br /> GradientStop { position: 1.0; color: &amp;#8221;#0e1B20&amp;amp;#8221; }<br /> }<br /></code>


A menüsorunkon használjuk majd a gradienst egy színátmenet megjelenítésére. Az első szín 0.0-nál kezdődik, az utolsó pedig 1.0-nál végződik.
A menüsorunkon használjuk majd a gradienst egy színátmenet megjelenítésére. Az első szín 0.0-nál kezdődik, az utolsó pedig 1.0-nál végződik.


===Innen hova===
=== Innen hova ===
 
Ezzel befejeztük egy nagyon egyszerű szövegszerkesztő felhasználói felületét. Tovább haladva most már implementálhatjuk az alkalmazásunk logikáját a jól megszokott Qt és C++ segítségével. A <span class="caps">QML</span> szépen dolgozik, elválasztva előbbit az UI designtól.


[[Image:qml-texteditor4_texteditor.png|qml-texteditor4_texteditor]]
Ezzel befejeztük egy nagyon egyszerű szövegszerkesztő felhasználói felületét. Tovább haladva most már implementálhatjuk az alkalmazásunk logikáját a jól megszokott Qt és C++ segítségével. A QML szépen dolgozik, elválasztva előbbit az UI designtól.


==<span class="caps">QML</span> kibővítése Qt C++ használatával==
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor4_texteditor.png|qml-texteditor4_texteditor]]


Már megvan a szövegszerkesztőnk váza, most implementálhatjuk a funkciókat C++ -ban. A <span class="caps">QML</span>-t és a C++ -t együtt használva lehetőségünk van Qt-ben létrehozni a program logikáját. Beilleszthetünk egy <span class="caps">QML</span> kotextust a C++ alkalmazásunkban a [http://doc.qt.nokia.com/4.7/qtbinding.html Qt’s Declarative] ''[doc.qt.nokia.com]'' osztályok használatával és meg is jeleníthetjük a <span class="caps">QML</span> elemeket a Graphic Scene segítségével. Vagy exportálhatjuk a C++ kódunkat egy olyan pluginba, amit a qmlviewer olvasni tud. A programunk számára a mentés és betöltés funkciókat C++ -ban fogjuk implementálni és ezt exportáljuk egy pluginba. Így csak a <span class="caps">QML</span> fájlunkat kell betöltenünk, nem kell egy futtatható állományt elindítani.
== QML kibővítése Qt C++ használatával ==


===C++ osztályok megismertetése a <span class="caps">QML</span>-el===
Már megvan a szövegszerkesztőnk váza, most implementálhatjuk a funkciókat C++ -ban. A QML-t és a C++ -t együtt használva lehetőségünk van Qt-ben létrehozni a program logikáját. Beilleszthetünk egy QML kotextust a C++ alkalmazásunkban a &quot;Qt's Declarative&amp;quot;:http://doc.qt.nokia.com/4.7/qtbinding.html osztályok használatával és meg is jeleníthetjük a QML elemeket a Graphic Scene segítségével. Vagy exportálhatjuk a C++ kódunkat egy olyan pluginba, amit a qmlviewer olvasni tud. A programunk számára a mentés és betöltés funkciókat C++ -ban fogjuk implementálni és ezt exportáljuk egy pluginba. Így csak a QML fájlunkat kell betöltenünk, nem kell egy futtatható állományt elindítani.


Qt és C++ segítségével fogjuk implementálni a betöltés és mentés opciókat. A C++ osztályok és függvények használatához regisztrálni kell őket a <span class="caps">QML</span>-ben. Az osztály továbbá Qt pluginként kell fordítani és a <span class="caps">QML</span> fájlnak tudnia kell, hogy ez a plugin merre található.
=== C++ osztályok megismertetése a QML-el ===


Az alkalmazásunk számára a következő elemeket kell létrehoznunk:
Qt és C++ segítségével fogjuk implementálni a betöltés és mentés opciókat. A C++ osztályok és függvények használatához regisztrálni kell őket a QML-ben. Az osztály továbbá Qt pluginként kell fordítani és a QML fájlnak tudnia kell, hogy ez a plugin merre található.


# Directory osztály, mely a mappákhoz kötődő művelteket fogja végrehajtani
Az alkalmazásunk számára a következő elemeket kell létrehoznunk:<br /># Directory osztály, mely a mappákhoz kötődő művelteket fogja végrehajtani<br /># File osztály, ami egy &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html, amely fájlok listáját szimulálja egy mappában<br /># plugin osztály mely a QML kontextushoz fogja regisztálni az osztályt<br /># Qt project fájl, mely majd lefordítja a plugin-t<br /># qmldir, mely átadja a plugin helyét a qmlviewer számára
# File osztály, ami egy [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]'', amely fájlok listáját szimulálja egy mappában
# plugin osztály mely a <span class="caps">QML</span> kontextushoz fogja regisztálni az osztályt
# Qt project fájl, mely majd lefordítja a plugin-t
# qmldir, mely átadja a plugin helyét a qmlviewer számára


===Qt plugin létrehozása===
=== Qt plugin létrehozása ===


A plugin létrehozásához a következőket kell beállítanunk a Qt project fájlunkban. Első körben a szükséges sources, headers, és a Qt modules szerepelnek a hozzáadandók listájában. Az összes C++ kód és project fájl a ''filedialog'' könyvtárban lesz.
A plugin létrehozásához a következőket kell beállítanunk a Qt project fájlunkban. Első körben a szükséges sources, headers, és a Qt modules szerepelnek a hozzáadandók listájában. Az összes C++ kód és project fájl a ''filedialog'' könyvtárban lesz.


A ''declarative'' modullal fordítjuk a Qt-t és ''plugin_ként konfiguráljuk, amihez egy _lib'' sablonra lesz szükségünk. A szülő ''plugins'' mappába kell tennünk a lefordított plugint.
<code><br />In cppPlugins.pro:


===Egy osztály regisztrálása <span class="caps">QML</span>-ben===
TEMPLATE = lib<br /> CONFIG ''= qt plugin<br /> QT''= declarative


A ''DialogPlugin'' osztályunk a [http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html QDeclarativeExtensionPlugin] ''[doc.qt.nokia.com]'' egy alosztálya. Implementálnunk kell az örökölt függvényt, a [http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registerTypes()] ''[doc.qt.nokia.com]'' -t. A ''dialogPlugin.cpp'' a következőképpen néz ki:
DESTDIR ''= ../plugins<br /> OBJECTS_DIR = tmp<br /> MOC_DIR = tmp
<br /> TARGET = FileDialog
<br /> HEADERS''= directory.h  file.dialogPlugin.h


A ''registerTypes()'' függvény regisztrálja a ''<span class="caps">FILE</span>'' és ''<span class="caps">DIRECTORY</span>'' osztályainkat <span class="caps">QML</span>-ben. Ennek a függvénynek meg kell adni a sablonja nevét, a fő- és az alverziószámot, valamint természetesen az osztályunk nevét.
SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp<br /></code>


Exportálnunk kell a plugint a [http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2 Q_EXPORT_PLUGIN2] ''[doc.qt.nokia.com]'' makróval. Megjegyzendő, hogy a ''dialogPlugin.h'' fájlunkban ott van a [http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT Q_OBJECT] ''[doc.qt.nokia.com]'' makró az osztályunk tetején. Majd futassuk a ''qmkae''-t a project fájlunkon hogy legeneráljuk a szükséges meta-object kódot.
A ''declarative'' modullal fordítjuk a Qt-t és _plugin_ként konfiguráljuk, amihez egy ''lib'' sablonra lesz szükségünk. A szülő ''plugins'' mappába kell tennünk a lefordított plugint.


===<span class="caps">QML</span> tulajdonságok létrehozása C++ osztályban===
=== Egy osztály regisztrálása QML-ben ===


Létrehozhatunk <span class="caps">QML</span> elemeket és tulajdonságokat a C++ és a [http://doc.qt.nokia.com/4.7/metaobjects.html Qt’s Meta-Object System] ''[doc.qt.nokia.com]'' segítségével. Implementálhatjuk ezeket a tulajdonságokat slot-ok és signal-ok használatával, átadva ezeket a Qt-nek.
<code><br />In dialogPlugin.h:


A szövegszerkesztőnknek be kell tudnia tölteni, illetve elmenteni a fájlokat. Általában ezeket a funkciókat egy fájl dialogban valósítjuk meg. Szerencsére használhatjuk a [http://doc.qt.nokia.com/4.7/qdir.html QDir] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qfile.html QFile] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] ''[doc.qt.nokia.com]'' függvényeket, hogy implementáljuk a mappaolvasásokat és az input/output folyamatokat.
#include &lt;QtDeclarative/QDeclarativeExtensionPlugin&amp;gt;


A ''Directory'' class a Qt’s Meta-Object System-et használja, hogy regisztrálja a fájlkezelés megvalósításához szükséges tulajdonságokat. A ''Directory'' osztályt pluginként exportáltuk és <span class="caps">QML</span>-ben Directory elemként hivatkozhatunk rá. Az összes listázott tulajdonság a Q_PROPERTY makrót használja, amely egy <span class="caps">QML</span> tulajdonság.
class DialogPlugin : public QDeclarativeExtensionPlugin<br /> {<br /> Q_OBJECT


A [http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY Q_PROPERTY] ''[doc.qt.nokia.com]'' deklarál egy tulajdonságot, továbbá függvényeket olvas és ír a Qt’s Meta-Object System-ből/be. Például a [http://doc.qt.nokia.com/4.7/qstring.html QString] ''[doc.qt.nokia.com]'' ''filename'' tulajdonságát a ''filename()'' függvénnyel tudjuk olvasni, illetve a ''setFilename()'' függvénnyel írni. Továbbá egy signál, a ''filenameChanged()'', is rendelve van a ''filename'' tulajdonsághoz, amely minden esetben emittálásra kerül, ha a tulajdonság megváltozik. Az író és olvasó függvényeket ''public''-ként deklaráljuk a header fájlban.
public:<br /> void registerTypes(const char *uri);


Hasonlóképpen deklaráljuk a többi tulajdonságot, természetesen a használatuknak megfelelően. A ''filesCount'' tulajdonság az adott mappában lévő fájlok számát adja jelzi. A ''filename'' tulajdonság mindig az éppen kijelölt fájl nevét tárolja, a ''fileContent'' tulajdonságban pedig a betöltött/elmentett fájl tartalma tárolódik el.
};<br /></code>


A ''files'' lista tulajdonság egy lista a mappában lévő fájlokról. A ''Directory'' osztály azért implementáltuk, hogy kiszűrje az érvénytelen szöveges fájlokat, csak a .txt kiterjesztésűek lesznek érvényesek. Továbbá a [http://doc.qt.nokia.com/4.7/qlist.html QList] ''[doc.qt.nokia.com]'' [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty] ''[doc.qt.nokia.com]'' -ként delarálva C++ -ban lesz használható <span class="caps">QML</span>-ben. A sablon objektumot a [http://doc.qt.nokia.com/4.7/qobject.html QObject] ''[doc.qt.nokia.com]'' -től kell származtatni, így a File osztályt is. A ''Directory'' osztályban, a ''File'' objektumok listáját a ''QList_–ben tárolj _m_fileList'' néven.
A ''DialogPlugin'' osztályunk a &quot;QDeclarativeExtensionPlugin&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html egy alosztálya. Implementálnunk kell az örökölt függvényt, a &quot;registerTypes()&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes -t. A ''dialogPlugin.cpp'' a következőképpen néz ki:


Ez a tulajdonság ezután a ''Directory'' elem tulajdonságainak részeként használható <span class="caps">QML</span>-ben. Jegyezzük meg, hogy nem kell azonosító ''id'' tulajdonságot létrehoznunk a C++ kódunkban.
<code><br />DialogPlugin.cpp:


A sima C++ függvények is elérhetőek QML–ben. A betöltő és elmentő függvények C++ -ban kerültek implementálásra a [http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE Q_INVOKABLE] ''[doc.qt.nokia.com]'' makró felhasználásával. De _slot_–ként is deklarálhatjuk a függvényeket, melyek ezután elérhetőek lesznek <span class="caps">QML</span> –ben.
#include &quot;dialogPlugin.h&amp;quot;<br /> #include &quot;directory.h&amp;quot;<br /> #include &quot;file.h&amp;quot;<br /> #include &lt;QtDeclarative/qdeclarative.h&amp;gt;


A ''Directory'' osztálynak tudomást kell szereznie más objektumokról, ha megváltozik a mappa tartalma. Ezt a funkciót ''signal_–ok használatával oldjuk meg. Ahogy előzőleg említettük, a <span class="caps">QML</span> _signal_–oknak van egy hozzájuk tartozó végrehajtójuk, egy ún. _handler_–jük, amelyek neve megegyezik egy on prefixumot leszámítva. A signal neve _directoryChanged'' és ez mindig emittálásra kerül, ha a mappa frissül. A frissítés szimplán újra betölti a mappa tartalmát és frissíti a listában a mappa érvényes fájljait. Ezek a <span class="caps">QML</span> elemek észrevehetőek felhasználjuk az ''onDirectoryChanged'' handler-t.
void DialogPlugin::registerTypes(const char '''uri){
<br /> qmlRegisterType&amp;lt;Directory&amp;gt;(uri, 1, 0, &quot;Directory&amp;quot;);<br /> qmlRegisterType&amp;lt;File&amp;gt;(uri, 1, 0,&quot;File&amp;quot;);<br /> }
<br /> Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);<br /></code>
<br />A ''registerTypes()'' függvény regisztrálja a ''FILE'' és ''DIRECTORY'' osztályainkat QML-ben. Ennek a függvénynek meg kell adni a sablonja nevét, a fő- és az alverziószámot, valamint természetesen az osztályunk nevét.
<br />Exportálnunk kell a plugint a &quot;Q_EXPORT_PLUGIN2&amp;quot;:http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2 makróval. Megjegyzendő, hogy a ''dialogPlugin.h'' fájlunkban ott van a &quot;Q_OBJECT&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT makró az osztályunk tetején. Majd futassuk a ''qmkae''-t a project fájlunkon hogy legeneráljuk a szükséges meta-object kódot.
<br />h3. QML tulajdonságok létrehozása C++ osztályban
<br />Létrehozhatunk QML elemeket és tulajdonságokat a C++ és a &quot;Qt's Meta-Object System&amp;quot;:http://doc.qt.nokia.com/4.7/metaobjects.html segítségével. Implementálhatjuk ezeket a tulajdonságokat slot-ok és signal-ok használatával, átadva ezeket a Qt-nek.
<br />A szövegszerkesztőnknek be kell tudnia tölteni, illetve elmenteni a fájlokat. Általában ezeket a funkciókat egy fájl dialogban valósítjuk meg. Szerencsére használhatjuk a &quot;QDir&amp;quot;:http://doc.qt.nokia.com/4.7/qdir.html, &quot;QFile&amp;quot;:http://doc.qt.nokia.com/4.7/qfile.html, &quot;QTextStream&amp;quot;:http://doc.qt.nokia.com/4.7/qtextstream.html függvényeket, hogy implementáljuk a mappaolvasásokat és az input/output folyamatokat.
<br /><code><br />class Directory : public QObject{
<br /> Q_OBJECT
<br /> Q_PROPERTY(int filesCount READ filesCount CONSTANT)<br /> Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)<br /> Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)<br /> Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )
<br /> …<br /></code>
<br />A ''Directory'' class a Qt’s Meta-Object System-et használja, hogy regisztrálja a fájlkezelés megvalósításához szükséges tulajdonságokat. A ''Directory'' osztályt pluginként exportáltuk és QML-ben Directory elemként hivatkozhatunk rá. Az összes listázott tulajdonság a Q_PROPERTY makrót használja, amely egy QML tulajdonság.
<br />A &quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY deklarál egy tulajdonságot, továbbá függvényeket olvas és ír a Qt’s Meta-Object System-ből/be. Például a &quot;QString&amp;quot;:http://doc.qt.nokia.com/4.7/qstring.html ''filename'' tulajdonságát a ''filename()'' függvénnyel tudjuk olvasni, illetve a ''setFilename()'' függvénnyel írni. Továbbá egy signál, a ''filenameChanged()'', is rendelve van a ''filename'' tulajdonsághoz, amely minden esetben emittálásra kerül, ha a tulajdonság megváltozik. Az író és olvasó függvényeket ''public''-ként deklaráljuk a header fájlban.
<br />Hasonlóképpen deklaráljuk a többi tulajdonságot, természetesen a használatuknak megfelelően. A ''filesCount'' tulajdonság az adott mappában lévő fájlok számát adja jelzi. A ''filename'' tulajdonság mindig az éppen kijelölt fájl nevét tárolja, a ''fileContent'' tulajdonságban pedig a betöltött/elmentett fájl tartalma tárolódik el.
<br /><code><br /> Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )<br /></code>
<br />A ''files'' lista tulajdonság egy lista a mappában lévő fájlokról. A ''Directory'' osztály azért implementáltuk, hogy kiszűrje az érvénytelen szöveges fájlokat, csak a .txt kiterjesztésűek lesznek érvényesek. Továbbá a &quot;QList&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html -ként delarálva C++ -ban lesz használható QML-ben. A sablon objektumot a &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html -től kell származtatni, így a File osztályt is. A ''Directory'' osztályban, a ''File'' objektumok listáját a _QList_–ben tárolj ''m_fileList'' néven.
<br /><code><br />class File : public QObject{
<br /> Q_OBJECT<br /> Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
<br /> …<br /> };<br /></code>
<br />Ez a tulajdonság ezután a ''Directory'' elem tulajdonságainak részeként használható QML-ben. Jegyezzük meg, hogy nem kell azonosító ''id'' tulajdonságot létrehoznunk a C++ kódunkban.
<br /><code><br />Directory{<br /> id: directory
<br /> filesCount<br /> filename<br /> fileContent<br /> files
<br /> files[0].name<br /> }<br /></code>
<br />Mivel a QML Javascript szintaktikát és struktúrát használ, így végigfuthatunk a fájlok listáján és meg is kapjuk azok tulajdonságait. Hogy megkapjuk az első fájl név tulajdonságát, csak hívjuk meg a ''files[0].name'' függvényt.
<br />A sima C++ függvények is elérhetőek QML–ben. A betöltő és elmentő függvények C++ -ban kerültek implementálásra a &quot;Q_INVOKABLE&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE makró felhasználásával. De _slot_–ként is deklarálhatjuk a függvényeket, melyek ezután elérhetőek lesznek QML –ben.
<br /><code><br />In Directory.h:
<br /> Q_INVOKABLE void saveFile&amp;amp;#40;&amp;#41;;<br /> Q_INVOKABLE void loadFile&amp;amp;#40;&amp;#41;;<br /></code>
<br />A ''Directory'' osztálynak tudomást kell szereznie más objektumokról, ha megváltozik a mappa tartalma. Ezt a funkciót _signal_–ok használatával oldjuk meg. Ahogy előzőleg említettük, a QML _signal_–oknak van egy hozzájuk tartozó végrehajtójuk, egy ún. _handler_–jük, amelyek neve megegyezik egy on prefixumot leszámítva. A signal neve ''directoryChanged'' és ez mindig emittálásra kerül, ha a mappa frissül. A frissítés szimplán újra betölti a mappa tartalmát és frissíti a listában a mappa érvényes fájljait. Ezek a QML elemek észrevehetőek felhasználjuk az ''onDirectoryChanged'' handler-t.
<br />Érdemes tovább vizsgálni a list tulajdonságokat, ugyanis ún. callback-eket, visszahívásokat alkalmaznak, hogy elérjék és módosítsák a lista tartalmát. A list tulajdonság ''QDeclarativeListProperty&amp;lt;File&amp;gt;'' típusú, így akárhányszor hozzáférünk a listához, a hozzáférőnek egy ''QDeclarativeListProperty&amp;lt;File&amp;gt;''-al kell visszatérnie. A sablon típusnak, a _File_–nak ''QObject'' leszármaztatottnak kell lennie! Hogy létrehozzunk egy &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html -t , a lista hozzáférőjét és módosítóját függvény mutatókként át kell adni konstruktornak! A listának, esetünkben a _QList_–nek egy ''File'' mutató listának kell lennie! A ''QDeclarativeProperrty'' konstruktor konstruktorának és a Directory implementálása:
<br /><code><br /> QDeclarativeListProperty ( QObject''' object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0 )<br /> QDeclarativeListProperty&amp;lt;File&amp;gt;( this, &amp;m_fileList, &amp;appendFiles, &amp;filesSize, &amp;fileAt, &amp;clearFilesPtr );<br /></code>


Érdemes tovább vizsgálni a list tulajdonságokat, ugyanis ún. callback-eket, visszahívásokat alkalmaznak, hogy elérjék és módosítsák a lista tartalmát. A list tulajdonság ''QDeclarativeListProperty&lt;File&gt;'' típusú, így akárhányszor hozzáférünk a listához, a hozzáférőnek egy ''QDeclarativeListProperty&lt;File&gt;''-al kell visszatérnie. A sablon típusnak, a ''File_–nak _QObject'' leszármaztatottnak kell lennie! Hogy létrehozzunk egy [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty] ''[doc.qt.nokia.com]'' -t , a lista hozzáférőjét és módosítóját függvény mutatókként át kell adni konstruktornak! A listának, esetünkben a ''QList_–nek egy _File'' mutató listának kell lennie! A ''QDeclarativeProperrty'' konstruktor konstruktorának és a Directory implementálása:
A konstruktor átadja a mutatókat a függényekneknek, amik csatolják, megszámolják a elemeinek számát vagy kiürítik a listát, illetve visszanyerik az elemeit az indexek segítségével. Csak az append (csatoló) függvény megbízott. Megjegyzendő, hogy a függvény mutatóknak meg kell egyezniük az &quot;AppendFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AppendFunction-typedef, a &quot;CountFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#CountFunction-typedef, az &quot;AtFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AtFunction-typedef, és a &quot;ClearFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef definícióival!


A konstruktor átadja a mutatókat a függényekneknek, amik csatolják, megszámolják a elemeinek számát vagy kiürítik a listát, illetve visszanyerik az elemeit az indexek segítségével. Csak az append (csatoló) függvény megbízott. Megjegyzendő, hogy a függvény mutatóknak meg kell egyezniük az [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AppendFunction-typedef AppendFunction] ''[doc.qt.nokia.com]'', a [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#CountFunction-typedef CountFunction] ''[doc.qt.nokia.com]'', az [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AtFunction-typedef AtFunction] ''[doc.qt.nokia.com]'', és a [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef ClearFunction] ''[doc.qt.nokia.com]'' definícióival!
<code><br />void appendFiles(QDeclarativeListProperty&amp;lt;File&amp;gt; * property, File * file)<br /> File* fileAt(QDeclarativeListProperty&amp;lt;File&amp;gt; * property, int index)<br /> int filesSize(QDeclarativeListProperty&amp;lt;File&amp;gt; * property)<br /> void clearFilesPtr(QDeclarativeListProperty&amp;lt;File&amp;gt; *property)<br /></code>


Hogy egyszerűbbé tegyük a dialógunkat, a ''Directory'' osztály kiszűr minden fájlt, amely nem .txt kiterjesztésű és csak azokat jeleníti meg, amelyek azok. Sőt, ez az implementáció arról is gondoskodik, hogy az elmentett fájljaink megfelelő (.txt) kiterjesztést kapjanak. A ''Directory'' a [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] ''[doc.qt.nokia.com]'' függvényt használja, hogy kiolvasson a fájlból, illetve hogy írjon bele.
Hogy egyszerűbbé tegyük a dialógunkat, a ''Directory'' osztály kiszűr minden fájlt, amely nem .txt kiterjesztésű és csak azokat jeleníti meg, amelyek azok. Sőt, ez az implementáció arról is gondoskodik, hogy az elmentett fájljaink megfelelő (.txt) kiterjesztést kapjanak. A ''Directory'' a &quot;QTextStream&amp;quot;:http://doc.qt.nokia.com/4.7/qtextstream.html függvényt használja, hogy kiolvasson a fájlból, illetve hogy írjon bele.


A ''Directory'' elemünkkel tehát visszanyerhetjük a fájljaink listáját, azok nevét és tartalmát stringként, megtudhatjuk, hogy hány fájl van az adott mappában, és valahányszor megváltozik annak tartalma, arról értesítést kaphatunk.
A ''Directory'' elemünkkel tehát visszanyerhetjük a fájljaink listáját, azok nevét és tartalmát stringként, megtudhatjuk, hogy hány fájl van az adott mappában, és valahányszor megváltozik annak tartalma, arról értesítést kaphatunk.


Ahhoz hogy létrehozzuk a ''plugin_–t, futassuk a _qmake_–t a _cppPlugins.pro'' project fájlon, aztán futassuk a ''make'' parancsot hogy lefordítsuk és áthelyezzük a pluginunkkat a plugins könyvtára.
Ahhoz hogy létrehozzuk a _plugin_–t, futassuk a _qmake_–t a ''cppPlugins.pro'' project fájlon, aztán futassuk a ''make'' parancsot hogy lefordítsuk és áthelyezzük a pluginunkkat a plugins könyvtára.
 
=== Plugin importálása QML-ben ===
 
A ''qmlviewer'' azokat a fájlokat importálja, amelyek az alkalmazásunkkal egy mappában van. De létrehozhatunk egy ''qmldir'' fájlt is, amely tartalmazza majd, hogy merre találhatóak a QML fájljaink, melyeket importálni szeretnénk. A ''qmldir'' fájl tovább tartalmazhatta más pluginok és ún. ''resources'', eszközök helyét.
 
<code><br />In qmldir:
 
Button ./Button.qml<br /> FileDialog ./FileDialog.qml<br /> TextArea ./TextArea.qml<br /> TextEditor ./TextEditor.qml<br /> EditMenu ./EditMenu.qml


===Plugin importálása <span class="caps">QML</span>-ben===
plugin FileDialog plugins<br /></code>


A ''qmlviewer'' azokat a fájlokat importálja, amelyek az alkalmazásunkkal egy mappában van. De létrehozhatunk egy ''qmldir'' fájlt is, amely tartalmazza majd, hogy merre találhatóak a <span class="caps">QML</span> fájljaink, melyeket importálni szeretnénk. A ''qmldir'' fájl tovább tartalmazhatta más pluginok és ún. ''resources'', eszközök helyét.
A ''plugin'', melyet fentebb létrehoztunk ''FileDialog'' névvel rendelkezik, ahogy azt a ''TARGET'' mezőben is jeleztük a project fájlunkban. A lefordított plugin a plugins könyvtárban található.


A ''plugin'', melyet fentebb létrehoztunk ''FileDialog'' névvel rendelkezik, ahogy azt a ''<span class="caps">TARGET</span>'' mezőben is jeleztük a project fájlunkban. A lefordított plugin a plugins könyvtárban található.
=== Egy File Dialog integrálása a File Menu–be ===


===Egy File Dialog integrálása a File Menu–be===
A _FileMenu_–ünknek egy _FileDialog_–ot kell elemet megjelenítenie, amely tartalmazza a könyvtár, .txt kiterjesztésű, fájljait és lehetővé teszi a felhasználó számára, hogy kiválassza a megnyitni kívánt fájlt. Továbbá el kell helyeznünk benne a mentés, a megnyitás és az új gombokat, hogy azok elvégezhessék a kívánt műveletet. A ''FileMenu'' tartalmazni fog egy szerkeszthető szövegmezőt is, ahová a felhasználó begépelhet egy fájlnevet. A ''Directory'' elemet a _FileMenu.qml_–ben használjuk fel, és ez majd értesít minket, ha megváltozott a könyvtár tartalma. Ezt az ''signal''-t az ''onDirectoryChanged'' handler fogja számunkra eljuttatni.


A ''FileMenu_–ünknek egy _FileDialog_–ot kell elemet megjelenítenie, amely tartalmazza a könyvtár, .txt kiterjesztésű, fájljait és lehetővé teszi a felhasználó számára, hogy kiválassza a megnyitni kívánt fájlt. Továbbá el kell helyeznünk benne a mentés, a megnyitás és az új gombokat, hogy azok elvégezhessék a kívánt műveletet. A _FileMenu'' tartalmazni fog egy szerkeszthető szövegmezőt is, ahová a felhasználó begépelhet egy fájlnevet. A ''Directory'' elemet a ''FileMenu.qml_–ben használjuk fel, és ez majd értesít minket, ha megváltozott a könyvtár tartalma. Ezt az _signal''-t az ''onDirectoryChanged'' handler fogja számunkra eljuttatni.
<code><br />In FileMenu.qml:
 
Directory{<br /> id:directory<br /> filename: textInput.text<br /> onDirectoryChanged: fileDialog.notifyRefresh()<br /> }<br /></code>


Alkalmazásunk egyszerűségét megőrizendő, a fájl dialógunk csak a szükséges fájlokat fogja megjeleníteni, amelyek .txt kiterjesztésűek.
Alkalmazásunk egyszerűségét megőrizendő, a fájl dialógunk csak a szükséges fájlokat fogja megjeleníteni, amelyek .txt kiterjesztésűek.


Ahogy fentebb írtuk, a ''FileDialog'' elem meg fogja jeleníteni a mappa számunkra releváns tartalmát, amelyet a files tulajdonság kiolvasásával fogunk elérni. A fájlokat egy [http://doc.qt.nokia.com/4.7/qml-gridview.html GridView] ''[doc.qt.nokia.com]'' modellt használó elem fogja megjeleníteni rácsos elrendezésben egy ''delegate''-nek megfelelően. A ''delegate'' fogja lekezelni a modellünk megjelenését és a fájl dialógunk létrehoz majd egy ''grid''-et, egy rácsot, középre igazítva benne a szöveget. Egy fájlnévre kattintva egy rectangle jelenik meg, kijelölve a fájlnevet. Akárhányszor emittálásra kerül a ''notifyRefresh'' signal, a ''FileDialog'' újratölti majd a könyvtár tartalmát.
<code><br />In FileDialog.qml:
 
signal notifyRefresh()<br /> onNotifyRefresh: dirView.model = directory.files<br /></code>
 
Ahogy fentebb írtuk, a ''FileDialog'' elem meg fogja jeleníteni a mappa számunkra releváns tartalmát, amelyet a files tulajdonság kiolvasásával fogunk elérni. A fájlokat egy &quot;GridView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gridview.html modellt használó elem fogja megjeleníteni rácsos elrendezésben egy ''delegate''-nek megfelelően. A ''delegate'' fogja lekezelni a modellünk megjelenését és a fájl dialógunk létrehoz majd egy ''grid''-et, egy rácsot, középre igazítva benne a szöveget. Egy fájlnévre kattintva egy rectangle jelenik meg, kijelölve a fájlnevet. Akárhányszor emittálásra kerül a ''notifyRefresh'' signal, a ''FileDialog'' újratölti majd a könyvtár tartalmát.


Most már a ''FileMenu''-nk kapcsolódhat a megfelelő műveletekhez. A ''saveButton'' továbbítja majd a ''TextEdit''-ből a szöveget a ''Directory'' ''filecontent'' tulajdonságában, majd átmásolja a fájl nevét a szerkeszthető szövegmezőből. Végül pedig a gomb meghívja a ''saveFile()'' függvényt, amely elmenti a fájlunkat. A ''loadButton'' hasonló végrehajtással rendelkezik. A ''New'' gomb megnyomására pedig kitörlődik a ''TextEdit'' tartalma. Továbbá a ''EditMenu'' gombjai kapcsolónak a ''TextEdit'' függvényeihez, hogy képesek legyenek a ''copy'', ''paste'' funkció betöltésére, valamint hogy a kijelölhessük a szöveget.
<code><br />In FileMenu.qml:


[[Image:qml-texteditor5_filemenu.png|qml-texteditor5_filemenu]]
Button{<br /> id: newButton<br /> label: &quot;New&amp;quot;<br /> onButtonClick:{<br /> textArea.textContent = &quot;&quot;<br /> }<br /> }<br /> Button{<br /> id: loadButton<br /> label: &quot;Load&amp;quot;<br /> onButtonClick:{<br /> directory.filename = textInput.text<br /> directory.loadFile&amp;amp;#40;&amp;#41;<br /> textArea.textContent = directory.fileContent<br /> }<br /> }<br /> Button{<br /> id: saveButton<br /> label: &quot;Save&amp;quot;<br /> onButtonClick:{<br /> directory.fileContent = textArea.textContent<br /> directory.filename = textInput.text<br /> directory.saveFile&amp;amp;#40;&amp;#41;<br /> }<br /> }<br /> Button{<br /> id: exitButton<br /> label: &quot;Exit&amp;quot;<br /> onButtonClick:{<br /> Qt.quit()<br /> }<br /> }<br /></code>


===A szövegszerkesztőnk befejezése===
Most már a ''FileMenu''-nk kapcsolódhat a megfelelő műveletekhez. A ''saveButton'' továbbítja majd a ''TextEdit''-ből a szöveget a ''Directory'' ''filecontent'' tulajdonságában, majd átmásolja a fájl nevét a szerkeszthető szövegmezőből. Végül pedig a gomb meghívja a ''saveFile&amp;amp;#40;&amp;#41;'' függvényt, amely elmenti a fájlunkat. A ''loadButton'' hasonló végrehajtással rendelkezik. A ''New'' gomb megnyomására pedig kitörlődik a ''TextEdit'' tartalma. Továbbá a ''EditMenu'' gombjai kapcsolónak a ''TextEdit'' függvényeihez, hogy képesek legyenek a ''copy'', ''paste'' funkció betöltésére, valamint hogy a kijelölhessük a szöveget.


[[Image:qml-texteditor5_newfile.png|qml-texteditor5_newfile]]
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_filemenu.png|qml-texteditor5_filemenu]]


Összegezve, a kis alkalmazásunk képes az alapvető szövegszerkesztési funkciók ellátása, így képes elmenteni, megnyitni, illetve módosítani bármilyen .txt kiterjesztésű fájlt.
=== A szövegszerkesztőnk befejezése ===


Köszönjük, hogy elolvasta eme ismertetőt, reméljük hasznosnak bizonyult és remek <span class="caps">QML</span> alkalmazások fognak születni az itt elolvasott tudás birtokában!
p=. [[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_newfile.png|qml-texteditor5_newfile]]


Have a nice day! <span class="smiley">:)</span>
Összegezve, a kis alkalmazásunk képes az alapvető szövegszerkesztési funkciók ellátása, így képes elmenteni, megnyitni, illetve módosítani bármilyen .txt kiterjesztésű fájlt.


===Categories:===
Köszönjük, hogy elolvasta eme ismertetőt, reméljük hasznosnak bizonyult és remek QML alkalmazások fognak születni az itt elolvasott tudás birtokában!


* [[:Category:Developing with Qt|Developing_with_Qt]]
Have a nice day! :)
** [[:Category:Developing with Qt::Qt-Quick|Qt Quick]]
* [[:Category:Developing with Qt::Qt-Quick::QML|QML]]
** [[:Category:Developing with Qt::Qt-Quick::QML::Hungarian|Hungarian]]

Revision as of 10:04, 24 February 2015

Az alant olvasható leírás rev. 0.2 verziót visel, ezzel is jelezve, hogy a jövőben szeretnénk még csiszolni rajta :)

Bevezetés a QML programozásba

Üdvözöllek a QML világában, mely egy UI leíró nyelv! Ebben a bevezetőben egy egyszerű szövegszerkesztő alkalmazást fogunk létrehozni a QML segítségével. Ezen útmutató olvasása után már készen fogsz állni, hogy kifejleszd a saját alkalmazásaidat a QML és a Qt keretrendszer segítségével.

Felhasználói felület létrehozása QML nyelven

Példa alkalmazásunk egy egyszerű szövegszerkesztő lesz, amely alkalmas egyszerű szövegfájlok megnyitására illetve alapvető szerkesztési műveletek elvégzésére. A leírás első részében a program felhasználói felületét tervezzük meg a QML leírónyelv segítségével. A második részben a fájlok betöltése és elmentése lesz implementálva C++ nyelven. A Qt "Meta-Object System&quot;:http://doc.qt.nokia.com/4.7/metaobjects.html segítségével a C++ függvényeket olyan tulajdonságokként ábrázolhatjuk, melyeket a QML elemek is képesek használni. QML és Qt C++ használatával hatékonyan szétválaszthatjuk a kezelői felület felépítését és a program logikáját.

p=. qml-texteditor5_editmenu.png

QML példakódunk futtatásához csupán adjuk meg argumentumként a "qmlviewer&quot;:http://doc.qt.nokia.com/4.7/qmlviewer.html programnak a QML fájlunkat. Ezen útmutató C++ része feltételezi, hogy az olvasó le tud fordítani egy Qt-ban írt programot.

Az útmutató fejezetei:

  1. Nyomógomb és menü létrehozása
  2. Menüsáv implementálása
  3. Szövegszerkesztő létrehozása
  4. A szövegszerkesztő küllemének megteremtése
  5. QML kibővítése Qt C++ segítségével

Nyomógomb és menü létrehozása

Alapelemek – a gomb

Szövegszerkesztőnket egy gomb létrehozásával kezdjük. Ha funkcionálisan nézzük, akkor a gomb rendelkezik egy egér számára érzékeny területtel és egy felirattal. A gombok akkor hajtják végre a feladatokat, ha a felhasználó rájuk klikkel. QML-ben a legalapvetőbb vizuális elem a "Rectangle&quot;:http://doc.qt.nokia.com/4.7/qml-rectangle.html. A Rectangle elem tulajdonságokkal rendelkezik, hogy beállíthassunk az elem megjelenését és elhelyezkedését.

Először az import Qt 4.7 sor engedélyezi a qmlviewer eszköznek, hogy betöltse azokat a QML elemeket, melyeket később használni fogunk. Ennek a sornak szerepelnie kell minden QML fájlban! Figyeljük meg, hogy a Qt modulok verzióját az import utasítás már tartalmazza!

Ez az egyszerű Rectangle rendelkezik egy egyedi azonosítóval, simplebutton, amely az id tulajdonsághoz kötődik. A Rectangle elem tulajdonságaihoz értékeket rendelünk a tulajdonság kilistázásakor, ekkor a kettőspont után áll az érték. A mintakódban a grey (szürke) színt rendeltük a Rectangle color tulajdonságához. Hasonlóan járunk el a Rectangle width és height tulajdonságainak esetében.

A Text elem egy nem szerkeszthető szövegmező. Nevezzük el buttonlabel-ként ezt a Text elemet. A szövegmezőben lévő szöveget a Text tulajdonság segítségével módosíthatjuk. A feliratot a Rectangle tárolja és hogy középre igazítsuk, a Text elem anchors tuljadonságát a szülőjéhez rendeljük, ami itt most a simplebutton. Az anchor-ok (kapcsok) olykor más elemek anchor-jaihoz kötődnek, hogy leegyszerűsítsék az elrendezést.

Most mentsük el a kódot SimpleButton.qml néven. Futtassuk a qmlviewer-t a fájlunkat argumentumként megadva. Egy szürke téglalapot fogunk látni, benne a feliratunkkal.

A gombnyomás funkciójának implementálására használhatjuk a QML eseménykezelő metódusát. A QML esemény kezelése nagyon hasonlít a Qt signal and slot mechanizmusára. Példánkban az onClicked handlerben kezeljük le az eseményt.

<br />Rectangle{<br /> id:simplebutton<br /> 

MouseArea{<br /> id: buttonMouseArea

anchors.fill: parent //anchor all sides of the mouse area to the rectangle&amp;amp;#8217;s anchors<br /> //onClicked handles valid mouse button clicks<br /> onClicked: console.log(buttonLabel.text + &amp;#8221; clicked&amp;amp;#8221; )<br /> }<br /> }<br />

Létrehozunk egy "MouseArea&quot;:qml-mousearea.html elemet a simplebutton-on belül. A MouseArea elem meghatározza azt az interaktív területet, ahol érzékelni fogjuk majd az egérkattintásokat. Gombunk esetében az egész MouseArea-t a szülőjéhez kapcsoljuk, ami most a simplebutton. Az anchors.fill szintaktika is egy mód, hogy elérjünk egy bizonyos tulajdonságot (fill), az anchors tulajdonságokon belül. A QML kapocs alapú vázat használ, ahol az egyes elemek más elemekhez kapcsolhatók, így robosztus vázakat hozhatunk létre.

A MouseArea-nak sok jelfeldolgozója ún. handler-je van, amelyek a meghatározott MouseArea határain belül történő egér események hatására hívódnak meg. Ezek közül az egyik az onClicked, amely a gomb megnyomásakor hívódik meg, alapértelmezésben ez itt a bal gomb. Műveleteket is köthetünk az onClicked handler-jéhez. A példánkban, a console.log() szöveget ír a kimenetre, akárhányszor ráklikkelünk a MouseArea területére. A console.log() függvény egy nagyon hasznos eszköz hibakeresésre, segítségével bármit kiírathatunk a konzolba.

A SimpleButton.qml kódja már képes arra, hogy megjelenítsen egy gombot és szöveget írjon képernyőre klikkeléskor.

<br />Rectangle {<br /> id: button<br /> 

property color buttonColor: &amp;#8220;lightblue&amp;amp;#8221;<br /> property color onHoverColor: &amp;#8220;gold&amp;amp;#8221;<br /> property color borderColor: &amp;#8220;white&amp;amp;#8221;

signal buttonClick()<br /> onButtonClick: {<br /> console.log(buttonLabel.text + &amp;#8221; clicked&amp;amp;#8221; )<br /> }

MouseArea{<br /> id: buttonMouseArea<br /> onClicked: buttonClick()<br /> hoverEnabled: true<br /> onEntered: parent.border.color = onHoverColor<br /> onExited: parent.border.color = borderColor<br /> }

//determines the color of the button by using the conditional operator<br /> color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> }<br />

Egy teljesen működő gomb a Button.qml fájlban található. Ebben a leírásban szereplő kódrészlet mellőz néhány részletet, mert azokat már vagy tárgyaltuk az előzőekben vagy irreleváns a kód értelmezése szempontjából.

Egyedi tulajdonságokat a tulajdonság típus név szintaktikával tudunk deklarálni. Kódunkban a color típusú buttonColor tulajdonsághoz a „lightblue”-t rendeljük. A buttonColor később lesz használva egy kiegészítő műveletben, hogy meghatározzuk a gomb kitöltési színét. Megemlítendő, hogy értékadás az = jellel is történhet a kettőspont helyett. Az egyedi tulajdonságok lehetővé teszik, hogy belső elemek kívülről hozzáférhetőek legyenek, a Rectangle hatósugarán kívül is. A QML-nek megvannak a maga alaptípusai, mint az int, a real, a string, vagy az általános konténertípus a variant.

Színeket hozzáadva az onEntered és az onExited jelkezelőkhöz, a gomb szegélye sárgává fog válni, amikor az egér a gomb fölé ér, és visszaáll az eredeti színre, ha a kurzor távozik a területéről.

Egy buttonClick() signalt is deklarálunk a Button.qml-ben a signal neve elé tett signal kulcsszóval. Minden signal-nak automatikusan létrejön a handler-je, „on”-al kezdődő nevekkel. Így értelemszerűen az onButtonClicked a buttonClicked handler-je. Ezután az onButtonClicked-edet összekötjük egy művelettel, hogy az megfelelően működhessen. A mi gomb-példánkban egérkattintásra az onClicked handlerje szimplán meg fogja hívni az onButtonClick függvényt, mely megjelenít egy szöveget. Az onButtonClick lehetővé teszi, hogy külső objektumok könnyedén hozzáférjenek a Button klikkelési területéhez. Például egy elemnek több MouseArea deklarációja is van és a ButtonClick signal jobban el tudja végezni a megkülönböztetést a több MouseArea handler között.

Most már megvan az alaptudásunk, hogy implementáljunk olyan elemeket QML-ben, melyek képesek lekezelni alap egérműveleteket. Hozzunk létre egy Text feliratot egy Rectangle-ben, szabjuk testre a tulajdonságait és implementáljuk az egérmozgásokra válaszoló műveleteit. Ez az alapelv, hogy elemeket hozunk létre más elemeken belül, végig fogja kísérni a szövegszerkesztő programunkat. Ám ez a gomb haszontalan, amíg nem műveletek ellátására szolgáló komponensként használjuk. A következő részben létrehozunk egy menüt, mely több ilyen gombot is tartalmazni fog.

p=. qml-texteditor1_button

Menü létrehozása

Eddig a részig áttekintettük, hogyan hozzunk létre elemeket és kössünk hozzájuk műveleteket egy QML fájlon belül. Ebben a fejezetben megtanuljuk, hogyan importáljunk QML elemeket és hogyan használjuk fel ezeket a komponenseket újra, hogy újabb komponenseket hozzunk létre.

Egy menü egy lista tartalmát jeleníti meg, mindegyik elemnek megvan a lehetősége, hogy végrehajtson egy feladatot. QML-ben sokféleképpen hozhatunk létre menüket. Először egy, a gombokat tartalmazó menüt fogunk készíteni, melyek különböző műveleteket hajtanak majd végre. A menü kódja a FileMenu.qml-ben található.

<br />import Qt 4.7 import the main Qt QML module<br />import &amp;#8220;folderName&amp;amp;#8221; import the contents of the folder<br />import &amp;#8220;script.js&amp;amp;#8221; as Script import a Javascript file and name it as Script<br />

A fent használt szintaktika megmutatja, hogyan használjuk az import parancsot. Olyan JavaScript vagy QML fájlok használatakor van szükségünk rá, melyek nem ugyanabban a mappában vannak. Mivel a Button.qml ugyanabban a mappában van, mint a FileMenu.qml, így nem kell importálnunk a button.qml-t, hogy használhassuk. Azonnal létrehozhatunk egy Button elemet a Button { } függvényt deklarálva, hasonlóan a Rectangle { }-hoz.

<br />In FileMenu.qml:

Row{<br /> anchors.centerIn: parent<br /> spacing: parent.width/6

Button{<br /> id: loadButton<br /> buttonColor: &amp;#8220;lightgrey&amp;amp;#8221;<br /> label: &amp;#8220;Load&amp;amp;#8221;<br /> }<br /> Button{<br /> buttonColor: &amp;#8220;grey&amp;amp;#8221;<br /> id: saveButton<br /> label: &amp;#8220;Save&amp;amp;#8221;<br /> }<br /> Button{<br /> id: exitButton<br /> label: &amp;#8220;Exit&amp;amp;#8221;<br /> buttonColor: &amp;#8220;darkgrey&amp;amp;#8221;

onButtonClick: Qt.quit()<br /> }<br /> }<br />

A FileMenu.qml-ben deklaráljunk egy Row elemen belül 3 Button elemet. A Row egy pozícionáló elem, ami egy vízszintes sorban rendezi el a gyerekeit.

A Button deklarációja a Button.qml-ben van, ami ugyan az a Button.qml, amit mi az előző fejezetben használtunk. Új tulajdonságkötéseket deklarálhatunk az újonnan létrehozott gombokban, hatékonyan felülírva a Button.qml-ben beállított tulajdonságokat. Az Exit gomb megnyomásának hatására ki fog lépni a program és bezárja az ablakot. Gondoljuk végig, hogy a Button.qml-ben lévő onButtonClick signal handler is meg lesz hívva az exitButtonban lévő onButtonClick handleren kívül.
p=. qml-texteditor1_filemenu
A Row.t a Rectangle.en belül deklaráljuk, ezzel létrehozunk egy _Rectangle
tárolót a gombok sorának. A második Rectangle létrehozása a menü gombjainak egy sorban történő tárolására indirekt módon történik. A Edit menü nagyon hasonló ebben a fázisban. Ez a menu is 3 gombot fog tartalmazni a következő nevekkel: Copy, Paste, Select All.

p=. qml-texteditor1_editmenu

Most, hogy tudjuk hogyan importáljuk és szabjuk testre az előzőleg már létrehozott komponenseiket, már elkészíthetjük a menüsorunkat, mely a menüpontok kiválasztására szolgáló gombokból fog állni. Nézzük meg, hogyan rendszerezzük adatainkat a QML-ben!

A menüsor implementálása

Szövegszerkesztőnknek meg kell tudni jelenítenie a menüket a menüsorból. A menüsoron kiválaszthatja a felhasználó, hogy melyik menüt jelenítse meg a program. A menük közötti váltásból következik, hogy az egy sorba rendezésnél bonyolultabb struktúrával fog rendelkezni a menünk.

Adatmodellek (Data Models) és adatnézetek (Data Views) használata:

Különböző "Data View&quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html -kal rendelkezik a QML a "Data Model&quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html -ek megjelenítésére. Menüsorunk listaként fogja megjeleníteni a kiválasztott menüt egy fejléccel, ahol többi menü nevét soroljuk fel vízszintesen. A menülistánk egy "VisualItemModel&quot;:http://doc.qt.nokia.com/4.7/qml-visualitemmodel.html -ben lesz deklarálva, mely olyan elemeket tartalmaz, melyek már eleve rendelkeznek valamilyen megjelenéssel, mint például egy Rectangle vagy egy importált UI elem. Más modell típusoknak, mint például a "ListModel&quot;:http://doc.qt.nokia.com/4.7/qml-listmodel.html, egy megbízott kell, hogy megjelenítse az adatait. Két vizuális elemet deklarálunk a menuListModel-ünkben, a FileMenu-t és az EditMenu-t. Testreszabjuk a két menüt és megjelenítjük őket a "ListView&quot;:http://doc.qt.nokia.com/4.7/qml-listview.html -val. A Menubar.qml fájlunk tartalmazza a QML deklarálását és egy egyszerű szerkesztői menüt, melyet az EditMenu.qml-ben hoztunk létre.

<br />VisualItemModel{<br /> id: menuListModel<br /> FileMenu{<br /> width: menuListView.width<br /> height: menuBar.height<br /> color: fileColor<br /> }<br /> EditMenu{<br /> color: editColor<br /> width: menuListView.width<br /> height: menuBar.height<br /> }<br /> }<br />

A ListView elem egy megbízotton keresztül fogja megjeleníteni a modellünket. A megbízott lehet hogy meghatározza, hogy például egy sorban vagy egy hálóban jelenítse meg az elemeket. A mi menuListModel-ünknek már vannak látható elemei, így nekünk nem kell megbízottat deklarálnunk hozzá.

<br />ListView{<br /> id: menuListView

//Anchors are set to react to window anchors<br /> anchors.fill:parent<br /> anchors.bottom: parent.bottom<br /> width:parent.width<br /> height: parent.height

//the model contains the data<br /> model: menuListModel

//control the movement of the menu switching<br /> snapMode: ListView.SnapOneItem<br /> orientation: ListView.Horizontal<br /> boundsBehavior: Flickable.StopAtBounds<br /> flickDeceleration: 5000<br /> highlightFollowsCurrentItem: true<br /> highlightMoveDuration:240<br /> highlightRangeMode: ListView.StrictlyEnforceRange<br /> }<br />

A "Flickable&quot;:http://doc.qt.nokia.com/4.7/qml-flickable.html -ből örököljük a ListView-unkat, ezzel a listánk reagálhat majd az egérmozdulatokra és más gesztusokra. Fenti kódunk utolsó része beállítja a Flickable tuljadonságait, hogy létrehozzunk a nézetünk kívánt kinetikus mozgását. A highLightMovementDuration tuljadonság meghatározza, hogy meddig tartson a kinetikus transzformáció. Egy nagyobb highLightMovementDuration érték lassabb menüváltást fog eredményezni. A ListView a modell minden egyes elemét egy indexszel látja el a deklarálásuk sorrendjében, melyeket ezeken az indexeken keresztül érhetünk el. A currentIndex értékének megváltoztatásával a ListView egy másik elemét jelöljük ki. A menüsor fejlécére is hatással lesz ez az effektus. Két gomb van egy sorban, melyek mindketten megváltozatják a megjelenített menüt, ha rájuk klikkelünk. A filebutton-ra kattintva megjelenik a fálj menü, az index pedig 0 lesz, mivel a FileMenu-t deklaráltuk először. A labelList rectangle-jének van egy z értéke, mely itt 1, ezzel jelölve, hogy ezt a menüsor előtt jelenítjük meg. Minél nagyobb a z értéke, annál előrébb foglal helyet a képernyőre merőleges síkban. A z alapértelmezett értéke 0.

<br /> Rectangle{<br /> id: labelList<br /> <br /> z: 1<br /> Row{<br /> anchors.centerIn: parent<br /> spacing:40<br /> Button{<br /> label: &amp;#8220;File&amp;amp;#8221;<br /> id: fileButton<br /> <br /> onButtonClick: menuListView.currentIndex = 0<br /> }<br /> Button{<br /> id: editButton<br /> label: &amp;#8220;Edit&amp;amp;#8221;<br /> <br /> onButtonClick: menuListView.currentIndex = 1<br /> }<br /> }<br /> }<br />

A létrehozott menüsorunkon vagy a felette lévő két gomb valamelyikére klikkelve megjeleníthetjük a menüket. Így egy intuitív és interaktív menüválasztó képernyőt alkottunk.

p=. qml-texteditor3_texteditor

A szövegszerkesztő megalkotása

TextArea deklarálása

Szövegszerkesztőnk mindaddig nem szövegszerkesztő, amíg nem tartalmaz egy szerkeszthető szövegmezőt.
A QML "TextEdit&quot;:http://doc.qt.nokia.com/4.7/qml-textedit.html eleme egy többsoros szövegmező létrehozását teszi lehetővé. A TextEdit különbözik a "Text&quot;:http://doc.qt.nokia.com/4.7/qml-text.html elemtől, melyet a felhasználó nem szerkeszthet direkt módon.

<br /> TextEdit{<br /> id: textEditor<br /> anchors.fill:parent<br /> width:parent.width; height:parent.height<br /> color:&amp;#8221;midnightblue&amp;amp;#8221;<br /> focus: true

wrapMode: TextEdit.Wrap

onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)<br /> }<br />

A szerkesztőnek megvan a saját betűszín tulajdonsága is. A TextArea egy flickable mezőn belül van, mely görgetni fogja a szöveget, ha a szövegkurzor a látható mezőn kívül van. Az ensureVisibility() függvény fogja leellenőrizni, hogy a kurzor rectangle-je kívül van-e a látható szegélyeken, és ha igen, akkor ennek megfelelően fogja mozgatni a szövegmezőt. A QML JavaScript szintaktikát használ a kódjaihoz, és ahogy már korábban említettük, importálhatunk és használhatunk is Javascript fájlokat egy QML fájlon belül.

<br /> function ensureVisible&amp;amp;#174;{<br /> if (contentX &gt;= r.x)<br /> contentX = r.x;<br /> else if (contentX+width &lt;= r.x+r.width)<br /> contentX = r.x+r.width-width;<br /> if (contentY &gt;= r.y)<br /> contentY = r.y;<br /> else if (contentY+height &lt;= r.y+r.height)<br /> contentY = r.y+r.height-height;<br /> }<br />

Komponensek kombinálása a szövegszerkesztőhöz

Most már készen állunk, hogy létrehozzuk szövegszerkesztőnket a QML segítségével. Programunk két fő komponensből áll, az általunk létrehozott menüsorból és egy szövegmezőből. A QML lehetővé teszi, hogy újrafelhasználjuk komponenseinket azok importálásával és testreszabásával ha szükséges, ezzel is egyszerűbbé téve a kódunkat. A szövegszerkesztőnk egyharmadát a menüsor, kétharmadát a szövegmez fogja elfoglalni. A menüsor minden más elem előtt fog megjelenni.

<br /> Rectangle{

id: screen<br /> width: 1000; height: 1000

//the screen is partitioned into the MenuBar and TextArea. 1/3 of the screen is assigned to the MenuBar<br /> property int partition: height/3

MenuBar{<br /> id:menuBar<br /> height: partition<br /> width:parent.width<br /> z: 1<br /> }

TextArea{<br /> id:textArea<br /> anchors.bottom:parent.bottom<br /> y: partition<br /> color: &amp;#8220;white&amp;amp;#8221;<br /> height: partition*2<br /> width:parent.width<br /> }<br /> }<br />

Újrafelhasznált komponenseikkel sokkal egyszerűbbnek tűnik a TextEditor forráskódja. Ezután testreszabhatjuk a fő alkalmazásunkat anélkül, hogy az előre definiál tulajdonságok miatt kellene aggódnunk. Ezzel a módszerrel könnyedén hozhatunk létre programvázakat és interfészeket.

p=. qml-texteditor3_texteditor

Szövegszerkesztőnk megjelenésének testreszabása

A Drawer Interface implementálása

A szövegszerkesztőnk egyszerűen néz ki, most már a megjelenését is testre kellene szabnunk. A QML-t használva átmeneteket és animációkat deklarálhatunk a szövegszerkesztőnkhöz. Menüsorunk elfoglalja az ablak egyharmadát, így jó lenne, ha csak akkor jelenne meg, ha mi akarjuk.
Hozzáadhatunk egy rajzoló interfészt, amely összecsukja illetve megjeleníti a menüsort klikkeléskor. Jelen esetben egy kis rectange.t használtunk, mely reagál az egérkattintásokra. A drawer, akárcsak az maga az alkalmazás, két állapottal rendelkezik, egy nyitottal és egy zárttal. A drawer elem egy kis magasságú rectangle, amihez kapcsolunk egy "Image&quot;:ttp://doc.qt.nokia.com/4.7/qml-image.html elemet, egy kis nyíl ikont jelenítve meg középen a rectangle-ön belül. A drawer meghatározza az program állapotát, ahogy a felhasználó rákattint a kis nyílra.

<br />Rectangle{<br /> id:drawer<br /> height:15

Image{<br /> id: arrowIcon<br /> source: &amp;#8220;images/arrow.png&amp;amp;#8221;<br /> anchors.horizontalCenter: parent.horizontalCenter<br /> }

MouseArea{<br /> id: drawerMouseArea<br /> anchors.fill:parent<br /> onClicked:{<br /> if (screen.state &amp;#34;DRAWER&amp;amp;#95;CLOSED&amp;amp;#34;){<br /> screen.state &amp;#61; &amp;#34;DRAWER&amp;amp;#95;OPEN&amp;amp;#34;<br /> }<br /> else if (screen.state &amp;#8220;DRAWER_OPEN&amp;amp;#8221;){<br /> screen.state = &amp;#8220;DRAWER_CLOSED&amp;amp;#8221;<br /> }<br /> }<br /> <br /> }<br /> }<br />

Ez az állapot egy sor konfigurációs beállítás, melyeket "State&quot;:http://doc.qt.nokia.com/4.7/qml-state.html elemeken keresztül deklarálunk. A különböző állapotok a state tulajdonsághoz kötődnek és kilistázhatjuk őket onnan. Az alkalmazásunkban két állapot, a DRAWER_CLOSED és a DRAWER_OPEN lesz. Az elemek konfigurációja a "PropertyChanges&quot;:http://doc.qt.nokia.com/4.7/qml-propertychanges.html elemben lesznek deklarálva. A DRAWER_OPEN állapotban 4 elem tulajdonsága fog megváltozni. A menuBar y tulajdonsága 0-ra fog változni. Hasonlóképpen, a textArea pozíciója lejjebb fog kerül, ha a DRAWER_OPEN állapot az aktív. A textArea, a drawer és a drawer ikonja fog változáson keresztülmenni, hogy elérje a megfelelő állapotot.

<br /> states:[<br /> State {<br /> name: &amp;#8220;DRAWER_OPEN&amp;amp;#8221;<br /> PropertyChanges { target: menuBar; y: 0}<br /> PropertyChanges { target: textArea; y: partition + drawer.height}<br /> PropertyChanges { target: drawer; y: partition}<br /> PropertyChanges { target: arrowIcon; rotation: 180}<br /> },<br /> State {<br /> name: &amp;#8220;DRAWER_CLOSED&amp;amp;#8221;<br /> PropertyChanges { target: menuBar; y:-height; }<br /> PropertyChanges { target: textArea; y: drawer.height; height: screen.height &amp;#8211; drawer.height }<br /> PropertyChanges { target: drawer; y: 0 }<br /> PropertyChanges { target: arrowIcon; rotation: 0 }<br /> }<br /> ]<br />

Az állapotváltozások azonnaliak, ám az átmenetnek ennél finomabbaknak kell lenniük. A "Transition&quot;:http://doc.qt.nokia.com/4.7/qml-transition.html elemben határozzuk meg a különböző állapotok közötti átmeneteket, amelyet ezután az elem transitions tulajdonságához rendelhetjük. A szövegszerkesztőnknek állapotátmenete lesz, akár DROWER_OPEN-re akár DROWER_CLOSED-ra módosul az állapota. Fontos, hogy az átmeneteknek rendelkezniük kell egy from (honnan) és egy to (hová) állapottal, de jelen esetben használhatunk csillagot * is, jelölve, hogy ez itt minden átmenetre vonatkozik. Az átmenetek során animációkat rendelhetünk a tulajdonság változásokhoz. A menüsorunk y : 0-ból y : x helyre ugrik, de ezt a mozgást leanimálhatjuk a "NumberAnimation&quot;:http://doc.qt.nokia.com/4.7/qml-numberanimation.html elem használatával. A cél elem tulajdonságait úgy állítjuk be, hogy annak mozgása egy meghatározott idő alatt, egy előre meghatározott csillapított görbe mentén animálódjon. Ez a csillapított görbe fogja szabályozni az animáció tulajdonságait az állapotváltozások között. Ez az ún. easing curve most az "Easing.OutQuint&quot;:http://doc.qt.nokia.com/4.7/qml-propertyanimation.html#easing.type-prop lesz, amely lelassítja az elem mozgását az animáció vége felé. Bővebb információért érdemes elolvasni a "QML's Animation&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html c. leírást.

<br />transitions: [<br /> Transition {<br /> to: &amp;#8221;*&amp;#8221;<br /> NumberAnimation { target: textArea; properties: &amp;#8220;y, height&amp;amp;#8221;; duration: 100; easing.type:Easing.OutExpo }<br /> NumberAnimation { target: menuBar; properties: &amp;#8220;y&amp;amp;#8221;; duration: 100; easing.type: Easing.OutExpo }<br /> NumberAnimation { target: drawer; properties: &amp;#8220;y&amp;amp;#8221;; duration: 100; easing.type: Easing.OutExpo }<br /> }<br /> ]<br />

Egy másik módja a tulajdonságváltozások animálásnak egy "Behavior&quot;:http://doc.qt.nokia.com/4.7/qml-behavior.html elem deklarálása. Egy átmenet csak állapotváltozások alatt működik, míg a Behavior hozzárendelhető egy egyszerű tulajdonságváltozáshoz is. A szövegszerkesztőnkben a nyílnak van egy NumberAnimation-ja, mely leanimálja annak rotation tulajdonságát valahányszor megváltozik az.

<br />In TextEditor.qml:

Behavior{<br /> NumberAnimation{property: &amp;#8220;rotation&amp;amp;#8221;;easing.type: Easing.OutExpo }<br /> }<br />

Térjünk vissza a komponenseinkhez az állapotokról és az animációkról megszerzett tudásunkkal, most már szebbé tehetjük azok megjelenését. A Button.qml-ben a gomb lenyomásához color és scale tulajdonságokat adhatunk. A szín típusokat a "ColorAnimation&quot;:http://doc.qt.nokia.com/4.7/qml-coloranimation.html fogja animálni, míg a számokat a NumberAnimation. Az alant látható on propertyName szintakszis hasznos lehet, ha csak egyetlen tulajdonságra akarunk utalni.

<br />In Button.qml:<br /> 

color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> Behavior on color { ColorAnimation{ duration: 55} }

scale: buttonMouseArea.pressed ? 1.1 : 1.00<br /> Behavior on scale { NumberAnimation{ duration: 55} }<br />

Még mutatósabbá tehetjük QML komponenseinket, ha olyan effektusokat adunk hozzájuk, mint a gradiens vagy az átlátszóság. Egy "Gradient&quot;:http://doc.qt.nokia.com/4.7/qml-gradient.html elem deklarálásával felülírhatjuk az elem color tulajdonságát. A "GradientStop&quot;:http://doc.qt.nokia.com/4.7/qml-gradientstop.html elemmel színeket is deklarálhatunk a gradiensünkön belül, melyet egy 0.0 és 1.0 közötti skálával adunk meg.

<br />In MenuBar.qml<br /> gradient: Gradient {<br /> GradientStop { position: 0.0; color: &amp;#8221;#8C8F8C&amp;amp;#8221; }<br /> GradientStop { position: 0.17; color: &amp;#8221;#6A6D6A&amp;amp;#8221; }<br /> GradientStop { position: 0.98;color: &amp;#8221;#3F3F3F&amp;amp;#8221; }<br /> GradientStop { position: 1.0; color: &amp;#8221;#0e1B20&amp;amp;#8221; }<br /> }<br />

A menüsorunkon használjuk majd a gradienst egy színátmenet megjelenítésére. Az első szín 0.0-nál kezdődik, az utolsó pedig 1.0-nál végződik.

Innen hova

Ezzel befejeztük egy nagyon egyszerű szövegszerkesztő felhasználói felületét. Tovább haladva most már implementálhatjuk az alkalmazásunk logikáját a jól megszokott Qt és C++ segítségével. A QML szépen dolgozik, elválasztva előbbit az UI designtól.

p=. qml-texteditor4_texteditor

QML kibővítése Qt C++ használatával

Már megvan a szövegszerkesztőnk váza, most implementálhatjuk a funkciókat C++ -ban. A QML-t és a C++ -t együtt használva lehetőségünk van Qt-ben létrehozni a program logikáját. Beilleszthetünk egy QML kotextust a C++ alkalmazásunkban a "Qt's Declarative&quot;:http://doc.qt.nokia.com/4.7/qtbinding.html osztályok használatával és meg is jeleníthetjük a QML elemeket a Graphic Scene segítségével. Vagy exportálhatjuk a C++ kódunkat egy olyan pluginba, amit a qmlviewer olvasni tud. A programunk számára a mentés és betöltés funkciókat C++ -ban fogjuk implementálni és ezt exportáljuk egy pluginba. Így csak a QML fájlunkat kell betöltenünk, nem kell egy futtatható állományt elindítani.

C++ osztályok megismertetése a QML-el

Qt és C++ segítségével fogjuk implementálni a betöltés és mentés opciókat. A C++ osztályok és függvények használatához regisztrálni kell őket a QML-ben. Az osztály továbbá Qt pluginként kell fordítani és a QML fájlnak tudnia kell, hogy ez a plugin merre található.

Az alkalmazásunk számára a következő elemeket kell létrehoznunk:
# Directory osztály, mely a mappákhoz kötődő művelteket fogja végrehajtani
# File osztály, ami egy "QObject&quot;:http://doc.qt.nokia.com/4.7/qobject.html, amely fájlok listáját szimulálja egy mappában
# plugin osztály mely a QML kontextushoz fogja regisztálni az osztályt
# Qt project fájl, mely majd lefordítja a plugin-t
# qmldir, mely átadja a plugin helyét a qmlviewer számára

Qt plugin létrehozása

A plugin létrehozásához a következőket kell beállítanunk a Qt project fájlunkban. Első körben a szükséges sources, headers, és a Qt modules szerepelnek a hozzáadandók listájában. Az összes C++ kód és project fájl a filedialog könyvtárban lesz.

<br />In cppPlugins.pro:

TEMPLATE = lib<br /> CONFIG ''= qt plugin<br /> QT''= declarative

DESTDIR ''= ../plugins<br /> OBJECTS_DIR = tmp<br /> MOC_DIR = tmp
<br /> TARGET = FileDialog
<br /> HEADERS''= directory.h  file.h  dialogPlugin.h

SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp<br />

A declarative modullal fordítjuk a Qt-t és _plugin_ként konfiguráljuk, amihez egy lib sablonra lesz szükségünk. A szülő plugins mappába kell tennünk a lefordított plugint.

Egy osztály regisztrálása QML-ben

<br />In dialogPlugin.h:

#include &lt;QtDeclarative/QDeclarativeExtensionPlugin&amp;gt;

class DialogPlugin : public QDeclarativeExtensionPlugin<br /> {<br /> Q_OBJECT

public:<br /> void registerTypes(const char *uri);

};<br />

A DialogPlugin osztályunk a "QDeclarativeExtensionPlugin&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html egy alosztálya. Implementálnunk kell az örökölt függvényt, a "registerTypes()":http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes -t. A dialogPlugin.cpp a következőképpen néz ki:

<br />DialogPlugin.cpp:

#include &quot;dialogPlugin.h&amp;quot;<br /> #include &quot;directory.h&amp;quot;<br /> #include &quot;file.h&amp;quot;<br /> #include &lt;QtDeclarative/qdeclarative.h&amp;gt;

void DialogPlugin::registerTypes(const char '''uri){
<br /> qmlRegisterType&amp;lt;Directory&amp;gt;(uri, 1, 0, &quot;Directory&amp;quot;);<br /> qmlRegisterType&amp;lt;File&amp;gt;(uri, 1, 0,&quot;File&amp;quot;);<br /> }
<br /> Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);<br />


A registerTypes() függvény regisztrálja a FILE és DIRECTORY osztályainkat QML-ben. Ennek a függvénynek meg kell adni a sablonja nevét, a fő- és az alverziószámot, valamint természetesen az osztályunk nevét.
Exportálnunk kell a plugint a "Q_EXPORT_PLUGIN2&quot;:http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2 makróval. Megjegyzendő, hogy a dialogPlugin.h fájlunkban ott van a "Q_OBJECT&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT makró az osztályunk tetején. Majd futassuk a qmkae-t a project fájlunkon hogy legeneráljuk a szükséges meta-object kódot.
h3. QML tulajdonságok létrehozása C++ osztályban
Létrehozhatunk QML elemeket és tulajdonságokat a C++ és a "Qt's Meta-Object System&quot;:http://doc.qt.nokia.com/4.7/metaobjects.html segítségével. Implementálhatjuk ezeket a tulajdonságokat slot-ok és signal-ok használatával, átadva ezeket a Qt-nek.
A szövegszerkesztőnknek be kell tudnia tölteni, illetve elmenteni a fájlokat. Általában ezeket a funkciókat egy fájl dialogban valósítjuk meg. Szerencsére használhatjuk a "QDir&quot;:http://doc.qt.nokia.com/4.7/qdir.html, "QFile&quot;:http://doc.qt.nokia.com/4.7/qfile.html, "QTextStream&quot;:http://doc.qt.nokia.com/4.7/qtextstream.html függvényeket, hogy implementáljuk a mappaolvasásokat és az input/output folyamatokat.


<br />class Directory : public QObject{
<br /> Q_OBJECT
<br /> Q_PROPERTY(int filesCount READ filesCount CONSTANT)<br /> Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)<br /> Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)<br /> Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )
<br /> <br />


A Directory class a Qt’s Meta-Object System-et használja, hogy regisztrálja a fájlkezelés megvalósításához szükséges tulajdonságokat. A Directory osztályt pluginként exportáltuk és QML-ben Directory elemként hivatkozhatunk rá. Az összes listázott tulajdonság a Q_PROPERTY makrót használja, amely egy QML tulajdonság.
A "Q_PROPERTY&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY deklarál egy tulajdonságot, továbbá függvényeket olvas és ír a Qt’s Meta-Object System-ből/be. Például a "QString&quot;:http://doc.qt.nokia.com/4.7/qstring.html filename tulajdonságát a filename() függvénnyel tudjuk olvasni, illetve a setFilename() függvénnyel írni. Továbbá egy signál, a filenameChanged(), is rendelve van a filename tulajdonsághoz, amely minden esetben emittálásra kerül, ha a tulajdonság megváltozik. Az író és olvasó függvényeket public-ként deklaráljuk a header fájlban.
Hasonlóképpen deklaráljuk a többi tulajdonságot, természetesen a használatuknak megfelelően. A filesCount tulajdonság az adott mappában lévő fájlok számát adja jelzi. A filename tulajdonság mindig az éppen kijelölt fájl nevét tárolja, a fileContent tulajdonságban pedig a betöltött/elmentett fájl tartalma tárolódik el.


<br /> Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )<br />


A files lista tulajdonság egy lista a mappában lévő fájlokról. A Directory osztály azért implementáltuk, hogy kiszűrje az érvénytelen szöveges fájlokat, csak a .txt kiterjesztésűek lesznek érvényesek. Továbbá a "QList&quot;:http://doc.qt.nokia.com/4.7/qlist.html "QDeclarativeListProperty&quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html -ként delarálva C++ -ban lesz használható QML-ben. A sablon objektumot a "QObject&quot;:http://doc.qt.nokia.com/4.7/qobject.html -től kell származtatni, így a File osztályt is. A Directory osztályban, a File objektumok listáját a _QList_–ben tárolj m_fileList néven.


<br />class File : public QObject{
<br /> Q_OBJECT<br /> Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
<br /> <br /> };<br />


Ez a tulajdonság ezután a Directory elem tulajdonságainak részeként használható QML-ben. Jegyezzük meg, hogy nem kell azonosító id tulajdonságot létrehoznunk a C++ kódunkban.


<br />Directory{<br /> id: directory
<br /> filesCount<br /> filename<br /> fileContent<br /> files
<br /> files[0].name<br /> }<br />


Mivel a QML Javascript szintaktikát és struktúrát használ, így végigfuthatunk a fájlok listáján és meg is kapjuk azok tulajdonságait. Hogy megkapjuk az első fájl név tulajdonságát, csak hívjuk meg a files[0].name függvényt.
A sima C++ függvények is elérhetőek QML–ben. A betöltő és elmentő függvények C++ -ban kerültek implementálásra a "Q_INVOKABLE&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE makró felhasználásával. De _slot_–ként is deklarálhatjuk a függvényeket, melyek ezután elérhetőek lesznek QML –ben.


<br />In Directory.h:
<br /> Q_INVOKABLE void saveFile&amp;amp;#40;&amp;#41;;<br /> Q_INVOKABLE void loadFile&amp;amp;#40;&amp;#41;;<br />


A Directory osztálynak tudomást kell szereznie más objektumokról, ha megváltozik a mappa tartalma. Ezt a funkciót _signal_–ok használatával oldjuk meg. Ahogy előzőleg említettük, a QML _signal_–oknak van egy hozzájuk tartozó végrehajtójuk, egy ún. _handler_–jük, amelyek neve megegyezik egy on prefixumot leszámítva. A signal neve directoryChanged és ez mindig emittálásra kerül, ha a mappa frissül. A frissítés szimplán újra betölti a mappa tartalmát és frissíti a listában a mappa érvényes fájljait. Ezek a QML elemek észrevehetőek felhasználjuk az onDirectoryChanged handler-t.
Érdemes tovább vizsgálni a list tulajdonságokat, ugyanis ún. callback-eket, visszahívásokat alkalmaznak, hogy elérjék és módosítsák a lista tartalmát. A list tulajdonság QDeclarativeListProperty&lt;File&gt; típusú, így akárhányszor hozzáférünk a listához, a hozzáférőnek egy QDeclarativeListProperty&lt;File&gt;-al kell visszatérnie. A sablon típusnak, a _File_–nak QObject leszármaztatottnak kell lennie! Hogy létrehozzunk egy "QDeclarativeListProperty&quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html -t , a lista hozzáférőjét és módosítóját függvény mutatókként át kell adni konstruktornak! A listának, esetünkben a _QList_–nek egy File mutató listának kell lennie! A QDeclarativeProperrty konstruktor konstruktorának és a Directory implementálása:


<br /> QDeclarativeListProperty ( QObject''' object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0 )<br /> QDeclarativeListProperty&amp;lt;File&amp;gt;( this, &amp;m_fileList, &amp;appendFiles, &amp;filesSize, &amp;fileAt, &amp;clearFilesPtr );<br />

A konstruktor átadja a mutatókat a függényekneknek, amik csatolják, megszámolják a elemeinek számát vagy kiürítik a listát, illetve visszanyerik az elemeit az indexek segítségével. Csak az append (csatoló) függvény megbízott. Megjegyzendő, hogy a függvény mutatóknak meg kell egyezniük az "AppendFunction&quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AppendFunction-typedef, a "CountFunction&quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#CountFunction-typedef, az "AtFunction&quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AtFunction-typedef, és a "ClearFunction&quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef definícióival!

<br />void appendFiles(QDeclarativeListProperty&amp;lt;File&amp;gt; * property, File * file)<br /> File* fileAt(QDeclarativeListProperty&amp;lt;File&amp;gt; * property, int index)<br /> int filesSize(QDeclarativeListProperty&amp;lt;File&amp;gt; * property)<br /> void clearFilesPtr(QDeclarativeListProperty&amp;lt;File&amp;gt; *property)<br />

Hogy egyszerűbbé tegyük a dialógunkat, a Directory osztály kiszűr minden fájlt, amely nem .txt kiterjesztésű és csak azokat jeleníti meg, amelyek azok. Sőt, ez az implementáció arról is gondoskodik, hogy az elmentett fájljaink megfelelő (.txt) kiterjesztést kapjanak. A Directory a "QTextStream&quot;:http://doc.qt.nokia.com/4.7/qtextstream.html függvényt használja, hogy kiolvasson a fájlból, illetve hogy írjon bele.

A Directory elemünkkel tehát visszanyerhetjük a fájljaink listáját, azok nevét és tartalmát stringként, megtudhatjuk, hogy hány fájl van az adott mappában, és valahányszor megváltozik annak tartalma, arról értesítést kaphatunk.

Ahhoz hogy létrehozzuk a _plugin_–t, futassuk a _qmake_–t a cppPlugins.pro project fájlon, aztán futassuk a make parancsot hogy lefordítsuk és áthelyezzük a pluginunkkat a plugins könyvtára.

Plugin importálása QML-ben

A qmlviewer azokat a fájlokat importálja, amelyek az alkalmazásunkkal egy mappában van. De létrehozhatunk egy qmldir fájlt is, amely tartalmazza majd, hogy merre találhatóak a QML fájljaink, melyeket importálni szeretnénk. A qmldir fájl tovább tartalmazhatta más pluginok és ún. resources, eszközök helyét.

<br />In qmldir:

Button ./Button.qml<br /> FileDialog ./FileDialog.qml<br /> TextArea ./TextArea.qml<br /> TextEditor ./TextEditor.qml<br /> EditMenu ./EditMenu.qml

plugin FileDialog plugins<br />

A plugin, melyet fentebb létrehoztunk FileDialog névvel rendelkezik, ahogy azt a TARGET mezőben is jeleztük a project fájlunkban. A lefordított plugin a plugins könyvtárban található.

Egy File Dialog integrálása a File Menu–be

A _FileMenu_–ünknek egy _FileDialog_–ot kell elemet megjelenítenie, amely tartalmazza a könyvtár, .txt kiterjesztésű, fájljait és lehetővé teszi a felhasználó számára, hogy kiválassza a megnyitni kívánt fájlt. Továbbá el kell helyeznünk benne a mentés, a megnyitás és az új gombokat, hogy azok elvégezhessék a kívánt műveletet. A FileMenu tartalmazni fog egy szerkeszthető szövegmezőt is, ahová a felhasználó begépelhet egy fájlnevet. A Directory elemet a _FileMenu.qml_–ben használjuk fel, és ez majd értesít minket, ha megváltozott a könyvtár tartalma. Ezt az signal-t az onDirectoryChanged handler fogja számunkra eljuttatni.

<br />In FileMenu.qml:

Directory{<br /> id:directory<br /> filename: textInput.text<br /> onDirectoryChanged: fileDialog.notifyRefresh()<br /> }<br />

Alkalmazásunk egyszerűségét megőrizendő, a fájl dialógunk csak a szükséges fájlokat fogja megjeleníteni, amelyek .txt kiterjesztésűek.

<br />In FileDialog.qml:

signal notifyRefresh()<br /> onNotifyRefresh: dirView.model = directory.files<br />

Ahogy fentebb írtuk, a FileDialog elem meg fogja jeleníteni a mappa számunkra releváns tartalmát, amelyet a files tulajdonság kiolvasásával fogunk elérni. A fájlokat egy "GridView&quot;:http://doc.qt.nokia.com/4.7/qml-gridview.html modellt használó elem fogja megjeleníteni rácsos elrendezésben egy delegate-nek megfelelően. A delegate fogja lekezelni a modellünk megjelenését és a fájl dialógunk létrehoz majd egy grid-et, egy rácsot, középre igazítva benne a szöveget. Egy fájlnévre kattintva egy rectangle jelenik meg, kijelölve a fájlnevet. Akárhányszor emittálásra kerül a notifyRefresh signal, a FileDialog újratölti majd a könyvtár tartalmát.

<br />In FileMenu.qml:

Button{<br /> id: newButton<br /> label: &quot;New&amp;quot;<br /> onButtonClick:{<br /> textArea.textContent = &quot;&quot;<br /> }<br /> }<br /> Button{<br /> id: loadButton<br /> label: &quot;Load&amp;quot;<br /> onButtonClick:{<br /> directory.filename = textInput.text<br /> directory.loadFile&amp;amp;#40;&amp;#41;<br /> textArea.textContent = directory.fileContent<br /> }<br /> }<br /> Button{<br /> id: saveButton<br /> label: &quot;Save&amp;quot;<br /> onButtonClick:{<br /> directory.fileContent = textArea.textContent<br /> directory.filename = textInput.text<br /> directory.saveFile&amp;amp;#40;&amp;#41;<br /> }<br /> }<br /> Button{<br /> id: exitButton<br /> label: &quot;Exit&amp;quot;<br /> onButtonClick:{<br /> Qt.quit()<br /> }<br /> }<br />

Most már a FileMenu-nk kapcsolódhat a megfelelő műveletekhez. A saveButton továbbítja majd a TextEdit-ből a szöveget a Directory filecontent tulajdonságában, majd átmásolja a fájl nevét a szerkeszthető szövegmezőből. Végül pedig a gomb meghívja a saveFile&amp;#40;&#41; függvényt, amely elmenti a fájlunkat. A loadButton hasonló végrehajtással rendelkezik. A New gomb megnyomására pedig kitörlődik a TextEdit tartalma. Továbbá a EditMenu gombjai kapcsolónak a TextEdit függvényeihez, hogy képesek legyenek a copy, paste funkció betöltésére, valamint hogy a kijelölhessük a szöveget.

p=. qml-texteditor5_filemenu

A szövegszerkesztőnk befejezése

p=. qml-texteditor5_newfile

Összegezve, a kis alkalmazásunk képes az alapvető szövegszerkesztési funkciók ellátása, így képes elmenteni, megnyitni, illetve módosítani bármilyen .txt kiterjesztésű fájlt.

Köszönjük, hogy elolvasta eme ismertetőt, reméljük hasznosnak bizonyult és remek QML alkalmazások fognak születni az itt elolvasott tudás birtokában!

Have a nice day! :)