Guida introduttiva alla programmazione con QML: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
(6 intermediate revisions by 2 users not shown)
Line 1: Line 1:
h1. Guida introduttiva alla programmazione con QML
#REDIRECT [[Getting Started Programming with QML/it]]
 
Benvenuto nel mondo di QML, il linguaggio dichiarativo per interfacce utente (UI: User Interface). In questa guida introduttiva, creeremo un semplice editor di testo utilizzando QML. Dopo la lettura di questa guida, dovresti essere in grado di sviluppare le tue applicazioni utilizzando QML e Qt C+''.
<br />h1. QML per la costruzione di interfacce utente
<br />p. L'applicazione che stiamo costruendo è un semplice editor di testo per caricare, salvare ed modificare del testo. Questa guida sarà composta di due parti. La prima parte prevede la progettazione della disposizione (layout) e dei comportamenti dei componenti dell'applicazione, tramite il linguaggio dichiarativo QML. Nella seconda parte procederemo allo sviluppo delle componenti per il caricamento e il salvataggio dei file utilizzando Qt C. Tramite l'utilizzo del Qt Meta-Object System, siamo in grado di esporre le funzioni C''+ come proprietà che gli elementi QML potranno utilizzare in modo nativo. In questo modo, utilizzando QML e Qt C+'', possiamo separare, in modo molto efficace, la logica di interfaccia dalla logica dell'applicazione.
<br />http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png
<br />p. Per eseguire il codice QML dell'esempio, è sufficente passare al programma &quot;qmlviewer &quot;:http://doc.qt.nokia.com/4.7/qmlviewer.html il nome del file QML come argomento. La parte C''+ di questa esercitazione presuppone che il lettore possieda una conoscenza di base delle procedure di compilazione di Qt.
 
Capitoli dell'esercitazione:<br /># Definire un pulsante e un menu<br /># Implementare una barra dei menu<br /># Costruire un editor di testo<br /># Decorare l'editor di testo<br /># Estendere QML usando Qt C++
 
= Definire un Pulsante e un Menu =
 
== Componenti di Base - un Pulsante ==
 
Iniziamo il nostro editor di testo con la costruzione di un pulsante. Funzionalmente, un pulsante è costituito da una zona sensibile ad azioni esterne (del mouse o di un'interfaccia touch screen per esempio) e da una etichetta. I pulsanti eseguono delle azioni ogniqualvolta l'utente preme il pulsante.
 
In QML, l'elemento visuale di base è il rettangolo (&quot;Rectangle&amp;quot;:http://doc.qt.nokia.com/4.7/qml-rectangle.html). L'elemento ''Rectangle'' ha delle proprietà che permettono di controllare l'aspetto dell'elemento e la sua posizione.
 
<code><br /> import Qt 4.7
 
Rectangle{<br /> id:simplebutton
 
color: &quot;grey&amp;quot;<br /> width: 400; height: 400
 
Text {<br /> id: buttonLabel<br /> text: &quot;button label&amp;quot;<br /> anchors.centerIn:parent<br /> }<br /> }<br /></code>
 
Per prima cosa, nel codice, l'istruzione ''import Qt 4.7'', permette al programma qmlviewer di importare gli elementi QML che useremo in seguito. Questa prima istruzione deve esistere in ogni file QML. Si noti che la versione dei moduli Qt è parte integrante della dichiarazione di importazione.
 
Questo semplice rettangolo possiede un identificatore univoco, ''simplebutton'', che è associato alla proprietà ''id''. Le proprietà dell'elemento ''Rectangle'' sono collegate ai relativi valori in questo modo: elencando il nome della proprietà, seguito da due punti, quindi il suo valore. Nel codice di esempio, il colore ''grey'' è legato alla proprietà ''color'' del rettangolo. Nello stesso modo colleghiamo le proprietà ''width'' (larghezza) e ''height'' (altezza) del rettangolo.
 
L'elemento ''Text'' è un campo di testo non modificabile. Chiamiamo ''buttonLabel'' questo elemento ''Text''. Per impostare il contenuto della stringa del campo di testo, associamo un valore alla proprietà ''text''. E' utile far notare che l'elemento QML ''Text'' e la sua proprietà ''text'' sono entità ben distinte. L'etichetta è contenuta all'interno del rettangolo e, al fine di centrarla nel mezzo, colleghiamo gerarchicamente le ''anchors'' (ancore) dell'elemento ''Text'' al suo genitore, che nel nostro caso si chiama ''simplebutton''. Ogni ancora può essere collegata alle ancore di altri elementi, in questo modo si semplifica la definizione della disposizione reciproca degli elementi.
 
Salviamo questo codice come ''SimpleButton.qml''. Se lanciamo il programma ''qmlviewer'' con il nome del file come argomento, vedremo visualizzato il rettangolo grigio con una etichetta di testo.
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor1_simplebutton.png
 
Per implementare la funzionalità collegata al click sul pulsante, utilizziamo la gestione degli eventi di QML. La gestione degli eventi di QML è molto simile al meccanismo &quot;signal e slot di Qt&amp;quot;:http://doc.qt.nokia.com/4.7/signalsandslots.html. Ogni qualvolta viene invocato una ''signal'', viene chiamato il corrispondente ''slot'' collegato.
 
<code><br />Rectangle{<br /> id:simplebutton<br /> …
 
MouseArea{<br /> id: buttonMouseArea
 
anchors.fill: parent //anchor all sides of the mouse area to the rectangle's anchors<br /> //onClicked handles valid mouse button clicks<br /> onClicked: console.log(buttonLabel.text + &quot; clicked&amp;quot; )<br /> }<br />}<br /></code>
 
Aggiungiamo un elemento ''MouseArea'' nel nostro componente ''simpleButton''. Gli elementi che compongono la nostra ''MouseArea'' descrivono l'area interattiva in cui vengono rilevati i movimenti del mouse. Nel nostro caso, per il nostro pulsante, 'ancoriamo' l'intera ''MouseArea'' al suo genitore, che è ''simpleButton''. La sintassi ''anchors.fill'' è un modo di esprimere l'accesso, nel nostro caso, ad una proprietà specifica denominata ''fill'' all'interno di un gruppo di proprietà denominato ''anchors''. QML utilizza layout basati su ancore, in cui ciascun elemento può ancorarsi ad un altro elemento, in questo modo si creano layout robusti e flessibili.
 
L'elemento ''MouseArea'' prevede molti gestori di segnali (signal handler) che vengono chiamati durante i movimenti del mouse all'interno dei suoi confini specificati. Uno di questi è ''onClicked'' ed è chiamato ogni volta che il previsto pulsante del mouse viene cliccato, nel nostro caso il click sinistro è l'azione di default. Possiamo legare delle azioni al gestore dell'evento ''onClicked''. Nel nostro esempio, la chiamata a ''console.log ()'' emette una stringa di testo ogni volta che l'area attiva viene cliccata. La funzione ''console.log'' è un strumento molto utile per il debugging e, in generale, per l'output di testo dell'applicazione.
 
Il codice in SimpleButton.qml è già sufficiente per visualizzare un pulsante sullo schermo e produrre del testo, ogni volta che lo si clicca con il mouse.
 
<code><br />Rectangle {<br /> id:Button<br /> …
 
property color buttonColor: &quot;lightblue&amp;quot;<br /> property color onHoverColor: &quot;gold&amp;quot;<br /> property color borderColor: &quot;white&amp;quot;
 
signal buttonClick()<br /> onButtonClick: {<br /> console.log(buttonLabel.text + &quot; clicked&amp;quot; )<br /> }
 
MouseArea{<br /> onClicked: buttonClick()<br /> hoverEnabled: true<br /> onEntered: parent.border.color = onHoverColor<br /> onExited: parent.border.color = borderColor<br /> }
 
//determines the color of the button by using the conditional operator<br /> color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br />}<br /></code>
 
Nel file ''Button.qml'' abbiamo il codice per un pulsante completamente funzionante. I frammenti di codice riportati in questo articolo, hanno alcune parti omesse, indicate con dei puntini di sospensione, perché o erano già stati introdotti in precedenza o perché non rilevanti per la discussione di questo codice specifico.
 
Per dichiarare delle proprietà personalizzate, si utilizza una sintassi del tipo ''proprietà tipo nome''. Nel nostro codice viene dichiarata la proprietà ''buttonColor'', di tipo ''color'', e collegata al valore ''&quot;lightblue&amp;quot;''. La proprietà ''buttonColor'' è poi utilizzata in un'operazione condizionale per determinare il colore di riempimento dei pulsanti. Si noti che l'assegnazione del valore della proprietà è possibile sia con il segno di uguale ''='', sia con l'operatore due punti '':''. Le proprietà personalizzate permettono di rendere accessibili elementi interni dell'elemento ''Rectangle'', anche dall'esterno del suo campo di applicazione (scope). Ci sono diversi tipi QML di base come ''int'', ''string'', ''real'', così come un tipo generico chiamato ''variant''.
 
Collegando i gestori di segnale ''onEntered'' e ''onExited'' ai colori, è possibile rendere il bordo del pulsante giallo quando il mouse passa sopra il pulsante e ripristinare il colore precedente quando il mouse lascia la sua zona sensibile (MouseArea).
 
Viene dichiarato un signal ''buttonClick()'', inserendo la keyword ''signal'' davanti al nome della funzione. Per ogni ''signal'' vengono creati automaticamente le relative funzioni di gestione, i loro nomi iniziano con il prefisso ''on''. Di conseguenza, la funzione ''onButtonClick'' è il gestore (handler) di ''buttonClick''. Succesivamente a ''onButtonClick'' viene quindi assegnata l'operazione da eseguire. Nel nostro pulsante di esempio, il gestore di mouse ''onClicked'' chiama semplicemente ''onButtonClick'', che visualizza un testo. La funzione ''onButtonClick'' permette ad oggetti esterni di accedere facilmente alla mouse area del pulsante. Inoltre, gli oggetti possono avere più di una dichiarazione di ''MouseArea'' e avere un ''signal'' ''ButtonClick'' può migliorare la distinzione tra i diversi gestori di segnali della MouseArea.
 
Adesso abbiamo le conoscenze di base che ci permettono l'implementazione di elementi in QML in grado di gestire i principali movimenti del mouse. Abbiamo creato una etichetta di tipo ''Text'' all'interno di un elemento ''Rectangle'', personalizzato le sue proprietà e implementato dei comportamenti che rispondono ai movimenti del mouse. Questa idea di base della creazione di elementi all'interno di altri elementi, si ripresenterà nello sviluppo di tutta questa applicazione di esempio.
 
Questo pulsante non è molto utile se non viene utilizzato come componente per eseguire qualche azione. Nella sezione successiva, vedremo come creare un menu che utilizza alcuni di questi pulsanti.
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor1_button.png
 
= Creazione di un Menu =
 
Fino ad ora, abbiamo spiegato come creare degli elementi e definirne i comportamenti all'interno di un singolo file QML. In questa sezione ci occuperemo di come importare elementi QML e come riutilizzare alcuni componenti già realizzati per costruire altri componenti.
 
Un Menu permette di visualizzare il contenuto di una lista, ogni elemento ha la capacità di eseguire un'azione. In QML, possiamo ottenere un menu in diversi modi. Per prima cosa, creiamo un menu contenente dei pulsanti cui faremo eseguire opportune azioni. Il codice del menu è nel file ''FileMenu.qml''.
 
<code><br /> import Qt 4.7 import the main Qt QML module<br /> import &quot;folderName&amp;quot; import the contents of the folder<br /> import &quot;script.js&amp;quot; as Script import a Javascript file and name it as Script<br /></code>
 
La sintassi riportata sopra mostra alcuni utilizzi della keyword ''import''. Questo è necessario per poter utilizzare dei file &quot;JavaScript&amp;quot;:https://developer.mozilla.org/en/JavaScript, o dei file QML che non sono presenti all'interno della directory corrente. Poiché ''Button.qml'' è nella stessa directory di ''FileMenu.qml'', non abbiamo la necessità di importare esplicitamente il file Button.qml per poterlo usare. Possiamo creare direttamente un elemento ''Button'' di tipo ''Button{}'', allo stesso modo di un ''Rectangle{}''.
 
<code><br /> In FileMenu.qml:
 
Row{<br /> anchors.centerIn: parent<br /> 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;
 
onButtonClick: Qt.quit()<br /> }<br /> }<br /></code>
 
Nel ''FileMenu.qml'', sono dichiariati tre elementi ''Button''. Questi sono dichiarati all'interno di un elemento di tipo ''Row'', un elemento di posizionamento che allinea i suoi figli lungo una fila verticale. La dichiarazione di ''Button'' risiede nel file ''Button.qml'', che è lo stesso file che abbiamo usato per la sezione precedente. E' possibile definire dei nuovi collegamenti per le proprietà dei pulsanti appena creati, in questo modo si sovrascrivono le proprietà impostate in ''Button.qml''. Il pulsante denominato ''ExitButton'', quando viene cliccato, fa in modo che la finestra dell'applicazione venga abbandonata e chiusa. E' bene tenere presente che il gestore di segnale ''onButtonClick'' nel file ''Button.qml'' viene chiamato in aggiunta al gestore ''onButtonClick'' di ''ExitButton''.
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor1_filemenu.png
 
L'elemeto ''Row'' è dichiarato all'interno di un ''Rectangle'', creando un contenitore rettangolare per la fila dei pulsanti. Questo rettangolo aggiuntivo permette di avere un modo indiretto di organizzare la fila dei pulsanti all'interno del menu.
 
La dichiarazione del menu Modifica (Edit) è molto simile a quanto già visto finora. Il menu è composto da pulsanti che hanno le etichette: ''Copy'' (Copia), ''Paste'' (Incolla) e ''Select All'' (Seleziona tutto).
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor1_editmenu.png
 
Grazie alla conoscenza di importazione e personalizzazione dei componenti acquisita finora, possiamo ora combinare queste pagine di menu per creare una barra dei menu, composta da pulsanti per selezionare i menu specifici e quindi passare a vedere come possiamo strutturare i dati utilizzando QML.
 
== Implementare una barra dei menu ==
 
Il nostro editor di testo potrà visualizzare i menu disponibili attraverso una barra dei menu. La barra dei menu proporrà i diversi menu e l'utente sceglierà quali menu visualizzare. La funzionalità di cambio dei menu implica che i questi avranno bisogno di una struttura più sofisticata di quella che si limita a mostrarli su di una riga. QML utilizza modelli e viste per gestire e visualizzare i dati strutturati.
 
== Utilizzare modelli dati e viste ==
 
QML dispone di diverse &quot;viste&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html (data views) che visualizzano i &quot;modelli dati&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativemodels.html (data models). La nostra barra dei menu visualizza i menu in una lista, con una testata che mostra una fila di nomi di menu. L'elenco dei menu è dichiarata all'interno di un ''VisualItemModel''. L'elemento ''&quot;VisualItemModel&amp;quot;:http://doc.qt.nokia.com/4.7/qml-visualitemmodel.html'' contiene elementi che dispongono già di viste come elementi ''Rectangle'' e altri elementi d'interfaccia. Altri tipi di modelli, come l'elemento &quot;ListModel&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listmodel.html, hanno bisogno di un elemento delegato (delegate) per visualizzare i propri dati.
 
In questo caso sono dichiarati due elementi visuali in ''menuListModel'', il ''FileMenu'' e l'''EditMenu'', e sono visualizzati e personalizzati tramite un controllo &quot;ListView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listview.html. Il file ''MenuBar.qml'' contiene le dichiarazioni QML e un semplice menu modifica è definito in ''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>
 
L'elemento &quot;ListView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-listview.html visualizza un modello attraverso un elemento delegato. Il delegato può dichiarare che gli elementi del modello siano visualizzati in un elemento di tipo ''Row'' o siano posti in una griglia. Nel nostro caso ''menuListModel'' ha già gli elementi visibili, quindi, non abbiamo bisogno di dichiarare un delegato.
 
<code><br /> ListView{<br /> id: menuListView
 
//Anchors are set to react to window anchors<br /> anchors.fill:parent<br /> anchors.bottom: parent.bottom<br /> width:parent.width<br /> height: parent.height
 
//the model contains the data<br /> model: menuListModel
 
//control the movement of the menu switching<br /> snapMode: ListView.SnapOneItem<br /> orientation: ListView.Horizontal<br /> boundsBehavior: Flickable.StopAtBounds<br /> flickDeceleration: 5000<br /> highlightFollowsCurrentItem: true<br /> highlightMoveDuration:240<br /> highlightRangeMode: ListView.StrictlyEnforceRange<br /> }<br /></code>
 
Inoltre, ''ListView'' deriva da &quot;Flickable&amp;quot;:http://doc.qt.nokia.com/4.7/qml-flickable.html, facendo così in modo l'elenco risponda al trascinamento con il mouse (drag) e altri eventi (gestures). L'ultima parte del codice di cui sopra imposta le proprietà di ''Flickable'' per ottenere il movimento desiderato sfogliando la nostra vista. Nello specifico, la proprietà ''highlightMoveDuration'' cambia la durata della transizione nello sfoglio. Un valore più alto di ''highlightMoveDuration'' causa un passaggio più lento tra i menu.
 
La ''ListView'' getisce gli elementi del modello attraverso un ''index'' (indice) e ogni elemento visual nel modello è accessibile tramite questo indice, secondo l'ordine di dichiarazione. Modificare il ''currentIndex'' ha come effetto quello di cambiare l'elemento evidenziato nella ''ListView''. L'intestazione nella nostra barra dei menu esemplifica questo effetto. Ci sono due pulsanti nella riga, entrambi cambiano il menu corrente quando vengono cliccati. Il pulsante ''fileButton'' cambia il menu corrente nel menu file quando viene cliccato, l'indice in questo caso è 0, perché ''FileMenu'' è dichiarato per primo nella ''menuListModel''. Analogamente, il pulsante ''editButton'', quando viene cliccato, cambierà il menù corrente nel menu ''EditMenu''.
 
Il rettangolo ''labelList'' ha valore di z di 1, questo indica che è visualizzato davanti alla barra dei menu. Gli elementi con valori di z maggiori sono visualizzati davanti a oggetti con valori più bassi di z. Il valore di default di 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<br /> label: &quot;Edit&amp;quot;<br /> …<br /> onButtonClick: menuListView.currentIndex = 1<br /> }<br /> }<br /> }<br /></code>
 
La barra dei menu che abbiamo appena creato può essere sfogliata per accedere ai menu oppure si può cliccare sui nomi dei menu nella barra in alto. La commutazione delle schermate dei menu è intuitiva e immediata per l'utente.
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor2_menubar.png
 
= Costruire un Editor di testo =
 
== Dichiarare una TextArea ==
 
Il nostro editor di testo non può essere un editor di testo finché non contiene una zona di testo modificabile. L'elemento ''TextEdit'' di QML permette proprio la dichiarazione di un componente per la modifica di testo multi-linea. ''TextEdit'' è diverso da un elemento di tipo ''Text'', che non consente all'utente di modificare direttamente il testo.
 
<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
 
wrapMode: TextEdit.Wrap
 
onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)<br /> }<br /></code>
 
Nell'editor sono impostate le proprietà ''color'' del proprio font e del testo a capo (wrap). L'area di TextEdit è all'interno di un area mobile che farà scorrere il testo, se il cursore del testo è al di fuori dell'area visibile. La funzione ''EnsureVisible()'' controlla se il rettangolo del cursore si trova al di fuori dei confini visibili e, nel caso, sposta opportunamente l'area di testo. QML utilizza la sintassi Javascript per i suoi script e, come accennato in precedenza, i file Javascript possono essere importati e utilizzati all'interno di un file 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>
 
== Combinare componenti per l'editor di testo ==
 
Ora siamo pronti per creare il layout del nostro editor di testo utilizzando QML. L'editor di testo ha due componenti, la barra dei menu che abbiamo creato e l'area di testo. QML ci permette di riutilizzare i componenti, rendendo quindi il nostro codice più semplice, mediante l'importazione di componenti e la personalizzazione quando ciò sia necessario. Il nostro editor di testo ha la propria finestra divisa in due parti: un terzo dello schermo è dedicata alla barra dei menu e i rimanenti due terzi della schermata al testo. La barra dei menu viene visualizzata davanti a ogni altro elemento.
 
<code><br /> Rectangle{
 
id: screen<br /> width: 1000; height: 1000
 
//the screen is partitioned into the MenuBar and TextArea. 1/3 of the screen is assigned to the MenuBar<br /> property int partition: height/3
 
MenuBar{<br /> id:menuBar<br /> height: partition<br /> width:parent.width<br /> z: 1<br /> }
 
TextArea{<br /> id:textArea<br /> anchors.bottom:parent.bottom<br /> y: partition<br /> color: &quot;white&amp;quot;<br /> height: partition*2<br /> width:parent.width<br /> }<br /> }<br /></code>
 
Tramite 'importazione di componenti riutilizzabili, il codice del nostro ''TextEditor'' appare molto più semplice. Si può quindi personalizzare l'applicazione principale, senza preoccuparsi delle proprietà che hanno già un comportamenti definito. Usando questo approccio, i layout delle applicazioni e i componenti di interfaccia utente possono essere assemblati più facilmente.
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor3_texteditor.png
 
= Abbellire l'editor di testo =
 
== Implementare una interfaccia a scomparsa ==
 
Il nostro editor di testo appare semplice e abbiamo bisogno di abbellirlo. Utilizzando QML, possiamo dichiarare delle transizioni e animare la nostra applicazione. La nostra barra dei menu occupa un terzo dello schermo, sarebbe bello fare in modo che appaia solo quando lo vogliamo.
 
A tale scopo possiamo aggiungere un elemento di interfaccia (''drawer'') che si occuperà di contrarre o espandere la barra dei menu quando viene cliccata. Nella nostra caso, abbiamo un piccolo rettangolo che risponde ai clic del mouse. Questo elemento, così come l'applicazione, ha due stati: lo stato &quot;''drawer'' aperto&amp;quot; e lo stato &quot;''drawer'' chiuso&amp;quot;. L'elemento ''drawer'' è una sottile striscia rettangolare con all'interno un elemento ''Imagine'' che definisce un'icona di una freccia centrata all'interno dell'area. Il ''drawer'' assegna uno stato all'intera applicazione, attraverso l'identificatore ''screen'', volta che un utente clicca sulla mouse area.
 
<code><br /> Rectangle{<br /> id:drawer<br /> height:15
 
Image{<br /> id: arrowIcon<br /> source: &quot;images/arrow.png&amp;quot;<br /> anchors.horizontalCenter: parent.horizontalCenter<br /> }
 
MouseArea{<br /> id: drawerMouseArea<br /> anchors.fill:parent<br /> onClicked:{<br /> if (screen.state  &amp;quot;DRAWER_CLOSED&amp;quot;)&amp;#123;
                    screen.state = &amp;quot;DRAWER_OPEN&amp;quot;
                &amp;#125;
                else if (screen.state  &quot;DRAWER_OPEN&amp;quot;){<br /> screen.state = &quot;DRAWER_CLOSED&amp;quot;<br /> }<br /> }<br /> …<br /> }<br /> }<br /></code>
 
Uno stato è semplicemente un insieme di configurazioni predefinite e si dichiara tramite un elemento di tipo ''State''. Un lista di stati possono essere collegati alla proprietà ''states'' e successivamente iterati. Nella nostra applicazione, i due stati sono chiamati ''DRAWER_CLOSED'' e ''DRAWER_OPEN''. Tramite i PropertyChanges sono definite le nuove configurazioni degli elementi. Nello stato ''DRAWER_OPEN'', ci sono quattro elementi che riceveranno delle modifiche alle proprietà. Il primo, ''menuBar'', cambierà la sua proprietà y in 0. Analogamente, la ''textArea'' si abbasserà in una nuova posizione quando lo stato è ''DRAWER_OPEN''. Anche la ''textarea'', il ''drawer'', e la sua icona subiranno dei cambiamento delle loro proprietà per adeguarsi allo stato corrente.
 
<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>
 
I cambiamenti di stato sono in genere repentini e c'è l'esigenza di smorzare le transizioni. Le transizioni tra gli stati sono definite utilizzando l'elemento ''Transition'', che può essere associato alla proprietà ''transitions'' di un elemento. Nel nostro editor di testo avviene una transizione di stato ogni volta che il suo stato diventa o ''DRAWER_OPEN'' o ''DRAWER_CLOSED''. È importante sottolineare che una transizione ha di solito bisogno di definire uno stato ''from'' e uno ''to'', ma nel nostro caso, possiamo usare il simbolo jolly (wild card) * per indicare che la transizione si applica a tutti i cambiamenti di stato.
 
Durante le transizioni, possiamo assegnare delle animazioni ai cambiamenti di proprietà. La nostra ''menuBar'' cambia di posizione da ''y: 0'' a ''Y:-partition'' ed è possibile animare questa transizione utilizzando l'elemento ''NumberAnimation''. Possiamo definire che le proprietà degli elementi interessati, si animeranno per un certo periodo di tempo e con una certa curva di andamento (easing curve). Una curva di andamento controlla la frequenza di animazione e il comportamento dell'interpolazione durante le transizioni di stato. La curva di andamento che abbiamo scelto è ''Easing.OutQuint'', che rallenta il movimento verso la fine dell'animazione. Potete approfondire l'argomento nell'articolo &quot;QML's Animation&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html.
 
<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>
 
Un altro modo per animare il cambiamento dei valori delle proprietà è dichiarare un elemento ''Behavior''. Una transizione funziona solo durante i cambiamenti di stato e un elemento ''Behavior'' può impostare un'animazione per un modifica generica della proprietà. Nell'editor di testo, l'icona freccia utilizza una ''NumberAnimation'' per animare la sua proprietà ''rotation'' (rotazione) ad ogni cambiamento.
 
<code><br /> In TextEditor.qml:
 
Behavior{<br /> NumberAnimation{property: &quot;rotation&amp;quot;;easing.type: Easing.OutExpo }<br /> }<br /></code>
 
Tornando ai nostri componenti, tramite l'utilizzo di stati e animazioni, possiamo migliorare l'aspetto di questi elementi. In ''Button.qml'', potremmo aggiungere delle modifiche alle proprietà ''color'' e ''scale'' quando il pulsante viene premuto. I tipi colore sono animati utilizzando &quot;ColorAnimation&amp;quot;:http://doc.qt.nokia.com/4.7/qml-coloranimation.html ed i numeri sono animati utilizzando &quot;NumberAnimation&amp;quot;:http://doc.qt.nokia.com/4.7/qml-numberanimation.html. La sintassi ''on propertyName'' visualizzata più sotto è comoda quando si agisce su di una singola proprietà.
 
<code><br /> In Button.qml:<br /> …
 
color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> Behavior on color { ColorAnimation{ duration: 55} }
 
scale: buttonMouseArea.pressed ? 1.1 : 1.00<br /> Behavior on scale { NumberAnimation{ duration: 55} }<br /></code>
 
Oltre a questo, possiamo intervenire sull'aspetto dei nostri componenti QML con l'aggiunta di effetti di colore, come sfumature ed effetti di trasparenza. Dichiarando un elemento &quot;Gradient&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gradient.html si sovrascrive la proprietà ''color'' dell'elemento. Si può quindi dichiarare il colore della sfumatura utilizzando l'elemento &quot;GradientStop&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gradientstop.html. La sfumatura è valorrizata utilizzando una scala tra ''0,0'' e ''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>
 
Questo gradiente è utilizzato dalla barra dei menu per visualizzare un gradiente che simula la profondità. Il primo colore è utilizzato al valore ''0,0'' e l'ultimo a ''1.0''.
 
=== Prossimi passi ===
 
Abbiamo così finito di costruire l'interfaccia utente di un semplice editor di testo. Andando avanti, completata l'interfaccia utente, siamo in grado di implementare la logica dell'applicazione con Qt e C+''. Come abbiamo visto QML funziona bene come strumento di prototipazione, separando efficacemente la logica applicativa dalla progettazione dell'interfaccia utente.
<br />h1. Estendere QML usando Qt C''+
 
Ora che abbiamo il layout del nostro editor di testo, possiamo ora implementare le funzionalità dell'editor in C+''. L'utilizzo di QML con C''+ permette di realizzare la logica della nostra applicazione utilizzando Qt. Siamo in grado di creare un ''context'' QML in una applicazione C++ usando le &quot;classi dichiarative di Qt&amp;quot;:http://doc.qt.nokia.com/4.7/qtbinding.html e visualizzare gli elementi QML tramite una &quot;Graphic Scene&amp;quot;:http://doc.qt.nokia.com/4.7/qgraphicsscene.html. In alternativa, possiamo esportare il nostro codice C++ compilato in un plugin che il programma ''qmlviewer'' è in grado di leggere. Per la nostra applicazione, implementeremo le funzioni in C++ per caricare e salvare i file e le esporteremo come plugin. In questo modo, abbiamo solo bisogno di lanciare il file QML direttamente anziché eseguire un file eseguibile.
 
== Esportare classi C++ per QML ==
 
Vogliamo implementare le funzioni di caricamento e salvataggio file utilizzando Qt e C+''. Le classi e le funzioni C''+ possono essere utilizzate in QML previa una loro registrazione. La classe ha inoltre bisogno di essere compilata come un plugin Qt e il file QML avrà bisogno di sapere dove si trova il plugin nel file system.
 
Per la nostra applicazione, abbiamo bisogno di creare i seguenti oggetti:
 
# una classe ''Directory'' che consenta di gestire le operazioni sulle directory (cartelle)
# una classe ''File'' che sia un QObject, che simuli l'elenco dei file in una directory
# una classe plugin che registri la classe nel corretto contesto QML
# un file di progetto (project file) Qt per compilare il plugin
# in file qmldir per indicare al programma qmlviewer dove trovare il plugin
 
== Costruire un pugin Qt ==
 
Per costruire un plugin, è necessario impostare le direttive che seguono in project file Qt. Innanzi tutto vanno specificati i file contenenti i sorgenti e i file di include, nonché i moduli Qt utilizzati. Tutti i file sorgenti C++ e di progetto si trovano nella directory FileDialog.
 
<code><br /> In cppPlugins.pro:
 
TEMPLATE = lib<br /> CONFIG ''= qt plugin<br /> QT''= declarative
 
DESTDIR ''= ../plugins<br /> OBJECTS_DIR = tmp<br /> MOC_DIR = tmp
<br /> TARGET = FileDialog
<br /> HEADERS''= directory.h  file.h  dialogPlugin.h
 
SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp<br /></code>
 
Nello specifico, compiliamo con il modulo Qt ''declarative'' e lo configuriamo come un ''plugin'', che necessita di un modello (template) di tipo ''lib''. Dovremmo poi mettere il plugin compilato nella directory ''plugins'' del genitore della directory corrente.
 
== Registrare una classe in QML ==
 
<code><br /> In dialogPlugin.h:
 
#include &lt;QtDeclarative/QDeclarativeExtensionPlugin&amp;gt;
 
class DialogPlugin : public QDeclarativeExtensionPlugin<br /> {<br /> Q_OBJECT
 
public:<br /> void registerTypes(const char *uri);
 
};<br /></code>
 
La nostra classe plugin, ''DialogPlugin'' è una sottoclasse di &quot;QDeclarativeExtensionPlugin&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html. Questa prevede che dobbiamo implementare la funzione ereditata, ''registerTypes()''. Il file dialogPlugin.cpp assomiglia a questo:
 
<code><br /> DialogPlugin.cpp:
 
#include &quot;dialogPlugin.h&amp;quot;<br /> #include &quot;directory.h&amp;quot;<br /> #include &quot;file.h&amp;quot;<br /> #include &lt;QtDeclarative/qdeclarative.h&amp;gt;
 
void DialogPlugin::registerTypes(const char '''uri){
<br /> qmlRegisterType&amp;lt;Directory&amp;gt;(uri, 1, 0, &quot;Directory&amp;quot;);<br /> qmlRegisterType&amp;lt;File&amp;gt;(uri, 1, 0,&quot;File&amp;quot;);<br /> }
<br /> Q_EXPORT_PLUGIN2(FileDialog, DialogPlugin);<br /></code>
<br />p. La funzione &quot;registerTypes()&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registra le nostre classi ''File'' e ''Directory'' in QML. Questa funzione ha bisogno dell nome della classe per il suo template, un numero di versione principale, un numero di versione minore, e un nome per le nostre classi.
<br />p. Abbiamo poi bisogno di esportare il plugin utilizzando la macro &quot;Q_EXPORT_PLUGIN2&amp;quot;:http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2#q-export-plugin2. Si noti che nel file ''dialogPlugin.h'', abbiamo la macro Q_OBJECT in cima alla nostra classe. Inoltre, abbiamo bisogno di eseguire ''qmake'' sul file di progetto per generare il necessario codice meta-object.
<br />h2. Creare proprietà QML in una classe C++
<br />p. Possiamo ora creare elementi e proprietà QML utilizzando C++ e il &quot;Qt Meta-Object System&amp;quot;:http://doc.qt.nokia.com/4.7/metaobjects.html. Siamo in grado di implementare le proprietà utilizzando gli slot e le signal, rendendole note anche a Qt. Queste proprietà possono poi essere utilizzate direttamente in QML.
<br />p. Per l'editor di testo, dobbiamo essere in grado di caricare e salvare file. Normalmente, queste funzionalità sono contenute in una finestra di dialogo. Per fortuna, possiamo usare &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 e &quot;QTextStream&amp;quot;:http://doc.qt.nokia.com/4.7/qtextstream.html per implementare la lettura di directory e gli stream di input/output.
<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 />p. La classe Directory utilizza il Meta-Object System di Qt per registrare le proprietà di cui ha bisogno per realizzare la gestione dei file. La classe Directory è esportata come un plugin ed è utilizzabile in QML come l'elemento ''Directory''. Ciascuna delle proprietà definite utilizzando la macro &quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY è anche una proprietà QML.
<br />p. La macro &quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY dichiara al Meta-Object System di Qt sia la proprietà, che le sue funzioni di lettura e scrittura. Ad esempio, la proprietà ''filename'', di tipo &quot;QString&amp;quot;:http://doc.qt.nokia.com/4.7/qstring.html, è leggibile con la funzione ''filename()'' e scrivibile utilizzando la funzione ''setFilename()''. Inoltre, vi è una ''signal'' associato alla proprietà ''filename'' chiamata ''filenameChanged()'', che viene emesso ogni volta che la proprietà cambia. Le funzioni di lettura e scrittura sono dichiarate come public nel file header (.h).
<br />p. Analogamente, abbiamo le altre proprietà dichiarate secondo il loro utilizzo. La proprietà ''filesCount'' indica il numero di file in una directory. La proprietà ''filename'' è impostata con il nome del file attualmente selezionato ed il contenuto del file salvato. o caricato, viene memorizzato nella proprietà ''fileContent''.
<br /><code><br /> Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )<br /></code>
<br />p. La lista di proprietà ''files'' è un elenco di tutti i file, filtrati, presenti in una directory. La classe ''Directory'' è implementato in modo da filtrare i file di testo non validi; solo i file con estensione .txt sono validi. Inoltre, una &quot;QList&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html può essere utilizzata nei file QML dichiarandola come &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html in C+''. L'oggetto deve ereditare da un &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html, quindi, la classe ''File'' deve anche ereditare da &quot;QObject&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html. Nella classe ''Directory'', l'elenco di oggetti di tipo ''File'' è memorizzato in una &quot;QList&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html chiamata ''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 />p. Le proprietà possono quindi essere utilizzate direttamente in QML come parte integrante delle proprietà dell'elemento ''Directory''. Si noti che non abbiamo dovuto creare un proprietà identificatore ''id'' nel nostro codice C.
<br /><code><br /> Directory{<br /> id: directory
<br /> filesCount<br /> filename<br /> fileContent<br /> files
<br /> files[0].name<br /> }<br /></code>
<br />p. Poiché QML utilizza la sintassi e la struttura di Javascript, siamo in grado di iterare l'elenco dei file e recuperare le sue proprietà. Per recuperare la proprietà nome del primo file, possiamo usare <code>files[0].name<code>
<br />p. Anche le normali funzioni C''+ sono accessibili da QML. Le funzioni di caricamento e di salvataggio dei file sono implementate in C++ e dichiarate utilizzando la macro &quot;Q_INVOKABLE&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE. In alternativa, possiamo dichiarare le funzioni come uno ''slot'' e renderle in questo modo accessibili da QML.
<br /></code><br /> In Directory.h:
<br /> Q_INVOKABLE void saveFile&amp;amp;#40;&amp;#41;;<br /> Q_INVOKABLE void loadFile&amp;amp;#40;&amp;#41;;<br /><code>
<br />p. La classe Directory deve anche notificare altri oggetti ogni volta che c'è un cambiamento nel contenuto della directory. Questa funzione viene eseguita utilizzando una ''signal''. Come accennato in precedenza, le ''signal'' QML hanno un gestore associato che ha lo stesso nome preceduto dal prefisso ''on''. La ''signal'' è denominato ''directoryChanged'' e viene emesso ogni volta che c'è un aggiornamento della directory. L'aggiornamento ricarica semplicemente il contenuto della directory e aggiorna l'elenco dei file validi della directory. Gli elementi QML possono poi essere notificati implementand il gestore di ''signal'' ''onDirectoryChanged''.
<br />p. Le proprietà ''list'' ha bisogno di essere ulteriormente esplorata. Questo perché le proprietà di tipo ''list'' utilizzano delle funzioni di callback per accedere e modificare il contenuto dell'elenco. La proprietà ''list'' è di tipo ''QDeclarativeListProperty&amp;lt;File&amp;gt;'' . Ogni volta che si accede alla lista, la funzione di accesso (accessor) deve restituire una oggetto di tipo ''QDeclarativeListProperty&amp;lt;File&amp;gt;''. Il tipo del ''template'', ''File'', deve essere un derivato di QObject. Inoltre, per creare la &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html, le funzioni di accesso e di modifica (modifier) devono essere passati al costruttore della classe come puntatori a funzione. La lista, una ''QList'' nel nostro caso, deve anche essere una lista di puntatori a ''File''.
<br />p.Il costruttore di &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html e l'implementazione in ''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>
 
Il costruttore passa i puntatori alle funzioni che implementano rispettivamente: aggiungi alla lista, enumera la lista, recupera l'oggetto utilizzando un indice, e svuota la lista. Solo la funzione ''append'' è obbligatoria. Si noti che i puntatori a funzione devono corrispondere alla definizione di &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, e &quot;ClearFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef.
 
</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>
 
Per semplificare la nostra finestra di dialogo file, la classe ''Directory'' filtra i file di testo non validi, che sono file che non hanno l'estensione .txt. Se un nome di file non ha l'estensione .txt, allora non sarà visibile nella nostra finestra di dialogo file. Inoltre, l'applicazione assicura che i file salvati abbiano l'estensione .txt nel nome del file. La classe ''Directory'' utilizza &quot;QTextStream&amp;quot;:http://doc.qt.nokia.com/4.7/qtextstream.html per leggere e scrivere il contenuto del file.
 
Tramite il nostro elemento ''Directory'', è possibile recuperare tutti i file come una lista, sapere quanti sono i file di tipo testo nella directory dell'applicazione, ottenere il nome del file corrente e il suo contenuto come stringa, ed essere informati quando ci sono cambiamenti nel contenuto delle directory.
 
Per costruire il plugin, bisogna eseguire ''qmake'' con il file di progetto ''cppPlugins.pro'', quindi lanciare ''make'' fare per compilare e trasferire il plugin nella directory ''plugins''.
 
== Importare un plugin in QML ==
 
Il programma ''qmlviewer'' importa i file che si trovano nella stessa directory dell'applicazione. Possiamo anche creare un file ''qmldir'' contenente la posizione dei file QML che vogliamo importare. Il file qmldir può anche memorizzare le posizioni di plugin e altre risorse.
 
</code><br /> In qmldir:
 
Button ./Button.qml<br /> FileDialog ./FileDialog.qml<br /> TextArea ./TextArea.qml<br /> TextEditor ./TextEditor.qml<br /> EditMenu ./EditMenu.qml
 
plugin FileDialog plugins<br /><code>
 
Il plugin che abbiamo appena creato si chiama FileDialog, come indicato dal campo ''TARGET'' nel file di progetto. Il plugin è compilato e copiato nella directory ''plugins''.
 
== Integrare una finestra di dialogo nel menu File ==
 
Il nostro ''FileMenu'' ha bisogno di visualizzare l'elemento ''FileDialog'', contenente un elenco dei file di testo in una directory consentendo così all'utente di selezionare un file facendo clic sulla lista. Abbiamo anche bisogno di collegare i pulsanti per salvare, caricare e creare nuovo, alle loro rispettive azioni. Il ''FileMenu'' contiene anche un campo di input di testo per consentire all'utente di digitare un nome di file utilizzando la tastiera.
 
L'elemento ''Directory'' viene utilizzato nel file ''FileMenu.qml'' e avvisa l'elemento ''FileDialog'' quando la directory ha aggiornato il suo contenuto. Questa notifica viene eseguita nel gestore del segnale, ''onDirectoryChanged''.
 
</code><br /> In FileMenu.qml:
 
Directory{<br /> id:directory<br /> filename: textInput.text<br /> onDirectoryChanged: fileDialog.notifyRefresh()<br /> }<br /><code>
 
Allineandola con la semplicità della nostra applicazione, la finestra di dialogo file è sempre visibile e non visualizza file di testo non validi, che non hanno una estensione .txt nei loro nomi.
 
</code><br /> In FileDialog.qml:
 
signal notifyRefresh()<br /> onNotifyRefresh: dirView.model = directory.file<br /><code>
 
L'elemento ''FileDialog'' visualizza il contenuto di una directory leggendo la lista di proprietà chiamata ''files''. I file vengono utilizzati come modello di un elemento &quot;GridView&amp;quot;:http://doc.qt.nokia.com/4.7/qml-gridview.html, che visualizza gli elementi dati in una griglia su indicazione di un componente delegato. Il delegato gestisce l'aspetto del modello e la nostra finestra di dialogo file utilizza semplicemente una griglia con il testo centrato nel mezzo. Cliccando sul nome del file compare un rettangolo per evidenziare il nome del file. Il ''FileDialog'' viene notificato ogni volta che la ''signal'' ''notifyRefresh'' viene emessa, ricaricando così i file nella directory.
 
</code><br /> In FileMenu.qml:
 
Button{<br /> id: newButton<br /> label: &quot;New&amp;quot;<br /> onButtonClick:{<br /> textArea.textContent = &quot;&quot;<br /> }<br /> }<br /> Button{<br /> id: loadButton<br /> label: &quot;Load&amp;quot;<br /> onButtonClick:{<br /> directory.filename = textInput.text<br /> directory.loadFile&amp;amp;#40;&amp;#41;<br /> textArea.textContent = directory.fileContent<br /> }<br /> }<br /> Button{<br /> id: saveButton<br /> label: &quot;Save&amp;quot;<br /> onButtonClick:{<br /> directory.fileContent = textArea.textContent<br /> directory.filename = textInput.text<br /> directory.saveFile&amp;amp;#40;&amp;#41;<br /> }<br /> }<br /> Button{<br /> id: exitButton<br /> label: &quot;Exit&amp;quot;<br /> onButtonClick:{<br /> Qt.quit()<br /> }<br /> }<br /><code>
 
Il nostro ''FileMenu'' può adesso essere connesso alle rispettive azioni. Il pulsante ''saveButton'' trasferirà il testo dal ''TextEdit'' alla proprietà ''fileContent'' della directory, quindi copia il nome del file nel campo di input testo. Infine, il pulsante chiama la funzione ''savefile&amp;amp;#40;&amp;#41;'', per salvare il contenuto del file. Il pulsante ''loadButton'' ha una comportamento simile. Inoltre, l'azione ''New'' svuota il contenuto del ''TextEdit''.
 
Per finire, i pulsanti ''EditMenu'' sono collegate alle funzioni di TextEdit per copiare, incollare e selezionare tutto il testo nell'editor.
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor5_filemenu.png
 
= L'editor di testo completo =
 
http://doc.qt.nokia.com/4.7/images/qml-texteditor5_newfile.png

Latest revision as of 16:15, 4 May 2015