Getting Started Programming with QML/mk: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
m (AutoSpider moved page GettingStartedQMLMacedonian to Getting Started Programming with QML/mk: Localisation)
 
(7 intermediate revisions by 2 users not shown)
Line 1: Line 1:
[toc align_right="yes" depth="3"]
{{Cleanup | reason=Auto-imported from ExpressionEngine.}}
 


= Започнување на програмирање со QML =
= Започнување на програмирање со QML =


Добредојдовте во светот на QML, декларативниот UI јазик. Во овој почетнички водич, ќе создадеме едноставен текст едитор користејќи QML. По читањето на ова упаство, треба да бидете подготвени да развивате сопствена апликација со употреба на QML и Qt C+''.
Добредојдовте во светот на QML, декларативниот UI јазик. Во овој почетнички водич, ќе создадеме едноставен текст едитор користејќи QML. По читањето на ова упаство, треба да бидете подготвени да развивате сопствена апликација со употреба на QML и Qt C+''.
<br />h2. QML за градење на кориснички интерфејси
 
<br />Апликацијата што ја градиме е едноставен текст едитор кој ќе вчитува, снима, и врши некаква текст манипулација. Овој водич ќе се состои од два дела. Првиот дел ќе вклучи дизајнирање на распоредот (layout) на апликацијата и однесување со користење на QML декларативниот јазик. За вториот дел, вчитување и снимање на фајлови ќе биде имплементирано со користење на Qt C. Со користење на &quot;Мета-Објектниот Систем&amp;quot;:http://doc.qt.nokia.com/4.7/metaobjects.html, можеме да ги изложиме C''+ функциите како својства (properties) што QML елементите можат да ги користат. Со користењето на QML и Qt C+'', ние можеме ефикасно да ја одвоиме интерфејс логиката од апликациската логика.
== QML за градење на кориснички интерфејси ==
<br />[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png|QML текст едитор]]
Апликацијата што ја градиме е едноставен текст едитор кој ќе вчитува, снима, и врши некаква текст манипулација. Овој водич ќе се состои од два дела. Првиот дел ќе вклучи дизајнирање на распоредот (layout) на апликацијата и однесување со користење на QML декларативниот јазик. За вториот дел, вчитување и снимање на фајлови ќе биде имплементирано со користење на Qt C. Со користење на [http://doc.qt.nokia.com/4.7/metaobjects.html Мета-Објектниот Систем], можеме да ги изложиме C''+ функциите како својства (properties) што QML елементите можат да ги користат. Со користењето на QML и Qt C+'', ние можеме ефикасно да ја одвоиме интерфејс логиката од апликациската логика.
<br />За да се стартува QML кодот со примери, доволно е да се вклучи &quot;qmlviewer&amp;quot;:http://doc.qt.nokia.com/4.7/qmlviewer.html алатката заедно со QML фајлот како аргумент. C''+ делот од овој туторијал претпоставува дека читателот има основни познавања на Qt компилациските процедури.
 
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png|QML текст едитор]]
 
За да се стартува QML кодот со примери, доволно е да се вклучи [http://doc.qt.nokia.com/4.7/qmlviewer.html qmlviewer] алатката заедно со QML фајлот како аргумент. C''+ делот од овој туторијал претпоставува дека читателот има основни познавања на Qt компилациските процедури.


== Дефинирање на копче и мени ==
== Дефинирање на копче и мени ==
Line 15: Line 19:
Го започнуваме нашиот текст едитор со изградба на копче (button). Функционално, копчето има област сензитивна на глувче и етикета (label). Копчињата вршат дејствија кога корисникот ќе го притисне копчето.
Го започнуваме нашиот текст едитор со изградба на копче (button). Функционално, копчето има област сензитивна на глувче и етикета (label). Копчињата вршат дејствија кога корисникот ќе го притисне копчето.


Во QML, основниот визуелен елемент е &quot;Rectangle&amp;quot;:http://doc.qt.nokia.com/4.7/qml-rectangle.html елементот. ''Rectangle'' (правоаголник) елементот има својства за контрола на изгледот и локацијата на елементот.
Во QML, основниот визуелен елемент е [http://doc.qt.nokia.com/4.7/qml-rectangle.html Rectangle] елементот. ''Rectangle'' (правоаголник) елементот има својства за контрола на изгледот и локацијата на елементот.


<code><br />import Qt 4.7
<code>
import Qt 4.7


Rectangle{<br /> id:simplebutton<br /> color: &quot;grey&amp;quot;<br /> width: 150<br /> height: 80<br /> Text{<br /> id: buttonLabel<br /> text: &quot;button label&amp;quot;<br /> anchors.centerIn: simplebutton;<br /> anchors.verticalCenterOffset: –1<br /> }<br /> }<br /></code>
Rectangle{
id:simplebutton
color: "grey"
width: 150
height: 80
Text{
id: buttonLabel
text: "button label"
anchors.centerIn: simplebutton;
anchors.verticalCenterOffset: –1
}
}
</code>


Прво, ''import Qt 4.7'' овозможува qmlviewer алатката да импортира QML елементи кои покасно ќе ги користиме. Оваа линија мора да постои во секој QML фајл. Забележете дека верзијата на Qt модулите е ставена во импорт изјавата.
Прво, ''import Qt 4.7'' овозможува qmlviewer алатката да импортира QML елементи кои покасно ќе ги користиме. Оваа линија мора да постои во секој QML фајл. Забележете дека верзијата на Qt модулите е ставена во импорт изјавата.
Line 25: Line 42:
Овој едноставен правоаголник има единствен идентификатор, ''simplebutton'', кој е врзан за id својството. Својствата на ''Rect'' елементот се врзуваат на вредности со листање на својството, следено од две точки, потоа вредноста. Во ова парче код, бојата ''grey'' (сива) е врзана за својството ''color'' (боја) на правоаголникот. Слично, ги врзуваме ''width'' (ширина) и ''height'' (висина) на правоаголникот.
Овој едноставен правоаголник има единствен идентификатор, ''simplebutton'', кој е врзан за id својството. Својствата на ''Rect'' елементот се врзуваат на вредности со листање на својството, следено од две точки, потоа вредноста. Во ова парче код, бојата ''grey'' (сива) е врзана за својството ''color'' (боја) на правоаголникот. Слично, ги врзуваме ''width'' (ширина) и ''height'' (висина) на правоаголникот.


&quot;Тext&amp;quot;:http://doc.qt.nokia.com/4.7/qml-text.html елементот е текст поле без можност за едитирање. Го крстиме овој ''Text'' елемент ''buttonLabel''. За да го поставите стрингот во Текст полето, ние ја врзуваме вредноста на ''text'' својството. Етикетата е во рамките на правоаголникот и со цел да ја центрираме во средината, ние доделуваме сидра (''anchors'') на Текст елементот на неговиот родител, кој се вика ''simplebutton''. Сидрата може да се врзуваат на сидра на други елементи, дозволувајќи поедноставно доделување на распоредот.
[http://doc.qt.nokia.com/4.7/qml-text.html Тext] елементот е текст поле без можност за едитирање. Го крстиме овој ''Text'' елемент ''buttonLabel''. За да го поставите стрингот во Текст полето, ние ја врзуваме вредноста на ''text'' својството. Етикетата е во рамките на правоаголникот и со цел да ја центрираме во средината, ние доделуваме сидра (''anchors'') на Текст елементот на неговиот родител, кој се вика ''simplebutton''. Сидрата може да се врзуваат на сидра на други елементи, дозволувајќи поедноставно доделување на распоредот.


Треба овој код да го снимиме како SimpleButton.qml. Стартувањето на qmlviewer со овој фајл како аргумент ќе прикаже сив правоаголник со текст етикета.
Треба овој код да го снимиме како SimpleButton.qml. Стартувањето на qmlviewer со овој фајл како аргумент ќе прикаже сив правоаголник со текст етикета.
Line 33: Line 50:
За имплементирање на клик функционалноста на копчето, можеме да користиме QML-овото справување со настани. Справувањето со настани во QML е доста сличен на Qt-овиот механизам на сигнали и слотови. Сигналите се емитираат и поврзаниот слот е повикан.
За имплементирање на клик функционалноста на копчето, можеме да користиме QML-овото справување со настани. Справувањето со настани во QML е доста сличен на Qt-овиот механизам на сигнали и слотови. Сигналите се емитираат и поврзаниот слот е повикан.


<code><br />Rectangle{<br /> id:simplebutton<br /> <br /> MouseArea{<br /> id: buttonMouseArea<br /> anchors.fill: parent //усидри ги сите страни на областа на глушецот на сидрата на правоаголникот<br /> //сигналот onClicked ги справува валидните кликови на копчињата на глушецот<br /> onClicked: console.log(buttonLabel.text + &quot; clicked&amp;quot; )<br /> }<br /> }<br /></code>
<code>
Rectangle{
id:simplebutton
MouseArea{
id: buttonMouseArea
anchors.fill: parent //усидри ги сите страни на областа на глушецот на сидрата на правоаголникот
//сигналот onClicked ги справува валидните кликови на копчињата на глушецот
onClicked: console.log(buttonLabel.text + " clicked" )
}
}
</code>


Го користиме &quot;MouseArea&amp;quot;:http://doc.qt.nokia.com/4.7/qml-mousearea.html елементот во нашиот ''simplebutton''. ''MouseArea'' елементите опишуваат интерактивна област каде движењата на глушецот се детектираат. За нашето копче, го усидруваме целиот &quot;MouseArea&amp;quot;:http://doc.qt.nokia.com/4.7/qml-mousearea.html на неговиот родител, кој е ''simplebutton''. синтаксата ''anchors.fill'' е еден начин на пристапување на специфично својство наречен ''fill'' внатре во групата на својства наречени ''anchors'' (сидра). QML користи &quot;распоред базиран на сидра&amp;quot;:http://doc.qt.nokia.com/4.7/qml-anchor-layout.html каде елементите можат да се усидрат со други елементи, креирајќи робустни распореди.
Го користиме [http://doc.qt.nokia.com/4.7/qml-mousearea.html MouseArea] елементот во нашиот ''simplebutton''. ''MouseArea'' елементите опишуваат интерактивна област каде движењата на глушецот се детектираат. За нашето копче, го усидруваме целиот [http://doc.qt.nokia.com/4.7/qml-mousearea.html MouseArea] на неговиот родител, кој е ''simplebutton''. синтаксата ''anchors.fill'' е еден начин на пристапување на специфично својство наречен ''fill'' внатре во групата на својства наречени ''anchors'' (сидра). QML користи [http://doc.qt.nokia.com/4.7/qml-anchor-layout.html распоред базиран на сидра] каде елементите можат да се усидрат со други елементи, креирајќи робустни распореди.


''MouseArea'' има многу справувачи со сигнали кои се повикуваат ако има движења на глушецот внатре во специфираните ''MouserArea'' граници. Еден од нив е ''onClicked'' и се повикува кога копчето на глушецот е кликнато, каде левиот клик е стандарден. Можеме да врземе акции на ''onClicked'' справувачот. Во нашиот пример, ''console.log()'' испишува текст кога областа на глувчето е кликната. Функцијата ''console.log()'' е корисна алатка за дебагирање и испишување текст.
''MouseArea'' има многу справувачи со сигнали кои се повикуваат ако има движења на глушецот внатре во специфираните ''MouserArea'' граници. Еден од нив е ''onClicked'' и се повикува кога копчето на глушецот е кликнато, каде левиот клик е стандарден. Можеме да врземе акции на ''onClicked'' справувачот. Во нашиот пример, ''console.log()'' испишува текст кога областа на глувчето е кликната. Функцијата ''console.log()'' е корисна алатка за дебагирање и испишување текст.
Line 41: Line 69:
Кодот во ''SimpleButton.qml'' е доволен да прикаже копче на екранот и да испише текст кога ќе се кликне на глувчето.
Кодот во ''SimpleButton.qml'' е доволен да прикаже копче на екранот и да испише текст кога ќе се кликне на глувчето.


<code><br />Rectangle {<br /> id:Button<br />
<code>
Rectangle {
id:Button


property color buttonColor: &quot;lightblue&amp;quot;<br /> property color onHoverColor: &quot;gold&amp;quot;<br /> property color borderColor: &quot;white&amp;quot;
property color buttonColor: "lightblue"
property color onHoverColor: "gold"
property color borderColor: "white"


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


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


//ја одредува бојата на копчето со користење на условниот оператор<br /> color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> }<br /></code>
//ја одредува бојата на копчето со користење на условниот оператор
color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor
}
</code>


Целосно функционално копче е во ''Button.qml''. Некој код во оваа статија е испуштен, означено со три точки бидејќи тие биле претходно воведени во претходните секции или се ирелевантни за тековната дискусија.
Целосно функционално копче е во ''Button.qml''. Некој код во оваа статија е испуштен, означено со три точки бидејќи тие биле претходно воведени во претходните секции или се ирелевантни за тековната дискусија.


Приспособените својства се декларираат со користење на ''property type name'' синтаксата. Во овој код, својството ''buttonColor'', од типот ''color'', е декларирано и врзано за вредноста ''&quot;lightblue&amp;quot;''. ''buttonColor'' подоцна се користи во условна операција за да се одреди бојата со која ќе се исполни копчето. Да се забележи дека доделување на вредност на својството е можно со користење на = еднакво симболот, а врзување на вредноста со : две точки карактерот. Приспособените својства овозможуваат интерните елементи да бидат пристапни надвор од Rectangle опсегот (scope). Постојат основни &quot;QML типови на податоци&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativebasictypes.html како што се ''int'', ''string'', ''real'' како и тип наречен ''variant''.
Приспособените својства се декларираат со користење на ''property type name'' синтаксата. Во овој код, својството ''buttonColor'', од типот ''color'', е декларирано и врзано за вредноста ''"lightblue"''. ''buttonColor'' подоцна се користи во условна операција за да се одреди бојата со која ќе се исполни копчето. Да се забележи дека доделување на вредност на својството е можно со користење на = еднакво симболот, а врзување на вредноста со : две точки карактерот. Приспособените својства овозможуваат интерните елементи да бидат пристапни надвор од Rectangle опсегот (scope). Постојат основни [http://doc.qt.nokia.com/4.7/qdeclarativebasictypes.html QML типови на податоци] како што се ''int'', ''string'', ''real'' како и тип наречен ''variant''.


Врзувањето на ''onEntered'' и ''onExited'' справувачите на сигнали со боите овозможува границата на копчето да стане жолта кога глувчето лебди на копчето и ја враќа бојата кога глувчето ќе излезе од областа.
Врзувањето на ''onEntered'' и ''onExited'' справувачите на сигнали со боите овозможува границата на копчето да стане жолта кога глувчето лебди на копчето и ја враќа бојата кога глувчето ќе излезе од областа.
Line 71: Line 115:
Менито прикажува содржина на листа, секој елемент има можност да изврши одредена акција. Во QML, можеме да креираме мени на неколку начини. Прво, ќе креираме мени кое ќе содржи неколку копчиња кои евентуално би извршувале различни акции. Кодот за мени е во ''FileMenu.qml''.
Менито прикажува содржина на листа, секој елемент има можност да изврши одредена акција. Во QML, можеме да креираме мени на неколку начини. Прво, ќе креираме мени кое ќе содржи неколку копчиња кои евентуално би извршувале различни акции. Кодот за мени е во ''FileMenu.qml''.


<code><br /> import Qt 4.7 импортирање на главниот Qt QML модул<br /> import &quot;folderName&amp;quot; импортирање на содржината на фолдерот<br /> import &quot;script.js&amp;quot; as Script импортирање на Javascript фајл кој би се именувал како Script<br /></code>
<code>
import Qt 4.7 импортирање на главниот Qt QML модул
import "folderName" импортирање на содржината на фолдерот
import "script.js" as Script импортирање на Javascript фајл кој би се именувал како Script
</code>


Синтаксата прикажана горе покажува како се употребува ''import''. Ова е потребно за користење на &quot;Javascript&amp;quot;:https://developer.mozilla.org/en/JavaScript фајлови, или QML фајлови кои не се во истиот директориум. Бидејќи ''Button.qml'' е во ист директориум како и ''FileMenu.qml'' нема потреба да се импортира ''Button.qml'' за да се користи. Можеме директно да креираме ''Button'' елемент со декларирање на ''Button{}'', слично на ''Rectangle'' декларацијата.
Синтаксата прикажана горе покажува како се употребува ''import''. Ова е потребно за користење на [https://developer.mozilla.org/en/JavaScript Javascript] фајлови, или QML фајлови кои не се во истиот директориум. Бидејќи ''Button.qml'' е во ист директориум како и ''FileMenu.qml'' нема потреба да се импортира ''Button.qml'' за да се користи. Можеме директно да креираме ''Button'' елемент со декларирање на ''Button{}'', слично на ''Rectangle'' декларацијата.


<code><br /> В файле FileMenu.qml:
<code>
В файле FileMenu.qml:


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


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


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


Во ''FileMenu.qml'', ние декларираме три ''Button'' елементи. Тие се декларирани внатре во &quot;''Row''&quot;:http://doc.qt.nokia.com/4.7/qml-row.html елементот, позицинионер кој ќе ги позиционира неговите деца во вертикална линија. ''Button'' декларацијата останува во ''Button.qml'', која е иста како и ''Button.qml'' што ја користевме во претходната секција. Нови врзувања на својствата може да бидат декларирани во новите креирани копчиња, ефективно пребришувајќи ги својствата сетирани во ''Button.qml''. Копчето наречено ''exitButton'' ќе излезе и затвори прозорот кога е кликнато. Да се забележи дека справувачот со сигнали ''onButtonClick'' во ''Button.qml'' ќе биде повикан заедно со ''onButtonClick'' справувачот во ''exitButton''.
Во ''FileMenu.qml'', ние декларираме три ''Button'' елементи. Тие се декларирани внатре во [http://doc.qt.nokia.com/4.7/qml-row.html ''Row''] елементот, позицинионер кој ќе ги позиционира неговите деца во вертикална линија. ''Button'' декларацијата останува во ''Button.qml'', која е иста како и ''Button.qml'' што ја користевме во претходната секција. Нови врзувања на својствата може да бидат декларирани во новите креирани копчиња, ефективно пребришувајќи ги својствата сетирани во ''Button.qml''. Копчето наречено ''exitButton'' ќе излезе и затвори прозорот кога е кликнато. Да се забележи дека справувачот со сигнали ''onButtonClick'' во ''Button.qml'' ќе биде повикан заедно со ''onButtonClick'' справувачот во ''exitButton''.


[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_filemenu.png|filemenu]]
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_filemenu.png|filemenu]]
Line 101: Line 168:
== Користење на податочни модели и прикази ==
== Користење на податочни модели и прикази ==


QML има различни &quot;податочни прикази&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html кои прикажуваат &quot;податочни модели&amp;quot;http://doc.qt.nokia.com/4.7/qdeclarativemodels.html. Нашата мени лента ќе ги прикажува менијата во листа, со заглавје кое прикажува редица на имиња на менијата. Листата на менијата се декларирани внатре во ''VisualItemModel''. &quot;VisualItemModel&amp;quot;:http://doc.qt.nokia.com/4.7/qml-visualitemmodel.html елементот содржи елементи кои веќе имаат свои прикази како што се ''Rectangle'' елементите и импортираните UI елементи. Други типови на модели како што е &quot;ListModel&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listmodel.html елементот имаат потреба од делегат за да ги прикажуваат нивните податоци.
QML има различни [http://doc.qt.nokia.com/4.7/qdeclarativemodels.html податочни прикази] кои прикажуваат "податочни модели"http://doc.qt.nokia.com/4.7/qdeclarativemodels.html. Нашата мени лента ќе ги прикажува менијата во листа, со заглавје кое прикажува редица на имиња на менијата. Листата на менијата се декларирани внатре во ''VisualItemModel''. [http://doc.qt.nokia.com/4.7/qml-visualitemmodel.html VisualItemModel] елементот содржи елементи кои веќе имаат свои прикази како што се ''Rectangle'' елементите и импортираните UI елементи. Други типови на модели како што е [http://doc.qt.nokia.com/4.7/qml-listmodel.html ListModel] елементот имаат потреба од делегат за да ги прикажуваат нивните податоци.


Декларираме два визуелни елементи во ''menuListModel'', ''FileMenu'' и ''EditMenu''. Ги прилагодуваме двете менија и ги прикажуваме со користење на &quot;ListView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listview.html. ''MenuBar.qml'' фајлот содржи QML декларации и едноставно мени за едитирање е дефинирано во ''EditMenu.qml''.
Декларираме два визуелни елементи во ''menuListModel'', ''FileMenu'' и ''EditMenu''. Ги прилагодуваме двете менија и ги прикажуваме со користење на [http://doc.qt.nokia.com/4.7/qml-listview.html ListView]. ''MenuBar.qml'' фајлот содржи QML декларации и едноставно мени за едитирање е дефинирано во ''EditMenu.qml''.


<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>
<code>
VisualItemModel{
id: menuListModel
FileMenu{
width: menuListView.width
height: menuBar.height
color: fileColor
}
EditMenu{
color: editColor
width: menuListView.width
height: menuBar.height
}
}
</code>


&quot;ListView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listview.html елементот ќе го прикаже моделот во зависност од делегатот. Делегатот може да ги декларира елементите на моделот за прикажување во ''Row'' елемент или да ги прикаже елементите во мрежа. Нашето ''menuListModel'' веќе има видливи елементи, затоа, нема потреба од декларирање на делегат.
[http://doc.qt.nokia.com/4.7/qml-listview.html ListView] елементот ќе го прикаже моделот во зависност од делегатот. Делегатот може да ги декларира елементите на моделот за прикажување во ''Row'' елемент или да ги прикаже елементите во мрежа. Нашето ''menuListModel'' веќе има видливи елементи, затоа, нема потреба од декларирање на делегат.


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


//сидрата се сетирани да реагираат на сидрата на прозорецот<br /> anchors.fill:parent<br /> anchors.bottom: parent.bottom<br /> width:parent.width<br /> height: parent.height
//сидрата се сетирани да реагираат на сидрата на прозорецот
anchors.fill:parent
anchors.bottom: parent.bottom
width:parent.width
height: parent.height


//моделот ги содржи податоците<br /> model: menuListModel
//моделот ги содржи податоците
model: menuListModel


//контрола на движењето на менувањето на менито<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>
//контрола на движењето на менувањето на менито
snapMode: ListView.SnapOneItem
orientation: ListView.Horizontal
boundsBehavior: Flickable.StopAtBounds
flickDeceleration: 5000
highlightFollowsCurrentItem: true
highlightMoveDuration:240
highlightRangeMode: ListView.StrictlyEnforceRange
}
</code>


Додатно, ''ListView'' наследува од ''Flickable'', овозможувајќи на листата да реагира на влечења на глувчето и други гестови. Последното парче на кодот погоре ги сетира Flickable својствата за да се создаде пожелно допирно (flicking) движење на нашиот приказ. Конкретно, својството ''highlightMoveDuration'' го менува времетраењето на допирната транзиција. Поголеми ''highlightMoveDuration'' вредности резултира со поспоро менување на менијата.
Додатно, ''ListView'' наследува од ''Flickable'', овозможувајќи на листата да реагира на влечења на глувчето и други гестови. Последното парче на кодот погоре ги сетира Flickable својствата за да се создаде пожелно допирно (flicking) движење на нашиот приказ. Конкретно, својството ''highlightMoveDuration'' го менува времетраењето на допирната транзиција. Поголеми ''highlightMoveDuration'' вредности резултира со поспоро менување на менијата.
Line 123: Line 220:
''labelList'' правоаголникот има z вредност 1, означувајќи дека мора да се прикаже пред мени лентата. Елементите со поголема z вредност се прикажуваат пред елементите со помали z вредности. Стандардната вредност на z е 0.
''labelList'' правоаголникот има z вредност 1, означувајќи дека мора да се прикаже пред мени лентата. Елементите со поголема z вредност се прикажуваат пред елементите со помали z вредности. Стандардната вредност на z е 0.


<code><br /> Rectangle{<br /> id: labelList<br /> <br /> z: 1<br /> Row{<br /> anchors.centerIn: parent<br /> spacing:40<br /> Button{<br /> label: &quot;File&amp;quot;<br /> id: fileButton<br /> <br /> onButtonClick: menuListView.currentIndex = 0<br /> }<br /> Button{<br /> id: editButton%0 …<br /> onButtonClick: menuListView.currentIndex = 1<br /> }<br /> }<br /> }<br /></code>
<code>
Rectangle{
id: labelList
z: 1
Row{
anchors.centerIn: parent
spacing:40
Button{
label: "File"
id: fileButton
onButtonClick: menuListView.currentIndex = 0
}
Button{
id: editButton%0 …
onButtonClick: menuListView.currentIndex = 1
}
}
}
</code>


Мени лентата што ја креиравме може да се движи со допир за да се пристапи на менијата или со кликање на имињата на менијата. Менувањето на менијата е интуитивно и респонзивно.
Мени лентата што ја креиравме може да се движи со допир за да се пристапи на менијата или со кликање на имињата на менијата. Менувањето на менијата е интуитивно и респонзивно.
Line 133: Line 250:
=== Декларирање на TextArea (текстуална област) ===
=== Декларирање на TextArea (текстуална област) ===


Нашиот текст едитор не е текст едитор ако не содржи област за едитирање на текстот. QML-овиот &quot;TextEdit&amp;quot;:http://doc.qt.nokia.com/4.7/qml-textedit.html елемент овозможува декларирање на мултилиниска област за едитирање на текст. &quot;TextEdit&amp;quot;:http://doc.qt.nokia.com/4.7/qml-textedit.html е различен од &quot;Text&amp;quot;:http://doc.qt.nokia.com/4.7/qml-text.html елементот, кој не дозволува на корисникот директно да го едитира текстот.
Нашиот текст едитор не е текст едитор ако не содржи област за едитирање на текстот. QML-овиот [http://doc.qt.nokia.com/4.7/qml-textedit.html TextEdit] елемент овозможува декларирање на мултилиниска област за едитирање на текст. [http://doc.qt.nokia.com/4.7/qml-textedit.html TextEdit] е различен од [http://doc.qt.nokia.com/4.7/qml-text.html Text] елементот, кој не дозволува на корисникот директно да го едитира текстот.


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


wrapMode: TextEdit.Wrap
wrapMode: TextEdit.Wrap


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


Својството на боја за фонтот е сетирано, исто така сетирано е текстот да се замотува (wrap). ''TextEdit'' областа е внатре во допирната (flickable) област која ќе го скролува текстот ако курсорот на текстот е надвор од видливата област. Функцијата ''ensureVisible()'' ќе провери дали правоаголникот на курсорот е надвор од видливите граници и ќе ја помести текстуалната област соодветно. QML користи Javascript синтакса за неговите скрипти, и како што беше претходно спомнато, Javascript фајловите може да бидат импортирани и користени внатре во QML фајлот.
Својството на боја за фонтот е сетирано, исто така сетирано е текстот да се замотува (wrap). ''TextEdit'' областа е внатре во допирната (flickable) област која ќе го скролува текстот ако курсорот на текстот е надвор од видливата област. Функцијата ''ensureVisible()'' ќе провери дали правоаголникот на курсорот е надвор од видливите граници и ќе ја помести текстуалната област соодветно. QML користи Javascript синтакса за неговите скрипти, и како што беше претходно спомнато, Javascript фајловите може да бидат импортирани и користени внатре во QML фајлот.


<code><br />function ensureVisible®{<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>
<code>
function ensureVisible®{
if (contentX >= r.x)
contentX = r.x;
else if (contentX+width <= r.x+r.width)
contentX = r.x+r.width-width;
if (contentY >= r.y)
contentY = r.y;
else if (contentY+height <= r.y+r.height)
contentY = r.y+r.height-height;
}
</code>


=== Комбинирање на компонентите за текст едиторот ===
=== Комбинирање на компонентите за текст едиторот ===
Line 149: Line 285:
Сега ние сме спремни да креираме распоред на нашиот текст едитор користејќи QML. Текст едиторот има две компоненти, мени лента која што ја креиравме и текстуална област. QML овозможува повторно користење на компонентите, а со тоа правејќи го нашиот код полесен, со импортирање компоненти и прилагодувајќи ги ако е потребно. Нашиот текст едитор го разделува прозорот на два дела; една третина на екранот е посветен на мени лентата, а другите две третини на екранот е текстуалната област. Мени лентата се прикажува пред другите компоненти.
Сега ние сме спремни да креираме распоред на нашиот текст едитор користејќи QML. Текст едиторот има две компоненти, мени лента која што ја креиравме и текстуална област. QML овозможува повторно користење на компонентите, а со тоа правејќи го нашиот код полесен, со импортирање компоненти и прилагодувајќи ги ако е потребно. Нашиот текст едитор го разделува прозорот на два дела; една третина на екранот е посветен на мени лентата, а другите две третини на екранот е текстуалната област. Мени лентата се прикажува пред другите компоненти.


<code><br />Rectangle{
<code>
Rectangle{


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


//екранот е поделен на MenuBar и TextArea. 1/3 од екранот е доделен на MenuBar<br /> property int partition: height/3
//екранот е поделен на MenuBar и TextArea. 1/3 од екранот е доделен на MenuBar
property int partition: height/3


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


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


Со импортирање на повторно употребливи компоненти, кодот на нашиот ''TextEditor'' изгледа многу поедноставно. Ние потоа можеме да ја прилагодиме главната апликација, без да се секираме за својствата кои имаат дефинирани однесувања. Со користење на овој пристап, распоредите на апликацијата и UI компонентите може лесно да се креираат.
Со импортирање на повторно употребливи компоненти, кодот на нашиот ''TextEditor'' изгледа многу поедноставно. Ние потоа можеме да ја прилагодиме главната апликација, без да се секираме за својствата кои имаат дефинирани однесувања. Со користење на овој пристап, распоредите на апликацијата и UI компонентите може лесно да се креираат.
Line 169: Line 322:
Нашиот текст едитор изгледа едноставно и ние имаме потреба да го декорираме. Користејќи QML, можеме да декларираме транзиции и да го анимираме нашиот текст едитор. Нашата мени лента опфаќа една третина од екранот и би било фино да се појави тогаш кога ние сакаме.
Нашиот текст едитор изгледа едноставно и ние имаме потреба да го декорираме. Користејќи QML, можеме да декларираме транзиции и да го анимираме нашиот текст едитор. Нашата мени лента опфаќа една третина од екранот и би било фино да се појави тогаш кога ние сакаме.


Можеме да додадеме фиока интерфејс, кој би ја собирал и ширел мени лентата кога е кликнат. Во нашата имплементација, ние имаме тенок правоаголник кој реагира на кликови на глувчето. ''drawer'', како и апликацијата, имаат две состојби: „фиоката отворена“ состојба и „фиоката затворена“ состојба. ''drawer'' елементот е лента од правоаголникот со мала висина. Постои и вгнезден &quot;Image&amp;quot;:http://doc.qt.nokia.com/4.7/qml-image.html елемент деклариран така да иконата со стрелка биде центрирана внатре во фиоката. Фиоката доделува состојба на целата апликација, со идентификатор ''screen'', било кога корисникот ќе кликна на областа на глувчето.
Можеме да додадеме фиока интерфејс, кој би ја собирал и ширел мени лентата кога е кликнат. Во нашата имплементација, ние имаме тенок правоаголник кој реагира на кликови на глувчето. ''drawer'', како и апликацијата, имаат две состојби: „фиоката отворена“ состојба и „фиоката затворена“ состојба. ''drawer'' елементот е лента од правоаголникот со мала висина. Постои и вгнезден [http://doc.qt.nokia.com/4.7/qml-image.html Image] елемент деклариран така да иконата со стрелка биде центрирана внатре во фиоката. Фиоката доделува состојба на целата апликација, со идентификатор ''screen'', било кога корисникот ќе кликна на областа на глувчето.


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


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


MouseArea{<br /> id: drawerMouseArea<br /> anchors.fill:parent<br /> onClicked:{<br /> if (screen.state  &amp;quot;DRAWER_CLOSED&amp;quot;)&amp;#123;
MouseArea{
                     screen.state = &amp;quot;DRAWER_OPEN&amp;quot;
id: drawerMouseArea
                 &amp;#125;
anchors.fill:parent
                 else if (screen.state  &quot;DRAWER_OPEN&amp;quot;){<br /> screen.state = &quot;DRAWER_CLOSED&amp;quot;<br /> }<br /> }<br /> <br /> }<br /> }<br /></code>
onClicked:{
if (screen.state  "DRAWER_CLOSED"){
                     screen.state = "DRAWER_OPEN"
                 }
                 else if (screen.state  "DRAWER_OPEN"){
screen.state = "DRAWER_CLOSED"
}
}
}
}
</code>


Состојба (state) е едноставно колекција на конфигурации и се декларира со &quot;State&amp;quot;:http://doc.qt.nokia.com/4.7/qml-state.html елементот. Листа на состојби може да бидат листани и врзани за ''states'' својството. Во нашата апликација, две состојби се наречени ''DRAWER_CLOSED'' и ''DRAWER_OPEN''. Конфигурациите на елементите се декларирани во &quot;PropertyChanges&amp;quot;:http://doc.qt.nokia.com/4.7/qml-propertychanges.html елементите. Во ''DRAWER_OPEN'' состојбата, постојат четири елементи кои ќе примат промени на својствата. Првиот таргет, ''menuBar'', ќе го промени своето y својство во 0. Слично, ''textArea'' ќе оди на пониска нова позиција кога состојбата е ''DRAWER_OPEN''. ''textArea'', ''drawer'', и иконата на фиоката ќе ги менат своите својства за да ја задоволат моменталната состојба.
Состојба (state) е едноставно колекција на конфигурации и се декларира со [http://doc.qt.nokia.com/4.7/qml-state.html State] елементот. Листа на состојби може да бидат листани и врзани за ''states'' својството. Во нашата апликација, две состојби се наречени ''DRAWER_CLOSED'' и ''DRAWER_OPEN''. Конфигурациите на елементите се декларирани во [http://doc.qt.nokia.com/4.7/qml-propertychanges.html PropertyChanges] елементите. Во ''DRAWER_OPEN'' состојбата, постојат четири елементи кои ќе примат промени на својствата. Првиот таргет, ''menuBar'', ќе го промени своето y својство во 0. Слично, ''textArea'' ќе оди на пониска нова позиција кога состојбата е ''DRAWER_OPEN''. ''textArea'', ''drawer'', и иконата на фиоката ќе ги менат своите својства за да ја задоволат моменталната состојба.


<code><br />states:[<br /> State {<br /> name: &quot;DRAWER_OPEN&amp;quot;<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: &quot;DRAWER_CLOSED&amp;quot;<br /> PropertyChanges { target: menuBar; y:<s>height; }<br /> PropertyChanges { target: textArea; y: drawer.height; height: screen.height</s> drawer.height}<br /> PropertyChanges { target: drawer; y: 0 }<br /> PropertyChanges { target: arrowIcon; rotation: 0 }<br /> }<br /> ]<br /></code>
<code>
states:[
State {
name: "DRAWER_OPEN"
PropertyChanges { target: menuBar; y: 0}
PropertyChanges { target: textArea; y: partition + drawer.height}
PropertyChanges { target: drawer; y: partition}
PropertyChanges { target: arrowIcon; rotation: 180}
},
State {
name: "DRAWER_CLOSED"
PropertyChanges { target: menuBar; y:-height; }
PropertyChanges { target: textArea; y: drawer.height; height: screen.height- drawer.height}
PropertyChanges { target: drawer; y: 0 }
PropertyChanges { target: arrowIcon; rotation: 0 }
}
]
</code>


Промените на состојбите се нагли и имаат потреба од помеки транзиции. Транзициите помеѓу својствата се дефинирани со &quot;Transition&amp;quot;:http://doc.qt.nokia.com/4.7/qml-transition.html елементот, кој може да е врзан за ''transitions'' својството. Нашиот текст едитор има транзиција било кога состојбата се менува од/во ''DRAWER_OPEN'' или од/во ''DRAWER_CLOSED''. Поважно, транзицијата има потреба од ''from'' и ''to'' состојба но за нашите транзиции, можеме да користиме џокер * симбол да обележиме дека транзициите се однесуваат на сите промени на состојбите.
Промените на состојбите се нагли и имаат потреба од помеки транзиции. Транзициите помеѓу својствата се дефинирани со [http://doc.qt.nokia.com/4.7/qml-transition.html Transition] елементот, кој може да е врзан за ''transitions'' својството. Нашиот текст едитор има транзиција било кога состојбата се менува од/во ''DRAWER_OPEN'' или од/во ''DRAWER_CLOSED''. Поважно, транзицијата има потреба од ''from'' и ''to'' состојба но за нашите транзиции, можеме да користиме џокер * симбол да обележиме дека транзициите се однесуваат на сите промени на состојбите.


Во текот на транзициите, можеме да доделиме анимации на промените на својствата. Нашиот ''menuBar'' ја менува позицијата од ''y:0'' во ''y:-partition'' и ние можеме да ја анимираме оваа транзиција со користење на &quot;''NumberAnimation''&quot;:http://doc.qt.nokia.com/4.7/qml-numberanimation.html елементот. Ние ги декларираме кои својства ќе се анимираат за одредено времетраење и со која одредена транзициона крива (easing curve). Кривата ја контролира стапката на анимација и интерполациското однесување во текот на транзицијата. Кривата што ја одбравме е &quot;Easing.OutQuint&amp;quot;:http://doc.qt.nokia.com/4.7/qml-propertyanimation.html#easing.type-prop, која го успорува движењето близу крајот на анимацијата. Прочитајте ја &quot;статијата&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html за QML анимациите.
Во текот на транзициите, можеме да доделиме анимации на промените на својствата. Нашиот ''menuBar'' ја менува позицијата од ''y:0'' во ''y:-partition'' и ние можеме да ја анимираме оваа транзиција со користење на [http://doc.qt.nokia.com/4.7/qml-numberanimation.html ''NumberAnimation''] елементот. Ние ги декларираме кои својства ќе се анимираат за одредено времетраење и со која одредена транзициона крива (easing curve). Кривата ја контролира стапката на анимација и интерполациското однесување во текот на транзицијата. Кривата што ја одбравме е [http://doc.qt.nokia.com/4.7/qml-propertyanimation.html#easing.type-prop Easing.OutQuint], која го успорува движењето близу крајот на анимацијата. Прочитајте ја [http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html статијата] за QML анимациите.


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


Друг начин за анимирање на промени на својствата е со декларирање на &quot;Behavior&amp;quot;:http://doc.qt.nokia.com/4.7/qml-behavior.html елементот. Транзицијата работи дури има промена на состојбата и ''Behavior'' може да ја сетира анимацијата за генерална промена на својството. Во текст едиторот, стрелката има ''NumberAnimation'' анимирајќи го ''rotation'' својството било кога својството ќе се промени.
Друг начин за анимирање на промени на својствата е со декларирање на [http://doc.qt.nokia.com/4.7/qml-behavior.html Behavior] елементот. Транзицијата работи дури има промена на состојбата и ''Behavior'' може да ја сетира анимацијата за генерална промена на својството. Во текст едиторот, стрелката има ''NumberAnimation'' анимирајќи го ''rotation'' својството било кога својството ќе се промени.


<code><br />In TextEditor.qml:
<code>
In TextEditor.qml:


Behavior{<br /> NumberAnimation{property: &quot;rotation&amp;quot;;easing.type: Easing.OutExpo }<br /> }<br /></code>
Behavior{
NumberAnimation{property: "rotation";easing.type: Easing.OutExpo }
}
</code>


Кога ќе се вратиме на нашите компоненти со познавање на состојби и анимации, може да го подобриме изгледот на компонентите. Во Button.qml ќе додадеме ''color'' и ''scale'' промени на својства кога копчето е притиснато. Бојата се анимира со користење на &quot;ColorAnimation&amp;quot;:http://doc.qt.nokia.com/4.7/qml-coloranimation.html и бројките се анимираат со користење на &quot;NumberAnimation&amp;quot;:http://doc.qt.nokia.com/4.7/qml-numberanimation.html. ''on propertyName'' синтаксата подолу помага кога се таргетира единечно својство.
Кога ќе се вратиме на нашите компоненти со познавање на состојби и анимации, може да го подобриме изгледот на компонентите. Во Button.qml ќе додадеме ''color'' и ''scale'' промени на својства кога копчето е притиснато. Бојата се анимира со користење на [http://doc.qt.nokia.com/4.7/qml-coloranimation.html ColorAnimation] и бројките се анимираат со користење на [http://doc.qt.nokia.com/4.7/qml-numberanimation.html NumberAnimation]. ''on propertyName'' синтаксата подолу помага кога се таргетира единечно својство.


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


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


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


Додатно, можеме да го подобриме изгледот на нашите QML компоненти со додавање колор ефекти како што се градиенти или транспаретност. Декларирањето на &quot;Gradient&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gradient.html елементот ќе го надреди ''color'' својството на елементот. Можете да декларирате боја во градиентот со користење на &quot;GradientStop&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gradientstop.html елементот. Градиентот е позициониран со користење на скала, од 0.0 до 1.0.
Додатно, можеме да го подобриме изгледот на нашите QML компоненти со додавање колор ефекти како што се градиенти или транспаретност. Декларирањето на [http://doc.qt.nokia.com/4.7/qml-gradient.html Gradient] елементот ќе го надреди ''color'' својството на елементот. Можете да декларирате боја во градиентот со користење на [http://doc.qt.nokia.com/4.7/qml-gradientstop.html GradientStop] елементот. Градиентот е позициониран со користење на скала, од 0.0 до 1.0.


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


Градиентот е искористен во мени лентата за да симулира длабочина. Првата боја стартува од 0.0 а последната на 1.0.
Градиентот е искористен во мени лентата за да симулира длабочина. Првата боја стартува од 0.0 а последната на 1.0.
Line 213: Line 427:


Ние го завршивме градењето на кориснички интерфејс на едноставен текст едитор. Одејќи нанапред, корисничкиот интерфејс е имплементиран, и можеме да имплементираме логика на апликацијата со користење на регуларен Qt и C+''. QML работи добро како прототипна алатка, одвојувајќи ја логиката на апликацијата од UI дизајнот.  
Ние го завршивме градењето на кориснички интерфејс на едноставен текст едитор. Одејќи нанапред, корисничкиот интерфејс е имплементиран, и можеме да имплементираме логика на апликацијата со користење на регуларен Qt и C+''. QML работи добро како прототипна алатка, одвојувајќи ја логиката на апликацијата од UI дизајнот.  
<br />[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor4_texteditor.png|Текст едитор]]
<br />h2. Проширување на QML со користење на Qt C''+


Сега кога го имаме распоредот на нашиот текст едитор, ние можеме да имплементираме додатни функционалности во C+''. Користење на QML со C''+ ни овозможува да ја креираме апликациската логика со користење на Qt. Можеме да креираме QML контекст во C++ апликација со користење на &quot;декларативните класи на Qt&amp;quot;:http://doc.qt.nokia.com/4.7/qtbinding.html и да прикажеме QML елементи користејќи графичка сцена (Graphics Scene). Алтернативно, можеме да го експортираме C++ кодот во дополнителна компонента (plugin) кој &quot;qmlviewer&amp;quot;:http://doc.qt.nokia.com/4.7/qmlviewer.html алатката може да ја прочита. За нашата апликација, ќе имплементираме функции на вчитување и снимање во C++ и ќе ги експортираме како плагин. На овој начин, нас ни е доволно да го вчитаме QML фајлот директно наместо да го стартуваме како апликација.
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor4_texteditor.png|Текст едитор]]
 
== Проширување на QML со користење на Qt C''+ ==
Сега кога го имаме распоредот на нашиот текст едитор, ние можеме да имплементираме додатни функционалности во C+''. Користење на QML со C''+ ни овозможува да ја креираме апликациската логика со користење на Qt. Можеме да креираме QML контекст во C++ апликација со користење на [http://doc.qt.nokia.com/4.7/qtbinding.html декларативните класи на Qt] и да прикажеме QML елементи користејќи графичка сцена (Graphics Scene). Алтернативно, можеме да го експортираме C++ кодот во дополнителна компонента (plugin) кој [http://doc.qt.nokia.com/4.7/qmlviewer.html qmlviewer] алатката може да ја прочита. За нашата апликација, ќе имплементираме функции на вчитување и снимање во C++ и ќе ги експортираме како плагин. На овој начин, нас ни е доволно да го вчитаме QML фајлот директно наместо да го стартуваме како апликација.


=== Изложување на C++ класите во QML ===
=== Изложување на C++ класите во QML ===
Line 225: Line 440:


# ''Directory'' класа која ќе се справува со директориумите
# ''Directory'' класа која ќе се справува со директориумите
# ''File'' класа која е &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html, што ќе симулира листа на фајлови во директориум
# ''File'' класа која е [http://doc.qt.nokia.com/4.7/qobject.html QObject], што ќе симулира листа на фајлови во директориум
# плагин класа која ќе регистрира класа во QML контекстот
# плагин класа која ќе регистрира класа во QML контекстот
# Qt проект фајл кој ќе го компајлира плагинот
# Qt проект фајл кој ќе го компајлира плагинот
Line 234: Line 449:
За да се изгради плагинот, мораме следниве работи да ги сетираме во Qt проект фајлот. Прво, неопходните сорсови, заглавја, и Qt модули треба да се додадат во нашиот проект фајл. Сиот C++ код и проект фајлови се во ''filedialog'' директориумот.
За да се изгради плагинот, мораме следниве работи да ги сетираме во Qt проект фајлот. Прво, неопходните сорсови, заглавја, и Qt модули треба да се додадат во нашиот проект фајл. Сиот C++ код и проект фајлови се во ''filedialog'' директориумот.


<code><br />Во cppPlugins.pro:
<code>
Во cppPlugins.pro:
 
TEMPLATE = lib
CONFIG ''= qt plugin
QT''= declarative


TEMPLATE = lib<br /> CONFIG ''= qt plugin<br /> QT''= declarative
DESTDIR ''= ../plugins
OBJECTS_DIR = tmp
MOC_DIR = tmp


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


SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp<br /></code>
HEADERS''= directory.h  file.h  dialogPlugin.h
 
SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp
</code>


Конкретно, компајлираме со ''declarative'' модулот и го конфигурираме како ''plugin'', на што му треба ''lib'' шаблонот (template). Ќе го ставиме компајлираниот плагин во родителот на ''plugins'' директориум.
Конкретно, компајлираме со ''declarative'' модулот и го конфигурираме како ''plugin'', на што му треба ''lib'' шаблонот (template). Ќе го ставиме компајлираниот плагин во родителот на ''plugins'' директориум.
Line 248: Line 471:
=== Регистрирање на класа во QML ===
=== Регистрирање на класа во QML ===


<code><br /> Во dialogPlugin.h:
<code>
Во dialogPlugin.h:


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


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


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


};<br /></code>
};
</code>


Во нашата плагин класа, ''DialogPlugin'' e подкласа на &quot;QDeclarativeExtensionPlugin&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html. Треба да имплементираме наследената функција, &quot;registerTypes()&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes. ''dialogPlugin.cpp'' изгледа вака:
Во нашата плагин класа, ''DialogPlugin'' e подкласа на [http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html QDeclarativeExtensionPlugin]. Треба да имплементираме наследената функција, [http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registerTypes()]. ''dialogPlugin.cpp'' изгледа вака:


<code><br />DialogPlugin.cpp:
<code>
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;
#include "dialogPlugin.h"
#include "directory.h"
#include "file.h"
#include <qdeclarative.h>


void DialogPlugin::registerTypes(const char '''uri){
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 />&quot;registerTypes()&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes функцијата ги регистрира нашите File и Directory класи во QML. На оваа функција и потребно името на класата за нејзиниот шаблон, броевите на верзијата, и името на нашите класи.
<br />Треба да го експортираме плагинот со користење на &quot;Q_EXPORT_PLUGIN2&amp;quot;:http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2#q-export-plugin2 макрото. Да се забележи дека во нашиот ''dialogPlugin.h'', мора да имаме &quot;Q_OBJECT&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT макро на врвот на нашата класа. Исто така, мораме да го стартуваме ''qmake'' на нашиот проект фајл за да се генерира неопходниот мета-објектен код.
<br />h3. Креирање на QML својства во C++ класа
<br />Можеме да креираме QML елементи и својства со користење на C++ и &quot;мета-објектниот систем&amp;quot;:http://doc.qt.nokia.com/4.7/metaobjects.html. Можеме да имплементираме својства користејќи слотови и сигнали, правејќи Qt да е свесно за овие својства. Овие својства може да се употребат во QML.
<br />За нашиот текст едитор, нас ни треба да можеме да вчитуваме и снимаме фајлови. Типично, вакви карактерстики се содржани во фајл дијалог. За наша среќа, можеме да ги користиме &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 за да имплементираме читање на директориум и влезни/излезни текови (streams).
<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 />''Directory'' класата користи мета-објектен систем за да ги регистрира потребните својства за да постигне справување со фајловите. ''Directory'' класата е експортирана како плагин и е употреблива во QML како ''Directory'' елемент. Секој од излистаните својства го користи &quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY макрото и е истовремено QML својство.
<br />&quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY декларира својство, како и функциите за читање и запишување во мета-објектниот систем. На пример, ''filename'' својството, од типот &quot;QString&amp;quot;:http://doc.qt.nokia.com/4.7/qstring.html може да се чита користејќи ја ''filename()'' функцијата и може да се запишува користејќи ја ''setFilename()'' функцијата. Додатно, постои сигнал асоциран со filename својството наречен ''filenameChanged()'', кој се емитира кога својството ќе се промени, Функциите за читање и запишување се декларирани како ''public'' во заглавјето.
<br />Слично, ние имаме други својства декларирани според нивната употреба. ''filesCount'' својството го покажува бројот на фајлови во директориумот. filename својството е сетирано на моменталниот селектиран фајл и вчитувањето/снимањето на содржината на фајлот е во ''fileContent'' својството.
<br /><code><br />Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )<br /></code>
<br />''files'' својството е листа на сите филтрирани фајлови во директориумот. ''Directory'' класата е имплементирана за да ги филтрира невалидните текст фајлови; фајловите со екстензија ''.txt'' се валидни. Понатаму, &quot;QList&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html класите можат да бидат користени во QML фајловите декларирајќи ги како &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html во C+''. Шаблонизираниот објект мора да наследува од &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html, затоа, ''File'' класата мора да наследува од &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html. Во ''Directory'' класата, листата на ''File'' објекти се чуваат во &quot;QList&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html наречено ''m_fileList''.
<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 />Својствата потоа може да бидат користени во QML како дел од ''Directory'' својствата. Да се забележи дека ние не креиравме својство индентификатор ''id'' во нашиот C''+ код.
<br /><code><br /> Directory{<br /> id: directory
<br /> filesCount<br /> filename<br /> fileContent<br /> files
<br /> files[0].name<br /> }<br /></code>
<br />Бидејќи QML користи Javascript синтакса и структура, ние можеме да итерираме низ листата на фајлови и да ги превземеме нивните својства. Да се превземе својството име на првиот фајл, ние повикуваме ''files[0].name''.
<br />Регуларните C++ функции исто така се пристапни во QML. Функциите на вчитување и снимање на фајлови се имплементирано во C++ и декларирани користејќи го &quot;Q_INVOKABLE&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE макрото. Алтернативно, можеме да декларираме функции како слот и тие функции ќе бидат пристапни во QML.
<br /><code><br /> Во 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 />''Directory'' класата исто така мора да ги извести другите објекти кога и да има промена содржината на директориумот. Оваа особеност се прави со користење на ''signal''. Како што спомнавме претходно, QML сигналите имаат соодветен справувач каде нивните имиња имаат префикс ''on''. Сигналот се нарекува ''directoryChanged'' и се емитира кога и да има освежување на директориумот. Освежувањето едноставно ја вчитува повторно содржината на директориумот и ја освежува листата на валидни фајлови во директориумот. QML елементите потоа можат да бидат известени со закачување на акцијата во ''onDirectoryChanged'' справувачот на сигнал.
<br />''list'' својствата треба да се истражат повеќе. Ова е потрено затоа што листа својствата користат обратни повици (callbacks) за пристап и модификација на содржината на листата. Листа својството е од типот ''QDeclarativeListProperty&amp;lt;File&amp;gt;''. Кога ќе се пристапи на листата, акцесор функција (accessor function) треба да врати ''QDeclarativeListProperty&amp;lt;File&amp;gt;''. Типот на шаблон, ''File'', мора да е наследува од ''QObject''. Понатаму, за да се креира &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html, акцесорот на листата и модификаторите треба да бидат предадени во конструкторот како функциски поинтери. Листата, ''QList'' во нашиот случај, исто така мора да е листа од ''File'' поинтери.
<br />Конструкторот на &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html и ''Directory'' имплементацијата:
<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>


Конструкторот ги предава поинтерите кон функции кои ќе додаваат на листата, бројат на листата, да се добие елемент со користење на индекс, и да се испразни листата. Само функцијата за додавање е мандаторна. Да се примети дека функциските поинтери мора да одговара на дефиницијата на &quot;AppendFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AppendFunction-typedef, &quot;CountFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#CountFunction-typedef, &quot;AtFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AtFunction-typedef, или &quot;ClearFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef.
qmlRegisterType<Directory>(uri, 1, 0, "Directory");
qmlRegisterType<File>(uri, 1, 0,"File");
}
 
Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);
</code>
 
[http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registerTypes()] функцијата ги регистрира нашите File и Directory класи во QML. На оваа функција и потребно името на класата за нејзиниот шаблон, броевите на верзијата, и името на нашите класи.
 
Треба да го експортираме плагинот со користење на [http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2#q-export-plugin2 Q_EXPORT_PLUGIN2] макрото. Да се забележи дека во нашиот ''dialogPlugin.h'', мора да имаме [http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT Q_OBJECT] макро на врвот на нашата класа. Исто така, мораме да го стартуваме ''qmake'' на нашиот проект фајл за да се генерира неопходниот мета-објектен код.
 
=== Креирање на QML својства во C++ класа ===
Можеме да креираме QML елементи и својства со користење на C++ и [http://doc.qt.nokia.com/4.7/metaobjects.html мета-објектниот систем]. Можеме да имплементираме својства користејќи слотови и сигнали, правејќи Qt да е свесно за овие својства. Овие својства може да се употребат во QML.
 
За нашиот текст едитор, нас ни треба да можеме да вчитуваме и снимаме фајлови. Типично, вакви карактерстики се содржани во фајл дијалог. За наша среќа, можеме да ги користиме [http://doc.qt.nokia.com/4.7/qdir.html QDir], [http://doc.qt.nokia.com/4.7/qfile.html QFile] и [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] за да имплементираме читање на директориум и влезни/излезни текови (streams).
 
<code>
class Directory : public QObject{
 
Q_OBJECT
 
Q_PROPERTY(int filesCount READ filesCount CONSTANT)
Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)
Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)
Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )
 
</code>
 
''Directory'' класата користи мета-објектен систем за да ги регистрира потребните својства за да постигне справување со фајловите. ''Directory'' класата е експортирана како плагин и е употреблива во QML како ''Directory'' елемент. Секој од излистаните својства го користи [http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY Q_PROPERTY] макрото и е истовремено QML својство.
 
[http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY Q_PROPERTY] декларира својство, како и функциите за читање и запишување во мета-објектниот систем. На пример, ''filename'' својството, од типот [http://doc.qt.nokia.com/4.7/qstring.html QString] може да се чита користејќи ја ''filename()'' функцијата и може да се запишува користејќи ја ''setFilename()'' функцијата. Додатно, постои сигнал асоциран со filename својството наречен ''filenameChanged()'', кој се емитира кога својството ќе се промени, Функциите за читање и запишување се декларирани како ''public'' во заглавјето.
 
Слично, ние имаме други својства декларирани според нивната употреба. ''filesCount'' својството го покажува бројот на фајлови во директориумот. filename својството е сетирано на моменталниот селектиран фајл и вчитувањето/снимањето на содржината на фајлот е во ''fileContent'' својството.
 
<code>
Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )
</code>
 
''files'' својството е листа на сите филтрирани фајлови во директориумот. ''Directory'' класата е имплементирана за да ги филтрира невалидните текст фајлови; фајловите со екстензија ''.txt'' се валидни. Понатаму, [http://doc.qt.nokia.com/4.7/qlist.html QList] класите можат да бидат користени во QML фајловите декларирајќи ги како [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty] во C+''. Шаблонизираниот објект мора да наследува од [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QObject], затоа, ''File'' класата мора да наследува од [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QObject]. Во ''Directory'' класата, листата на ''File'' објекти се чуваат во [http://doc.qt.nokia.com/4.7/qlist.html QList] наречено ''m_fileList''.
 
<code>
class File : public QObject{
 
Q_OBJECT
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
 
};
</code>
 
Својствата потоа може да бидат користени во QML како дел од ''Directory'' својствата. Да се забележи дека ние не креиравме својство индентификатор ''id'' во нашиот C''+ код.
 
<code>
Directory{
id: directory
 
filesCount
filename
fileContent
files
 
files[0].name
}
</code>
 
Бидејќи QML користи Javascript синтакса и структура, ние можеме да итерираме низ листата на фајлови и да ги превземеме нивните својства. Да се превземе својството име на првиот фајл, ние повикуваме ''files[0].name''.
 
Регуларните C++ функции исто така се пристапни во QML. Функциите на вчитување и снимање на фајлови се имплементирано во C++ и декларирани користејќи го [http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE Q_INVOKABLE] макрото. Алтернативно, можеме да декларираме функции како слот и тие функции ќе бидат пристапни во QML.
 
<code>
Во Directory.h:
 
Q_INVOKABLE void saveFile();
Q_INVOKABLE void loadFile();
</code>
 
''Directory'' класата исто така мора да ги извести другите објекти кога и да има промена содржината на директориумот. Оваа особеност се прави со користење на ''signal''. Како што спомнавме претходно, QML сигналите имаат соодветен справувач каде нивните имиња имаат префикс ''on''. Сигналот се нарекува ''directoryChanged'' и се емитира кога и да има освежување на директориумот. Освежувањето едноставно ја вчитува повторно содржината на директориумот и ја освежува листата на валидни фајлови во директориумот. QML елементите потоа можат да бидат известени со закачување на акцијата во ''onDirectoryChanged'' справувачот на сигнал.
 
''list'' својствата треба да се истражат повеќе. Ова е потрено затоа што листа својствата користат обратни повици (callbacks) за пристап и модификација на содржината на листата. Листа својството е од типот ''QDeclarativeListProperty<File>''. Кога ќе се пристапи на листата, акцесор функција (accessor function) треба да врати ''QDeclarativeListProperty<File>''. Типот на шаблон, ''File'', мора да е наследува од ''QObject''. Понатаму, за да се креира [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty], акцесорот на листата и модификаторите треба да бидат предадени во конструкторот како функциски поинтери. Листата, ''QList'' во нашиот случај, исто така мора да е листа од ''File'' поинтери.
 
Конструкторот на [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty] и ''Directory'' имплементацијата:
 
<code>
QDeclarativeListProperty ( QObject''' object, void * data, AppendFunction append, CountFunction count = 0, AtFunction at = 0, ClearFunction clear = 0 )
QDeclarativeListProperty<File>( this, &m_fileList, &appendFiles, &filesSize, &fileAt, &clearFilesPtr );
</code>
 
Конструкторот ги предава поинтерите кон функции кои ќе додаваат на листата, бројат на листата, да се добие елемент со користење на индекс, и да се испразни листата. Само функцијата за додавање е мандаторна. Да се примети дека функциските поинтери мора да одговара на дефиницијата на [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AppendFunction-typedef AppendFunction], [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#CountFunction-typedef CountFunction], [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AtFunction-typedef AtFunction], или [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef ClearFunction].


<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>
<code>
void appendFiles(QDeclarativeListProperty<File> * property, File * file)
File* fileAt(QDeclarativeListProperty<File> * property, int index)
int filesSize(QDeclarativeListProperty<File> * property)
void clearFilesPtr(QDeclarativeListProperty<File> *property)
</code>


За да го поедноставиме нашиот фајл дијалог, ''Directory'' класата ги филтрира сите невалидни текст фајлови, фајлови кои немаат ''.txt'' екстензија. Ако фајлот нема ''.txt'' екстензија, тогаш нема да прикажан на нашиот дијалог. Исто така, имплементацијата се осигурува да снимените фајлови имаат ''.txt'' екстензија. ''Directory'' користи &quot;QTextStream&amp;quot;:http://doc.qt.nokia.com/4.7/qtextstream.html за читање на фајлот и запишување на содржината во фајлот.
За да го поедноставиме нашиот фајл дијалог, ''Directory'' класата ги филтрира сите невалидни текст фајлови, фајлови кои немаат ''.txt'' екстензија. Ако фајлот нема ''.txt'' екстензија, тогаш нема да прикажан на нашиот дијалог. Исто така, имплементацијата се осигурува да снимените фајлови имаат ''.txt'' екстензија. ''Directory'' користи [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] за читање на фајлот и запишување на содржината во фајлот.


Со нашиот ''Directory'' елемент, можеме да ги земеме фајловите како листа, да знаеме колку текст фајлови има во директориумот, да се прочита името на фајлот и содржината како стринг, и да бидеме известени кога ќе има промени во содржината на директориумот.
Со нашиот ''Directory'' елемент, можеме да ги земеме фајловите како листа, да знаеме колку текст фајлови има во директориумот, да се прочита името на фајлот и содржината како стринг, и да бидеме известени кога ќе има промени во содржината на директориумот.
Line 311: Line 605:
qmlviewer алатката импортира фајлови кои се во истиот директориум како и апликацијата. Можеме исто така да креирамe ''qmldir'' фајл кој ќе содржи локации на QML фајлови кои сакаме да се импортираат. ''qmldir'' фајлот може да зачува локации на плагини и други ресурси.
qmlviewer алатката импортира фајлови кои се во истиот директориум како и апликацијата. Можеме исто така да креирамe ''qmldir'' фајл кој ќе содржи локации на QML фајлови кои сакаме да се импортираат. ''qmldir'' фајлот може да зачува локации на плагини и други ресурси.


<code><br /> Во qmldir:
<code>
Во qmldir:


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


plugin FileDialog plugins<br /></code>
plugin FileDialog plugins
</code>


Плагинот што ние го креиравме се нарекува ''FileDialog'', како што се гледа во ''TARGET'' полето во проектниот фајл. Компајлираниот плагин е во ''plugins'' директориум.
Плагинот што ние го креиравме се нарекува ''FileDialog'', како што се гледа во ''TARGET'' полето во проектниот фајл. Компајлираниот плагин е во ''plugins'' директориум.
Line 325: Line 625:
''Directory'' елементот е искористен во ''FileMenu.qml'' фајлот и го известува ''FileDialog'' елементот дека директориумот ја освежил својата содржина. Ова известување се извршува со справувач на сигнали, ''onDirectoryChanged''.
''Directory'' елементот е искористен во ''FileMenu.qml'' фајлот и го известува ''FileDialog'' елементот дека директориумот ја освежил својата содржина. Ова известување се извршува со справувач на сигнали, ''onDirectoryChanged''.


<code><br />Во FileMenu.qml:
<code>
Во FileMenu.qml:


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


Зачувувајќи ја едноставноста на нашата апликација, дијалогот секојпат ќе биде видлив, и нема да прикажува невалидни текст фајлови, кои немаат ''.txt'' екстензија на нивните имиња.
Зачувувајќи ја едноставноста на нашата апликација, дијалогот секојпат ќе биде видлив, и нема да прикажува невалидни текст фајлови, кои немаат ''.txt'' екстензија на нивните имиња.


<code><br />Во FileDialog.qml:
<code>
Во FileDialog.qml:


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


''FileDialog'' елементот ќе ја прикаже содржината на директориумот со читање на листа својството наречено ''files''. Фајловите се користат како модел во &quot;GridView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gridview.html елементот, кој прикажува податочни елементи во мрежа одредено од делегатот. Делегатот е одговорен за изгледот на моделот и нашиот дијалог едноставно ќе креира мрежа со текст центриран во средината. Со кликање на името на фајлот ќе резултира со појавување на правоаголник кој ќе го означи името на фајлот. ''FileDialog'' се известува кога ''notifyRefresh'' сигналот е емитиран, вчитувајќи ги повторно фајловите во директориумот.
''FileDialog'' елементот ќе ја прикаже содржината на директориумот со читање на листа својството наречено ''files''. Фајловите се користат како модел во [http://doc.qt.nokia.com/4.7/qml-gridview.html GridView] елементот, кој прикажува податочни елементи во мрежа одредено од делегатот. Делегатот е одговорен за изгледот на моделот и нашиот дијалог едноставно ќе креира мрежа со текст центриран во средината. Со кликање на името на фајлот ќе резултира со појавување на правоаголник кој ќе го означи името на фајлот. ''FileDialog'' се известува кога ''notifyRefresh'' сигналот е емитиран, вчитувајќи ги повторно фајловите во директориумот.


<code><br />В FileMenu.qml:
<code>
В 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 /></code>
Button{
id: newButton
label: "New"
onButtonClick:{
textArea.textContent = ""
}
}
Button{
id: loadButton
label: "Load"
onButtonClick:{
directory.filename = textInput.text
directory.loadFile()
textArea.textContent = directory.fileContent
}
}
Button{
id: saveButton
label: "Save"
onButtonClick:{
directory.fileContent = textArea.textContent
directory.filename = textInput.text
directory.saveFile()
}
}
Button{
id: exitButton
label: "Exit"
onButtonClick:{
Qt.quit()
}
}
</code>


Нашето ''FileMenu'' сега може да се поврзе со соодветните акции. ''saveButton'' ќе го пренесе текстот од ''TextEdit'' во ''fileContent'' својството на директориумот, потоа ќе го копира името на фајлот во влезен едитирачки текст. Конечно, копчето ја повикува ''saveFile&amp;amp;#40;&amp;#41;'' функција, снимајќи го со тоа фајлот. ''loadButton'' се извршува слично. Исто така, ''New'' акцијата ќе ја испразни содржината на ''TextEdit''.
Нашето ''FileMenu'' сега може да се поврзе со соодветните акции. ''saveButton'' ќе го пренесе текстот од ''TextEdit'' во ''fileContent'' својството на директориумот, потоа ќе го копира името на фајлот во влезен едитирачки текст. Конечно, копчето ја повикува ''saveFile()'' функција, снимајќи го со тоа фајлот. ''loadButton'' се извршува слично. Исто така, ''New'' акцијата ќе ја испразни содржината на ''TextEdit''.


Понатаму, ''EditMenu'' копчињата се конектирани со ''TextEdit'' функциите за копирање, лепење и селектирање на сиот текст во текст едиторот.
Понатаму, ''EditMenu'' копчињата се конектирани со ''TextEdit'' функциите за копирање, лепење и селектирање на сиот текст во текст едиторот.

Latest revision as of 16:12, 4 May 2015

This article may require cleanup to meet the Qt Wiki's quality standards. Reason: Auto-imported from ExpressionEngine.
Please improve this article if you can. Remove the {{cleanup}} tag and add this page to Updated pages list after it's clean.


Започнување на програмирање со QML

Добредојдовте во светот на QML, декларативниот UI јазик. Во овој почетнички водич, ќе создадеме едноставен текст едитор користејќи QML. По читањето на ова упаство, треба да бидете подготвени да развивате сопствена апликација со употреба на QML и Qt C+.

QML за градење на кориснички интерфејси

Апликацијата што ја градиме е едноставен текст едитор кој ќе вчитува, снима, и врши некаква текст манипулација. Овој водич ќе се состои од два дела. Првиот дел ќе вклучи дизајнирање на распоредот (layout) на апликацијата и однесување со користење на QML декларативниот јазик. За вториот дел, вчитување и снимање на фајлови ќе биде имплементирано со користење на Qt C. Со користење на Мета-Објектниот Систем, можеме да ги изложиме C+ функциите како својства (properties) што QML елементите можат да ги користат. Со користењето на QML и Qt C+, ние можеме ефикасно да ја одвоиме интерфејс логиката од апликациската логика.

QML текст едитор

За да се стартува QML кодот со примери, доволно е да се вклучи qmlviewer алатката заедно со QML фајлот како аргумент. C+ делот од овој туторијал претпоставува дека читателот има основни познавања на Qt компилациските процедури.

Дефинирање на копче и мени

Базична компонента - копче

Го започнуваме нашиот текст едитор со изградба на копче (button). Функционално, копчето има област сензитивна на глувче и етикета (label). Копчињата вршат дејствија кога корисникот ќе го притисне копчето.

Во QML, основниот визуелен елемент е Rectangle елементот. Rectangle (правоаголник) елементот има својства за контрола на изгледот и локацијата на елементот.

import Qt 4.7

Rectangle{
 id:simplebutton
 color: "grey"
 width: 150
 height: 80
 Text{
 id: buttonLabel
 text: "button label"
 anchors.centerIn: simplebutton;
 anchors.verticalCenterOffset: 1
 }
 }

Прво, import Qt 4.7 овозможува qmlviewer алатката да импортира QML елементи кои покасно ќе ги користиме. Оваа линија мора да постои во секој QML фајл. Забележете дека верзијата на Qt модулите е ставена во импорт изјавата.

Овој едноставен правоаголник има единствен идентификатор, simplebutton, кој е врзан за id својството. Својствата на Rect елементот се врзуваат на вредности со листање на својството, следено од две точки, потоа вредноста. Во ова парче код, бојата grey (сива) е врзана за својството color (боја) на правоаголникот. Слично, ги врзуваме width (ширина) и height (висина) на правоаголникот.

Тext елементот е текст поле без можност за едитирање. Го крстиме овој Text елемент buttonLabel. За да го поставите стрингот во Текст полето, ние ја врзуваме вредноста на text својството. Етикетата е во рамките на правоаголникот и со цел да ја центрираме во средината, ние доделуваме сидра (anchors) на Текст елементот на неговиот родител, кој се вика simplebutton. Сидрата може да се врзуваат на сидра на други елементи, дозволувајќи поедноставно доделување на распоредот.

Треба овој код да го снимиме како SimpleButton.qml. Стартувањето на qmlviewer со овој фајл како аргумент ќе прикаже сив правоаголник со текст етикета.

Simple Button

За имплементирање на клик функционалноста на копчето, можеме да користиме QML-овото справување со настани. Справувањето со настани во QML е доста сличен на Qt-овиот механизам на сигнали и слотови. Сигналите се емитираат и поврзаниот слот е повикан.

Rectangle{
 id:simplebutton
 
 MouseArea{
 id: buttonMouseArea
 anchors.fill: parent //усидри ги сите страни на областа на глушецот на сидрата на правоаголникот
 //сигналот onClicked ги справува валидните кликови на копчињата на глушецот
 onClicked: console.log(buttonLabel.text + " clicked" )
 }
 }

Го користиме MouseArea елементот во нашиот simplebutton. MouseArea елементите опишуваат интерактивна област каде движењата на глушецот се детектираат. За нашето копче, го усидруваме целиот MouseArea на неговиот родител, кој е simplebutton. синтаксата anchors.fill е еден начин на пристапување на специфично својство наречен fill внатре во групата на својства наречени anchors (сидра). QML користи распоред базиран на сидра каде елементите можат да се усидрат со други елементи, креирајќи робустни распореди.

MouseArea има многу справувачи со сигнали кои се повикуваат ако има движења на глушецот внатре во специфираните MouserArea граници. Еден од нив е onClicked и се повикува кога копчето на глушецот е кликнато, каде левиот клик е стандарден. Можеме да врземе акции на onClicked справувачот. Во нашиот пример, console.log() испишува текст кога областа на глувчето е кликната. Функцијата console.log() е корисна алатка за дебагирање и испишување текст.

Кодот во SimpleButton.qml е доволен да прикаже копче на екранот и да испише текст кога ќе се кликне на глувчето.

Rectangle {
 id:Button
 

property color buttonColor: "lightblue"
 property color onHoverColor: "gold"
 property color borderColor: "white"

signal buttonClick()
 onButtonClick: {
 console.log(buttonLabel.text + " clicked" )
 }

MouseArea{
 onClicked: buttonClick()
 hoverEnabled: true
 onEntered: parent.border.color = onHoverColor
 onExited: parent.border.color = borderColor
 }

//ја одредува бојата на копчето со користење на условниот оператор
 color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor
 }

Целосно функционално копче е во Button.qml. Некој код во оваа статија е испуштен, означено со три точки бидејќи тие биле претходно воведени во претходните секции или се ирелевантни за тековната дискусија.

Приспособените својства се декларираат со користење на property type name синтаксата. Во овој код, својството buttonColor, од типот color, е декларирано и врзано за вредноста "lightblue". buttonColor подоцна се користи во условна операција за да се одреди бојата со која ќе се исполни копчето. Да се забележи дека доделување на вредност на својството е можно со користење на = еднакво симболот, а врзување на вредноста со : две точки карактерот. Приспособените својства овозможуваат интерните елементи да бидат пристапни надвор од Rectangle опсегот (scope). Постојат основни QML типови на податоци како што се int, string, real како и тип наречен variant.

Врзувањето на onEntered и onExited справувачите на сигнали со боите овозможува границата на копчето да стане жолта кога глувчето лебди на копчето и ја враќа бојата кога глувчето ќе излезе од областа.

buttonClick() сигналот е деклариран во Button.qml со ставање на signal пред името на сигналот. Кај сите сигнали справувачите автоматски се креираат, нивните имиња стартуваат со on. Како резултат, onButtonClick е справувач на buttonClick. На onButtonClick потоа му се доделува акција за извршување. Во нашиот пример, onClicked справувачот едноставно ќе го повика onButtonClick, кој ќе прикаже текст. onButtonClick овозможува надворешни објекти едноставно да пристапат на Button областа на глувчето. На пример, елементите може да имаат повеќе од една MouseArea декларација и buttonClick сигналот може да направи разлика помеѓу неколку MouseArea справувачи со сигнал подобро.

Сега имаме основно познавање како да имплементираме елементи во QML кои можат да се справат со основните потези на глувчето. Креиравме Text етикета внатре во Rectangle, приспособувајќи ги нивните својства, и имплементиравме однесувања кои реагираат на движење на глувчето.

Копчето не е корисно освен ако не се користи како компонента која врши акција. Во наредната секција, ќе креираме мени кој ќе ги содржи овие копчиња.

button label

Креирање на страница со мени

До ова ниво, ние покривме како се креираат елементи и доделуваат однесување внатре во единечен QML фајл. Во оваа секција, ќе покажеме како да се импортираат QML елементи и како повторно да се искористат веќе креираните компоненти за да се изградат други компоненти.

Менито прикажува содржина на листа, секој елемент има можност да изврши одредена акција. Во QML, можеме да креираме мени на неколку начини. Прво, ќе креираме мени кое ќе содржи неколку копчиња кои евентуално би извршувале различни акции. Кодот за мени е во FileMenu.qml.

 import Qt 4.7 импортирање на главниот Qt QML модул
 import "folderName" импортирање на содржината на фолдерот
 import "script.js" as Script импортирање на Javascript фајл кој би се именувал како Script

Синтаксата прикажана горе покажува како се употребува import. Ова е потребно за користење на Javascript фајлови, или QML фајлови кои не се во истиот директориум. Бидејќи Button.qml е во ист директориум како и FileMenu.qml нема потреба да се импортира Button.qml за да се користи. Можеме директно да креираме Button елемент со декларирање на Button{}, слично на Rectangle декларацијата.

 В файле FileMenu.qml:

Row{
 anchors.centerIn: parent
 spacing: parent.width/6

Button{
 id: loadButton
 buttonColor: "lightgrey"
 label: "Load"
 }
 Button{
 buttonColor: "grey"
 id: saveButton
 label: "Save"
 }
 Button{
 id: exitButton
 label: "Exit"
 buttonColor: "darkgrey"

onButtonClick: Qt.quit()
 }
 }

Во FileMenu.qml, ние декларираме три Button елементи. Тие се декларирани внатре во Row елементот, позицинионер кој ќе ги позиционира неговите деца во вертикална линија. Button декларацијата останува во Button.qml, која е иста како и Button.qml што ја користевме во претходната секција. Нови врзувања на својствата може да бидат декларирани во новите креирани копчиња, ефективно пребришувајќи ги својствата сетирани во Button.qml. Копчето наречено exitButton ќе излезе и затвори прозорот кога е кликнато. Да се забележи дека справувачот со сигнали onButtonClick во Button.qml ќе биде повикан заедно со onButtonClick справувачот во exitButton.

filemenu

Row декларацијата е декларирана во Rectangle, креирајќи правоаголен контејнер за редица од копчиња. Овој додатен правоаголник креира индиректен начин на организирање на редица на копчиња внатре во менито.

Декларацијата на менито за едитирање е многу слична во оваа фаза. Менито има копчиња кои имаат етикети: Copy, Paste, и Select All.

editmenu

Вооружани со нашето знаење за импортирање и прилагодување на претходно направени компоненти, сега можеме да ги комбинираме овие страници со менија за да креираме мени лента, која ќе е составена од копчиња за селекција на менито, и да видиме како можеме да ги структуираме податоците со користење на QML.

Имплементирање на мени лента

Нашата апликација ќе има потреба некако да ги прикаже менијата со користење на мени лента. Мени лентата ќе префрли на различни менија и корисникот ќе може да одбере кое мени да се прикаже. Менувањето на менито имплицира дека менијата имаат потреба од нешто повеќе отколку само да се прикажуваат во редица. QML користи модели и прикази (views) за да ги структуира податоците и да прикаже структуирани податоци.

Користење на податочни модели и прикази

QML има различни податочни прикази кои прикажуваат "податочни модели"http://doc.qt.nokia.com/4.7/qdeclarativemodels.html. Нашата мени лента ќе ги прикажува менијата во листа, со заглавје кое прикажува редица на имиња на менијата. Листата на менијата се декларирани внатре во VisualItemModel. VisualItemModel елементот содржи елементи кои веќе имаат свои прикази како што се Rectangle елементите и импортираните UI елементи. Други типови на модели како што е ListModel елементот имаат потреба од делегат за да ги прикажуваат нивните податоци.

Декларираме два визуелни елементи во menuListModel, FileMenu и EditMenu. Ги прилагодуваме двете менија и ги прикажуваме со користење на ListView. MenuBar.qml фајлот содржи QML декларации и едноставно мени за едитирање е дефинирано во EditMenu.qml.

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

ListView елементот ќе го прикаже моделот во зависност од делегатот. Делегатот може да ги декларира елементите на моделот за прикажување во Row елемент или да ги прикаже елементите во мрежа. Нашето menuListModel веќе има видливи елементи, затоа, нема потреба од декларирање на делегат.

 ListView{
 id: menuListView

//сидрата се сетирани да реагираат на сидрата на прозорецот
 anchors.fill:parent
 anchors.bottom: parent.bottom
 width:parent.width
 height: parent.height

//моделот ги содржи податоците
 model: menuListModel

//контрола на движењето на менувањето на менито
 snapMode: ListView.SnapOneItem
 orientation: ListView.Horizontal
 boundsBehavior: Flickable.StopAtBounds
 flickDeceleration: 5000
 highlightFollowsCurrentItem: true
 highlightMoveDuration:240
 highlightRangeMode: ListView.StrictlyEnforceRange
 }

Додатно, ListView наследува од Flickable, овозможувајќи на листата да реагира на влечења на глувчето и други гестови. Последното парче на кодот погоре ги сетира Flickable својствата за да се создаде пожелно допирно (flicking) движење на нашиот приказ. Конкретно, својството highlightMoveDuration го менува времетраењето на допирната транзиција. Поголеми highlightMoveDuration вредности резултира со поспоро менување на менијата.

ListView ги одржува елементите на моделот преку index и секој визуелен елемент во моделот може да му се пристапи преку index, по редослед на декларацијата. Менувањето на currentIndex ефективно го менува нагласениот (highlighted) елемент во ListView. Заглавјето на нашата мени лента е пример на овој ефект. Постојат две копчиња во редица, двете го менуваат моментално мени кога се кликнати. fileButton го менува моменталното мени во мени за фајлови кога е кликнато, каде index станува 0 бидејќи FileMenu е декларирано прво во menuListModel. Слично, editButton ќе го промени менито во EditMenu кога е кликнато.

labelList правоаголникот има z вредност 1, означувајќи дека мора да се прикаже пред мени лентата. Елементите со поголема z вредност се прикажуваат пред елементите со помали z вредности. Стандардната вредност на z е 0.

 Rectangle{
 id: labelList
 
 z: 1
 Row{
 anchors.centerIn: parent
 spacing:40
 Button{
 label: "File"
 id: fileButton
 
 onButtonClick: menuListView.currentIndex = 0
 }
 Button{
 id: editButton%0 
 onButtonClick: menuListView.currentIndex = 1
 }
 }
 }

Мени лентата што ја креиравме може да се движи со допир за да се пристапи на менијата или со кликање на имињата на менијата. Менувањето на менијата е интуитивно и респонзивно.

мени лента

Градење на текст едитор

Декларирање на TextArea (текстуална област)

Нашиот текст едитор не е текст едитор ако не содржи област за едитирање на текстот. QML-овиот TextEdit елемент овозможува декларирање на мултилиниска област за едитирање на текст. TextEdit е различен од Text елементот, кој не дозволува на корисникот директно да го едитира текстот.

TextEdit{
 id: textEditor
 anchors.fill:parent
 width:parent.width; height:parent.height
 color:"midnightblue"
 focus: true

wrapMode: TextEdit.Wrap

onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)
 }

Својството на боја за фонтот е сетирано, исто така сетирано е текстот да се замотува (wrap). TextEdit областа е внатре во допирната (flickable) област која ќе го скролува текстот ако курсорот на текстот е надвор од видливата област. Функцијата ensureVisible() ќе провери дали правоаголникот на курсорот е надвор од видливите граници и ќе ја помести текстуалната област соодветно. QML користи Javascript синтакса за неговите скрипти, и како што беше претходно спомнато, Javascript фајловите може да бидат импортирани и користени внатре во QML фајлот.

function ensureVisible®{
 if (contentX >= r.x)
 contentX = r.x;
 else if (contentX+width <= r.x+r.width)
 contentX = r.x+r.width-width;
 if (contentY >= r.y)
 contentY = r.y;
 else if (contentY+height <= r.y+r.height)
 contentY = r.y+r.height-height;
 }

Комбинирање на компонентите за текст едиторот

Сега ние сме спремни да креираме распоред на нашиот текст едитор користејќи QML. Текст едиторот има две компоненти, мени лента која што ја креиравме и текстуална област. QML овозможува повторно користење на компонентите, а со тоа правејќи го нашиот код полесен, со импортирање компоненти и прилагодувајќи ги ако е потребно. Нашиот текст едитор го разделува прозорот на два дела; една третина на екранот е посветен на мени лентата, а другите две третини на екранот е текстуалната област. Мени лентата се прикажува пред другите компоненти.

Rectangle{

id: screen
 width: 1000; height: 1000

//екранот е поделен на MenuBar и TextArea. 1/3 од екранот е доделен на MenuBar
 property int partition: height/3

MenuBar{
 id:menuBar
 height: partition
 width:parent.width
 z: 1
 }

TextArea{
 id:textArea
 anchors.bottom:parent.bottom
 y: partition
 color: "white"
 height: partition*2
 width:parent.width
 }
 }

Со импортирање на повторно употребливи компоненти, кодот на нашиот TextEditor изгледа многу поедноставно. Ние потоа можеме да ја прилагодиме главната апликација, без да се секираме за својствата кои имаат дефинирани однесувања. Со користење на овој пристап, распоредите на апликацијата и UI компонентите може лесно да се креираат.

Едноставен едитор

Декорирање на текст едиторот

Имплементирање на фиока (drawer) интерфејс

Нашиот текст едитор изгледа едноставно и ние имаме потреба да го декорираме. Користејќи QML, можеме да декларираме транзиции и да го анимираме нашиот текст едитор. Нашата мени лента опфаќа една третина од екранот и би било фино да се појави тогаш кога ние сакаме.

Можеме да додадеме фиока интерфејс, кој би ја собирал и ширел мени лентата кога е кликнат. Во нашата имплементација, ние имаме тенок правоаголник кој реагира на кликови на глувчето. drawer, како и апликацијата, имаат две состојби: „фиоката отворена“ состојба и „фиоката затворена“ состојба. drawer елементот е лента од правоаголникот со мала висина. Постои и вгнезден Image елемент деклариран така да иконата со стрелка биде центрирана внатре во фиоката. Фиоката доделува состојба на целата апликација, со идентификатор screen, било кога корисникот ќе кликна на областа на глувчето.

Rectangle{
 id:drawer
 height:15

Image{
 id: arrowIcon
 source: "images/arrow.png"
 anchors.horizontalCenter: parent.horizontalCenter
 }

MouseArea{
 id: drawerMouseArea
 anchors.fill:parent
 onClicked:{
 if (screen.state  "DRAWER_CLOSED"){
                     screen.state = "DRAWER_OPEN"
                 }
                 else if (screen.state  "DRAWER_OPEN"){
 screen.state = "DRAWER_CLOSED"
 }
 }
 
 }
 }

Состојба (state) е едноставно колекција на конфигурации и се декларира со State елементот. Листа на состојби може да бидат листани и врзани за states својството. Во нашата апликација, две состојби се наречени DRAWER_CLOSED и DRAWER_OPEN. Конфигурациите на елементите се декларирани во PropertyChanges елементите. Во DRAWER_OPEN состојбата, постојат четири елементи кои ќе примат промени на својствата. Првиот таргет, menuBar, ќе го промени своето y својство во 0. Слично, textArea ќе оди на пониска нова позиција кога состојбата е DRAWER_OPEN. textArea, drawer, и иконата на фиоката ќе ги менат своите својства за да ја задоволат моменталната состојба.

states:[
 State {
 name: "DRAWER_OPEN"
 PropertyChanges { target: menuBar; y: 0}
 PropertyChanges { target: textArea; y: partition + drawer.height}
 PropertyChanges { target: drawer; y: partition}
 PropertyChanges { target: arrowIcon; rotation: 180}
 },
 State {
 name: "DRAWER_CLOSED"
 PropertyChanges { target: menuBar; y:-height; }
 PropertyChanges { target: textArea; y: drawer.height; height: screen.height- drawer.height}
 PropertyChanges { target: drawer; y: 0 }
 PropertyChanges { target: arrowIcon; rotation: 0 }
 }
 ]

Промените на состојбите се нагли и имаат потреба од помеки транзиции. Транзициите помеѓу својствата се дефинирани со Transition елементот, кој може да е врзан за transitions својството. Нашиот текст едитор има транзиција било кога состојбата се менува од/во DRAWER_OPEN или од/во DRAWER_CLOSED. Поважно, транзицијата има потреба од from и to состојба но за нашите транзиции, можеме да користиме џокер * симбол да обележиме дека транзициите се однесуваат на сите промени на состојбите.

Во текот на транзициите, можеме да доделиме анимации на промените на својствата. Нашиот menuBar ја менува позицијата од y:0 во y:-partition и ние можеме да ја анимираме оваа транзиција со користење на NumberAnimation елементот. Ние ги декларираме кои својства ќе се анимираат за одредено времетраење и со која одредена транзициона крива (easing curve). Кривата ја контролира стапката на анимација и интерполациското однесување во текот на транзицијата. Кривата што ја одбравме е Easing.OutQuint, која го успорува движењето близу крајот на анимацијата. Прочитајте ја статијата за QML анимациите.

transitions: [
 Transition {
 to: "*"
 NumberAnimation { target: textArea; properties: "y, height"; duration: 100; easing.type:Easing.OutExpo }
 NumberAnimation { target: menuBar; properties: "y"; duration: 100; easing.type: Easing.OutExpo }
 NumberAnimation { target: drawer; properties: "y"; duration: 100; easing.type: Easing.OutExpo }
 }
 ]

Друг начин за анимирање на промени на својствата е со декларирање на Behavior елементот. Транзицијата работи дури има промена на состојбата и Behavior може да ја сетира анимацијата за генерална промена на својството. Во текст едиторот, стрелката има NumberAnimation анимирајќи го rotation својството било кога својството ќе се промени.

In TextEditor.qml:

Behavior{
 NumberAnimation{property: "rotation";easing.type: Easing.OutExpo }
 }

Кога ќе се вратиме на нашите компоненти со познавање на состојби и анимации, може да го подобриме изгледот на компонентите. Во Button.qml ќе додадеме color и scale промени на својства кога копчето е притиснато. Бојата се анимира со користење на ColorAnimation и бројките се анимираат со користење на NumberAnimation. on propertyName синтаксата подолу помага кога се таргетира единечно својство.

In Button.qml:
 

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

scale: buttonMouseArea.pressed ? 1.1 : 1.00
 Behavior on scale { NumberAnimation{ duration: 55} }

Додатно, можеме да го подобриме изгледот на нашите QML компоненти со додавање колор ефекти како што се градиенти или транспаретност. Декларирањето на Gradient елементот ќе го надреди color својството на елементот. Можете да декларирате боја во градиентот со користење на GradientStop елементот. Градиентот е позициониран со користење на скала, од 0.0 до 1.0.

In MenuBar.qml
 gradient: Gradient {
 GradientStop { position: 0.0; color: "#8C8F8C" }
 GradientStop { position: 0.17; color: "#6A6D6A" }
 GradientStop { position: 0.98;color: "#3F3F3F" }
 GradientStop { position: 1.0; color: "#0e1B20" }
 }

Градиентот е искористен во мени лентата за да симулира длабочина. Првата боја стартува од 0.0 а последната на 1.0.

Што понатаму

Ние го завршивме градењето на кориснички интерфејс на едноставен текст едитор. Одејќи нанапред, корисничкиот интерфејс е имплементиран, и можеме да имплементираме логика на апликацијата со користење на регуларен Qt и C+. QML работи добро како прототипна алатка, одвојувајќи ја логиката на апликацијата од UI дизајнот.

Текст едитор

Проширување на QML со користење на Qt C+

Сега кога го имаме распоредот на нашиот текст едитор, ние можеме да имплементираме додатни функционалности во C+. Користење на QML со C+ ни овозможува да ја креираме апликациската логика со користење на Qt. Можеме да креираме QML контекст во C++ апликација со користење на декларативните класи на Qt и да прикажеме QML елементи користејќи графичка сцена (Graphics Scene). Алтернативно, можеме да го експортираме C++ кодот во дополнителна компонента (plugin) кој qmlviewer алатката може да ја прочита. За нашата апликација, ќе имплементираме функции на вчитување и снимање во C++ и ќе ги експортираме како плагин. На овој начин, нас ни е доволно да го вчитаме QML фајлот директно наместо да го стартуваме како апликација.

Изложување на C++ класите во QML

Ќе имплементираме вчитување и снимање на фајлови со користење на Qt и C+. C+ класите и функциите може да бидат користени во QML со нивно регистрирање. Класата е доволно да биде компајлирана како Qt плагин и на QML фајлот доволно ќе му биде каде е плагинот лоциран.

За нашата апликација, потребно е да се креираат следниве елементи:

  1. Directory класа која ќе се справува со директориумите
  2. File класа која е QObject, што ќе симулира листа на фајлови во директориум
  3. плагин класа која ќе регистрира класа во QML контекстот
  4. Qt проект фајл кој ќе го компајлира плагинот
  5. qmldir фајл кој ќе му каже на qmlviewer алатката каде да го најде плагинот

Градење на Qt плагин

За да се изгради плагинот, мораме следниве работи да ги сетираме во Qt проект фајлот. Прво, неопходните сорсови, заглавја, и Qt модули треба да се додадат во нашиот проект фајл. Сиот C++ код и проект фајлови се во filedialog директориумот.

Во cppPlugins.pro:

TEMPLATE = lib
 CONFIG ''= qt plugin
 QT''= declarative

DESTDIR ''= ../plugins
 OBJECTS_DIR = tmp
 MOC_DIR = tmp

 TARGET = FileDialog

 HEADERS''= directory.h  file.h  dialogPlugin.h

SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp

Конкретно, компајлираме со declarative модулот и го конфигурираме како plugin, на што му треба lib шаблонот (template). Ќе го ставиме компајлираниот плагин во родителот на plugins директориум.

Регистрирање на класа во QML

 Во dialogPlugin.h:

#include <QDeclarativeExtensionPlugin>

class DialogPlugin : public QDeclarativeExtensionPlugin
 {
 Q_OBJECT

public:
 void registerTypes(const char *uri);

};

Во нашата плагин класа, DialogPlugin e подкласа на QDeclarativeExtensionPlugin. Треба да имплементираме наследената функција, registerTypes(). dialogPlugin.cpp изгледа вака:

DialogPlugin.cpp:

#include "dialogPlugin.h"
 #include "directory.h"
 #include "file.h"
 #include <qdeclarative.h>

void DialogPlugin::registerTypes(const char '''uri){

 qmlRegisterType<Directory>(uri, 1, 0, "Directory");
 qmlRegisterType<File>(uri, 1, 0,"File");
 }

 Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);

registerTypes() функцијата ги регистрира нашите File и Directory класи во QML. На оваа функција и потребно името на класата за нејзиниот шаблон, броевите на верзијата, и името на нашите класи.

Треба да го експортираме плагинот со користење на Q_EXPORT_PLUGIN2 макрото. Да се забележи дека во нашиот dialogPlugin.h, мора да имаме Q_OBJECT макро на врвот на нашата класа. Исто така, мораме да го стартуваме qmake на нашиот проект фајл за да се генерира неопходниот мета-објектен код.

Креирање на QML својства во C++ класа

Можеме да креираме QML елементи и својства со користење на C++ и мета-објектниот систем. Можеме да имплементираме својства користејќи слотови и сигнали, правејќи Qt да е свесно за овие својства. Овие својства може да се употребат во QML.

За нашиот текст едитор, нас ни треба да можеме да вчитуваме и снимаме фајлови. Типично, вакви карактерстики се содржани во фајл дијалог. За наша среќа, можеме да ги користиме QDir, QFile и QTextStream за да имплементираме читање на директориум и влезни/излезни текови (streams).

 class Directory : public QObject{

 Q_OBJECT

 Q_PROPERTY(int filesCount READ filesCount CONSTANT)
 Q_PROPERTY(QString filename READ filename WRITE setFilename NOTIFY filenameChanged)
 Q_PROPERTY(QString fileContent READ fileContent WRITE setFileContent NOTIFY fileContentChanged)
 Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )

 

Directory класата користи мета-објектен систем за да ги регистрира потребните својства за да постигне справување со фајловите. Directory класата е експортирана како плагин и е употреблива во QML како Directory елемент. Секој од излистаните својства го користи Q_PROPERTY макрото и е истовремено QML својство.

Q_PROPERTY декларира својство, како и функциите за читање и запишување во мета-објектниот систем. На пример, filename својството, од типот QString може да се чита користејќи ја filename() функцијата и може да се запишува користејќи ја setFilename() функцијата. Додатно, постои сигнал асоциран со filename својството наречен filenameChanged(), кој се емитира кога својството ќе се промени, Функциите за читање и запишување се декларирани како public во заглавјето.

Слично, ние имаме други својства декларирани според нивната употреба. filesCount својството го покажува бројот на фајлови во директориумот. filename својството е сетирано на моменталниот селектиран фајл и вчитувањето/снимањето на содржината на фајлот е во fileContent својството.

Q_PROPERTY(QDeclarativeListProperty<File> files READ files CONSTANT )

files својството е листа на сите филтрирани фајлови во директориумот. Directory класата е имплементирана за да ги филтрира невалидните текст фајлови; фајловите со екстензија .txt се валидни. Понатаму, QList класите можат да бидат користени во QML фајловите декларирајќи ги како QDeclarativeListProperty во C+. Шаблонизираниот објект мора да наследува од QObject, затоа, File класата мора да наследува од QObject. Во Directory класата, листата на File објекти се чуваат во QList наречено m_fileList.

 class File : public QObject{

 Q_OBJECT
 Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)

 
 };

Својствата потоа може да бидат користени во QML како дел од Directory својствата. Да се забележи дека ние не креиравме својство индентификатор id во нашиот C+ код.

 Directory{
 id: directory

 filesCount
 filename
 fileContent
 files

 files[0].name
 }

Бидејќи QML користи Javascript синтакса и структура, ние можеме да итерираме низ листата на фајлови и да ги превземеме нивните својства. Да се превземе својството име на првиот фајл, ние повикуваме files[0].name.

Регуларните C++ функции исто така се пристапни во QML. Функциите на вчитување и снимање на фајлови се имплементирано во C++ и декларирани користејќи го Q_INVOKABLE макрото. Алтернативно, можеме да декларираме функции како слот и тие функции ќе бидат пристапни во QML.

 Во Directory.h:

 Q_INVOKABLE void saveFile();
 Q_INVOKABLE void loadFile();

Directory класата исто така мора да ги извести другите објекти кога и да има промена содржината на директориумот. Оваа особеност се прави со користење на signal. Како што спомнавме претходно, QML сигналите имаат соодветен справувач каде нивните имиња имаат префикс on. Сигналот се нарекува directoryChanged и се емитира кога и да има освежување на директориумот. Освежувањето едноставно ја вчитува повторно содржината на директориумот и ја освежува листата на валидни фајлови во директориумот. QML елементите потоа можат да бидат известени со закачување на акцијата во onDirectoryChanged справувачот на сигнал.

list својствата треба да се истражат повеќе. Ова е потрено затоа што листа својствата користат обратни повици (callbacks) за пристап и модификација на содржината на листата. Листа својството е од типот QDeclarativeListProperty<File>. Кога ќе се пристапи на листата, акцесор функција (accessor function) треба да врати QDeclarativeListProperty<File>. Типот на шаблон, File, мора да е наследува од QObject. Понатаму, за да се креира QDeclarativeListProperty, акцесорот на листата и модификаторите треба да бидат предадени во конструкторот како функциски поинтери. Листата, QList во нашиот случај, исто така мора да е листа од File поинтери.

Конструкторот на QDeclarativeListProperty и Directory имплементацијата:

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

Конструкторот ги предава поинтерите кон функции кои ќе додаваат на листата, бројат на листата, да се добие елемент со користење на индекс, и да се испразни листата. Само функцијата за додавање е мандаторна. Да се примети дека функциските поинтери мора да одговара на дефиницијата на AppendFunction, CountFunction, AtFunction, или ClearFunction.

 void appendFiles(QDeclarativeListProperty<File> * property, File * file)
 File* fileAt(QDeclarativeListProperty<File> * property, int index)
 int filesSize(QDeclarativeListProperty<File> * property)
 void clearFilesPtr(QDeclarativeListProperty<File> *property)

За да го поедноставиме нашиот фајл дијалог, Directory класата ги филтрира сите невалидни текст фајлови, фајлови кои немаат .txt екстензија. Ако фајлот нема .txt екстензија, тогаш нема да прикажан на нашиот дијалог. Исто така, имплементацијата се осигурува да снимените фајлови имаат .txt екстензија. Directory користи QTextStream за читање на фајлот и запишување на содржината во фајлот.

Со нашиот Directory елемент, можеме да ги земеме фајловите како листа, да знаеме колку текст фајлови има во директориумот, да се прочита името на фајлот и содржината како стринг, и да бидеме известени кога ќе има промени во содржината на директориумот.

За да се изгради плагинот, стартувајте го qmake на cppPlugins.pro проектниот фајл, потоа стартувајте го make за да се изгради и пренесе плагинот во plugins директориумот.

Импортирање на плагинот во QML

qmlviewer алатката импортира фајлови кои се во истиот директориум како и апликацијата. Можеме исто така да креирамe qmldir фајл кој ќе содржи локации на QML фајлови кои сакаме да се импортираат. qmldir фајлот може да зачува локации на плагини и други ресурси.

 Во qmldir:

Button ./Button.qml
 FileDialog ./FileDialog.qml
 TextArea ./TextArea.qml
 TextEditor ./TextEditor.qml
 EditMenu ./EditMenu.qml

plugin FileDialog plugins

Плагинот што ние го креиравме се нарекува FileDialog, како што се гледа во TARGET полето во проектниот фајл. Компајлираниот плагин е во plugins директориум.

Интегрирање на File Dialog во File Menu

Нашето FileMenu има потреба да го прикаже FileDialog елемент, кој ќе содржи листа на текст фајлови во директориумот, а со тоа, овозможувајќи на корисникот да селектира фајл со кликање на листата. Нас ни е уште потребно да доделиме save, load и new копчињата на нивните соодветни акции. FileMenu содржи влезен едитирачки текст да му овозможи на корисникот да го напише името на фајлот со користење на тастатура.

Directory елементот е искористен во FileMenu.qml фајлот и го известува FileDialog елементот дека директориумот ја освежил својата содржина. Ова известување се извршува со справувач на сигнали, onDirectoryChanged.

Во FileMenu.qml:

Directory{
 id:directory
 filename: textInput.text
 onDirectoryChanged: fileDialog.notifyRefresh()
 }

Зачувувајќи ја едноставноста на нашата апликација, дијалогот секојпат ќе биде видлив, и нема да прикажува невалидни текст фајлови, кои немаат .txt екстензија на нивните имиња.

Во FileDialog.qml:

signal notifyRefresh()
 onNotifyRefresh: dirView.model = directory.files

FileDialog елементот ќе ја прикаже содржината на директориумот со читање на листа својството наречено files. Фајловите се користат како модел во GridView елементот, кој прикажува податочни елементи во мрежа одредено од делегатот. Делегатот е одговорен за изгледот на моделот и нашиот дијалог едноставно ќе креира мрежа со текст центриран во средината. Со кликање на името на фајлот ќе резултира со појавување на правоаголник кој ќе го означи името на фајлот. FileDialog се известува кога notifyRefresh сигналот е емитиран, вчитувајќи ги повторно фајловите во директориумот.

В FileMenu.qml:

Button{
 id: newButton
 label: "New"
 onButtonClick:{
 textArea.textContent = ""
 }
 }
 Button{
 id: loadButton
 label: "Load"
 onButtonClick:{
 directory.filename = textInput.text
 directory.loadFile()
 textArea.textContent = directory.fileContent
 }
 }
 Button{
 id: saveButton
 label: "Save"
 onButtonClick:{
 directory.fileContent = textArea.textContent
 directory.filename = textInput.text
 directory.saveFile()
 }
 }
 Button{
 id: exitButton
 label: "Exit"
 onButtonClick:{
 Qt.quit()
 }
 }

Нашето FileMenu сега може да се поврзе со соодветните акции. saveButton ќе го пренесе текстот од TextEdit во fileContent својството на директориумот, потоа ќе го копира името на фајлот во влезен едитирачки текст. Конечно, копчето ја повикува saveFile() функција, снимајќи го со тоа фајлот. loadButton се извршува слично. Исто така, New акцијата ќе ја испразни содржината на TextEdit.

Понатаму, EditMenu копчињата се конектирани со TextEdit функциите за копирање, лепење и селектирање на сиот текст во текст едиторот.

File Menu

Завршување со текст едиторот

New File