GettingStartedQML Spanish: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
 
No edit summary
Line 1: Line 1:
=Introducción a la Programación con <span class="caps">QML</span>=
[[Category:Learning]] [[Category:Spanish]]


Bienvenido al mundo de <span class="caps">QML</span>, el lenguaje declarativo de Interfaces de Usuario (UI). En esta guía de introducción, crearemos una simple aplicación de editor de texto utilizando <span class="caps">QML</span>. Después de leer esta guía, usted debería estar listo para desarrollar sus propias aplicaciones utilizando <span class="caps">QML</span> y Qt C++.
= Introducción a la Programación con QML =


==<span class="caps">QML</span> para crear interfaces de usuario==
Bienvenido al mundo de QML, el lenguaje declarativo de Interfaces de Usuario (UI). En esta guía de introducción, crearemos una simple aplicación de editor de texto utilizando QML. Después de leer esta guía, usted debería estar listo para desarrollar sus propias aplicaciones utilizando QML y Qt C+''.
<br />h2. QML para crear interfaces de usuario
<br />La aplicación que estamos construyendo es un editor de texto simple que va a cargar, guardar y realizar alguna manipulación de texto. Esta guía constará de dos partes. La primera parte consistirá en diseñar la interfaz de la aplicación y sus comportamientos (behaviors) utilizando lenguaje declarativo en QML. En la segunda parte, agregaremos funcionalidad para cargar y guardar un archivo mediante Qt C. Usaremos Meta-Object System de Qt para exponer funciones C''+ como propiedades para que puedan ser usadas por elementos QML. Al utilizar QML y Qt C++ podemos desacoplar eficientemente la lógica de la interfaz de usuario, de la lógica de la aplicación.


La aplicación que estamos construyendo es un editor de texto simple que va a cargar, guardar y realizar alguna manipulación de texto. Esta guía constará de dos partes. La primera parte consistirá en diseñar la interfaz de la aplicación y sus comportamientos (behaviors) utilizando lenguaje declarativo en <span class="caps">QML</span>. En la segunda parte, agregaremos funcionalidad para cargar y guardar un archivo mediante Qt C++. Usaremos Meta-Object System de Qt para exponer funciones C++ como propiedades para que puedan ser usadas por elementos <span class="caps">QML</span>. Al utilizar <span class="caps">QML</span> y Qt C++ podemos desacoplar eficientemente la lógica de la interfaz de usuario, de la lógica de la aplicación.
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png]]


[[Image:qml-texteditor5_editmenu.png]]
Para ejecutar el código de ejemplo de QML, simplemente provea el archivo QML como argumento a la herramienta qmlviewer incluida. La porción de C++ de este tutorial asume que el lector posee conocimiento básico sobre el procedimiento de compilación de Qt.


Para ejecutar el código de ejemplo de <span class="caps">QML</span>, simplemente provea el archivo <span class="caps">QML</span> como argumento a la herramienta qmlviewer incluida. La porción de C++ de este tutorial asume que el lector posee conocimiento básico sobre el procedimiento de compilación de Qt.
Capítulos del tutorial:<br /># Definiendo un Botón y un Menú<br /># Implementando una Barra de Menús<br /># Construyendo un Editor de Texto<br /># Decorando el Editor de Texto<br /># Extendiendo QML utilizando Qt C++


Capítulos del tutorial:
== Definiendo un Botón y un Menú ==


# Definiendo un Botón y un Menú
=== Componente Básico - un Botón ===
# Implementando una Barra de Menús
# Construyendo un Editor de Texto
# Decorando el Editor de Texto
# Extendiendo <span class="caps">QML</span> utilizando Qt C++
 
==Definiendo un Botón y un Menú==
 
===Componente Básico un Botón===


Comenzamos nuestro editor de textos construyendo un botón. Funcionalmente, un botón tiene un área sensitiva al mouse y una etiqueta. Los botones realizan acciones cuando un usuario los presiona.
Comenzamos nuestro editor de textos construyendo un botón. Funcionalmente, un botón tiene un área sensitiva al mouse y una etiqueta. Los botones realizan acciones cuando un usuario los presiona.


En <span class="caps">QML</span>, el elemento visual básico es el elemento Rectangle (Rectángulo). El elemento Rectangle tiene propiedades para controlar su apariencia y ubicación.
En QML, el elemento visual básico es el elemento Rectangle (Rectángulo). El elemento Rectangle tiene propiedades para controlar su apariencia y ubicación.


Primero, la importación de Qt 4.7 permite que la herramienta qmlviewer importe los elementos <span class="caps">QML</span> que usaremos más tarde. Esta línea debe existir para cada archivo <span class="caps">QML</span>.<br /> Note que la versión de los módulos de Qt se incluye en sentencia de importación
Primero, la importación de Qt 4.7 permite que la herramienta qmlviewer importe los elementos QML que usaremos más tarde. Esta línea debe existir para cada archivo QML.<br />Note que la versión de los módulos de Qt se incluye en sentencia de importación


Este simple rectángulo tiene un identificador único, simplebutton (botón simple), el cual está ligado a la propiedad id. Las propiedades del elemento Rectangle se enlazan con valores listando la propiedad seguida de dos puntos :, y después el valor. En el código de ejemplo, el color gris está ligado con la propiedad color del Rectángulo. De manera similar, enlazamos el ancho y el alto del Rectángulo
Este simple rectángulo tiene un identificador único, simplebutton (botón simple), el cual está ligado a la propiedad id. Las propiedades del elemento Rectangle se enlazan con valores listando la propiedad seguida de dos puntos ':', y después el valor. En el código de ejemplo, el color gris está ligado con la propiedad color del Rectángulo. De manera similar, enlazamos el ancho y el alto del Rectángulo


El elemento Text (Texto) es un campo de texto no editable. Nombramos a este elemento Text como buttonLabel. Para establecer el contenido del campo de texto, enlazamos un valor a su propiedad text. La etiqueta está contenida dentro del Rectángulo y con el fin de centrarla, asignamos las anchors (anclas) del elemento Text a su padre, el cual es llamado simplebutton. Las anchors se pueden enlazar con las anchors de otros elementos, permitiendo que las asignaciones de layouts sean más simples.
El elemento Text (Texto) es un campo de texto no editable. Nombramos a este elemento Text como buttonLabel. Para establecer el contenido del campo de texto, enlazamos un valor a su propiedad text. La etiqueta está contenida dentro del Rectángulo y con el fin de centrarla, asignamos las anchors (anclas) del elemento Text a su padre, el cual es llamado simplebutton. Las anchors se pueden enlazar con las anchors de otros elementos, permitiendo que las asignaciones de layouts sean más simples.
Line 35: Line 29:
Vamos a guardar este código como SimpleButton.qml. Ejecutar el qmlviewer con este archivo como argumento mostrará el rectángulo gris con una etiqueta de texto.
Vamos a guardar este código como SimpleButton.qml. Ejecutar el qmlviewer con este archivo como argumento mostrará el rectángulo gris con una etiqueta de texto.


[[Image:qml-texteditor1_simplebutton.png]]
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_simplebutton.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor1_simplebutton.png]]
 
Para implementar la funcionalidad de click del botón, podemos utilizar el manejo de eventos de QML. El manejo de eventos de QML es muy similar a el mecanismo de Signals y Slots (Señales y Ranuras) de Qt. Las Signals se emiten y el Slot conectado es invocado.
 
<code>Rectangle{<br /> id:simplebutton<br /> …


Para implementar la funcionalidad de click del botón, podemos utilizar el manejo de eventos de <span class="caps">QML</span>. El manejo de eventos de <span class="caps">QML</span> es muy similar a el mecanismo de Signals y Slots (Señales y Ranuras) de Qt. Las Signals se emiten y el Slot conectado es invocado.
MouseArea{<br /> id: buttonMouseArea


Incluimos un elemento MouseArea (Área de Mouse) en nuestro elemento simplebutton. El elemento MouseArea describe el área interactiva en dónde los movimientos del mouse son detectados. Para nuestro botón, anclamos el MouseArea completa a su padre, el cual es simplebutton. La sintaxis anchors.fill es una manera de acceder a una propiedad específica llamada fill dentro de un grupo de propiedades llamadas anchors. <span class="caps">QML</span> utiliza layouts basados en anchors en dónde los items se pueden anclar a otros items, creando layouts robustos.
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 />}</code>
 
Incluimos un elemento MouseArea (Área de Mouse) en nuestro elemento simplebutton. El elemento MouseArea describe el área interactiva en dónde los movimientos del mouse son detectados. Para nuestro botón, anclamos el MouseArea completa a su padre, el cual es simplebutton. La sintaxis anchors.fill es una manera de acceder a una propiedad específica llamada fill dentro de un grupo de propiedades llamadas anchors. QML utiliza layouts basados en anchors en dónde los items se pueden anclar a otros items, creando layouts robustos.


El MouseArea tiene muchos manejadores (handlers) de signals que son llamados durante los movimientos del mouse realizados dentro de los límites especificados por el MouseArea. Uno de ellos es onClicked, el cual es llamado cuando el botón de aceptar del mouse se presiona, siendo el botón izquierdo el botón aceptar por defecto. Podemos enlazar acciones al manejador onClicked. En nuestro ejemplo, console.log() imprime texto en pantalla cada vez que se hace click sobre el área de mouse. La función console.log() es una herramienta útil para propósitos de depuración y para mostrar texto en pantalla.
El MouseArea tiene muchos manejadores (handlers) de signals que son llamados durante los movimientos del mouse realizados dentro de los límites especificados por el MouseArea. Uno de ellos es onClicked, el cual es llamado cuando el botón de aceptar del mouse se presiona, siendo el botón izquierdo el botón aceptar por defecto. Podemos enlazar acciones al manejador onClicked. En nuestro ejemplo, console.log() imprime texto en pantalla cada vez que se hace click sobre el área de mouse. La función console.log() es una herramienta útil para propósitos de depuración y para mostrar texto en pantalla.


El código en SimpleButton.qml es suficiente para mostrar un botón en la pantalla e imprimir texto en pantalla cada vez que se hace click con el mouse sobre el botón.
El código en SimpleButton.qml es suficiente para mostrar un botón en la pantalla e imprimir texto en pantalla cada vez que se hace click con el mouse sobre el botón.
<code>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 />}</code>


Un botón completamente funcional se encuentra en Button.qml. En el fragmento de código de este artículo se omite cierto código, el cual se denota por puntos suspensivos, debido a que se presentó en secciones anteriores o a que es irrelevante para la discusión del código de la sección actual.
Un botón completamente funcional se encuentra en Button.qml. En el fragmento de código de este artículo se omite cierto código, el cual se denota por puntos suspensivos, debido a que se presentó en secciones anteriores o a que es irrelevante para la discusión del código de la sección actual.


Las propiedades personalizadas se declaran utilizando la sintaxis tipo de propiedad, nombre. En el código, la propiedad buttonColor (Color de Botón), de tipo color, se declara y enlaza al valor “lightblue” (azul claro). La propiedad buttonColor se utiliza más tarde en una operación condicional para determinar el color de relleno del botón. Note que la asignación de un valor a una propiedad es posible utilizando el signo igual =, en adición al enlace de de valores utilizando el carácter dos puntos :. Las propiedades personalizadas permiten que los elementos internos sean accesibles desde fuera del ámbito del Rectángulo. Existen tipos básicos <span class="caps">QML</span> como int, string, real y también un tipo llamado variant.
Las propiedades personalizadas se declaran utilizando la sintaxis tipo de propiedad, nombre. En el código, la propiedad buttonColor (Color de Botón), de tipo color, se declara y enlaza al valor &quot;lightblue&amp;quot; (azul claro). La propiedad buttonColor se utiliza más tarde en una operación condicional para determinar el color de relleno del botón. Note que la asignación de un valor a una propiedad es posible utilizando el signo igual '=', en adición al enlace de de valores utilizando el carácter dos puntos ':'. Las propiedades personalizadas permiten que los elementos internos sean accesibles desde fuera del ámbito del Rectángulo. Existen tipos básicos QML como int, string, real y también un tipo llamado variant.


Mediante el enlace de los manejadores de señal onEntered y onExited, el borde de los botones cambiará a amarillo cuando el mouse se coloque encima del botón y el cambio de color se revertirá cuando el mouse salga del área de mouse.
Mediante el enlace de los manejadores de señal onEntered y onExited, el borde de los botones cambiará a amarillo cuando el mouse se coloque encima del botón y el cambio de color se revertirá cuando el mouse salga del área de mouse.
Line 53: Line 63:
La signal buttonClick está declarada en Button.qml mediante la colocación de la palabra clave signal frente al nombre de la signal Los manejadores de las signals se crean automáticamente con su nombre comenzando con on. Como resultado, onButtonClick es el manejador de buttonClick. Entonces a onButtonClick se le asigna una acción para realizar. En nuestro ejemplo de botón, el manejador de onClicked simplemente invocará onButtonClick, el cual mostrará algún texto. onButtonClick permite que los objetos externos accedan al área de mouse del botón de manera sencilla. (?)Por ejemplo, los elementos podrían tener más una declaración de MouseArea y una signal buttonClick puede mejorar la distinción entre los distintos manejadores de signals del MouseArea(?).
La signal buttonClick está declarada en Button.qml mediante la colocación de la palabra clave signal frente al nombre de la signal Los manejadores de las signals se crean automáticamente con su nombre comenzando con on. Como resultado, onButtonClick es el manejador de buttonClick. Entonces a onButtonClick se le asigna una acción para realizar. En nuestro ejemplo de botón, el manejador de onClicked simplemente invocará onButtonClick, el cual mostrará algún texto. onButtonClick permite que los objetos externos accedan al área de mouse del botón de manera sencilla. (?)Por ejemplo, los elementos podrían tener más una declaración de MouseArea y una signal buttonClick puede mejorar la distinción entre los distintos manejadores de signals del MouseArea(?).


Ahora tenemos el conocimiento básico para implementar elementos en <span class="caps">QML</span> que puedan manejar movimientos básicos del mouse. Creamos una etiqueta de Texto dentro de un Rectángulo, personalizamos sus propiedades, e implementamos comportamientos que responden a los movimientos del mouse. Está idea de crear elementos dentro de elementos se repite a través de toda la aplicación del editor de textos.
Ahora tenemos el conocimiento básico para implementar elementos en QML que puedan manejar movimientos básicos del mouse. Creamos una etiqueta de Texto dentro de un Rectángulo, personalizamos sus propiedades, e implementamos comportamientos que responden a los movimientos del mouse. Está idea de crear elementos dentro de elementos se repite a través de toda la aplicación del editor de textos.


Este botón no es útil a menos que se utilice como componente para realizar una acción. En la siguiente sección, pronto crearemos un menú que contenga varios de estos botones.
Este botón no es útil a menos que se utilice como componente para realizar una acción. En la siguiente sección, pronto crearemos un menú que contenga varios de estos botones.


[[Image:qml-texteditor1_button.png]]
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_button.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor1_button.png]]
 
=== Creando una Página de Menú ===


===Creando una Página de Menú===
Hasta este momento, hemos cubierto como crear elementos y asignar comportamientos dentro de un sólo archivo QML. En esta sección, cubriremos como importar elementos QML y como reutilizar algunos de los componentes creados para construir otros componentes.


Hasta este momento, hemos cubierto como crear elementos y asignar comportamientos dentro de un sólo archivo <span class="caps">QML</span>. En esta sección, cubriremos como importar elementos <span class="caps">QML</span> y como reutilizar algunos de los componentes creados para construir otros componentes.
Los Menús muestran el contenido de una lista, cada elemento posee la habilidad de realizar alguna acción. En QML, podemos crear un menú de varias maneras. Primero, crearemos un menú que contenga botones, los cuales eventualmente realizarán diferentes acciones. El código del menú está en FileMenu.qml


Los Menús muestran el contenido de una lista, cada elemento posee la habilidad de realizar alguna acción. En <span class="caps">QML</span>, podemos crear un menú de varias maneras. Primero, crearemos un menú que contenga botones, los cuales eventualmente realizarán diferentes acciones. El código del menú está en FileMenu.qml
<code>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 sintaxis mostrada arriba muestra como utilizar la palabra clave import. Ésto se requiere para utilizar archivos JavaScript o <span class="caps">QML</span> que no están en el mismo directorio. Debido a que Button.qml está en el mismo directorio que FileMenu.qml, no necesitamos importar el archivo Button.qml para utilizarlo. Podemos directamente crear un elemento Button declarando Button{}, similar a la declaración de Rectangle{}.
La sintaxis mostrada arriba muestra como utilizar la palabra clave import. Ésto se requiere para utilizar archivos JavaScript o QML que no están en el mismo directorio. Debido a que Button.qml está en el mismo directorio que FileMenu.qml, no necesitamos importar el archivo Button.qml para utilizarlo. Podemos directamente crear un elemento Button declarando Button{}, similar a la declaración de Rectangle{}.


En FileMenu.qml:
En FileMenu.qml:
<code>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 />}</code>


En FileMenu.qml, declaramos tres elementos Button. Están declarados dentro de un elemento Row (Fila), el cual posicionará a sus hijos a lo largo de una fila vertical. La declaración del Botón reside en Button.qml, el cual es el mismo Button.qml que utilizamos en la sección previa. Se pueden declarar nuevos enlaces de propiedades dentro de los nuevos botones creados, sobrescribiendo efectivamente las propiedades establecidas en Button.qml. El botón llamado exitButton (Botón Salir) cerrará la ventana y terminará la aplicación cuando se presione. Note que el manejador de signal onButtonClick en Button.qml será invocado en adición al manejador onButtonClick en exitButton.
En FileMenu.qml, declaramos tres elementos Button. Están declarados dentro de un elemento Row (Fila), el cual posicionará a sus hijos a lo largo de una fila vertical. La declaración del Botón reside en Button.qml, el cual es el mismo Button.qml que utilizamos en la sección previa. Se pueden declarar nuevos enlaces de propiedades dentro de los nuevos botones creados, sobrescribiendo efectivamente las propiedades establecidas en Button.qml. El botón llamado exitButton (Botón Salir) cerrará la ventana y terminará la aplicación cuando se presione. Note que el manejador de signal onButtonClick en Button.qml será invocado en adición al manejador onButtonClick en exitButton.


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


La declaración de Row está declarada dentro de un Rectangle, creando un rectángulo contenedor para las filas de botones. Este rectángulo adicional crea una manera indirecta de organizar las filas de botones dentro de un menú
La declaración de Row está declarada dentro de un Rectangle, creando un rectángulo contenedor para las filas de botones. Este rectángulo adicional crea una manera indirecta de organizar las filas de botones dentro de un menú
Line 77: Line 95:
La declaración del menú edit (editar) es muy similar en esta etapa. El menú tiene botones con las etiquetas: Copy (Copiar), Paste (Pegar), y Select All (Seleccionar Todo).
La declaración del menú edit (editar) es muy similar en esta etapa. El menú tiene botones con las etiquetas: Copy (Copiar), Paste (Pegar), y Select All (Seleccionar Todo).


[[Image:qml-texteditor1_editmenu.png]]
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor1_editmenu.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor1_editmenu.png]]
 
Armados con nuestro conocimiento de importar y personalizar componentes previamente creados, ahora podemos combinar estas páginas de menú para crear una barra de menús, que consiste en botones para seleccionar el menú, y mire como podemos estructurar datos utilizando QML.


Armados con nuestro conocimiento de importar y personalizar componentes previamente creados, ahora podemos combinar estas páginas de menú para crear una barra de menús, que consiste en botones para seleccionar el menú, y mire como podemos estructurar datos utilizando <span class="caps">QML</span>.
== Implementando una Barra de Menús ==


==Implementando una Barra de Menús==
Nuestra aplicación de editor de textos necesitará una manera de mostrar menús utilizando una barra de menús. La barra de menús realizará los cambios entre los diferentes menús y el usuario puede elegir cual menú desplegar.<br />El cambió de menú implica que los menús necesitan más estructura que simplemente mostrarlos en una fila. QML utiliza modelos y vistas para estructurar datos y mostrar los datos estructurados.


Nuestra aplicación de editor de textos necesitará una manera de mostrar menús utilizando una barra de menús. La barra de menús realizará los cambios entre los diferentes menús y el usuario puede elegir cual menú desplegar.<br /> El cambió de menú implica que los menús necesitan más estructura que simplemente mostrarlos en una fila. <span class="caps">QML</span> utiliza modelos y vistas para estructurar datos y mostrar los datos estructurados.
=== Utilizando Modelos de Datos y Vistas ===


===Utilizando Modelos de Datos y Vistas===
QML tiene diferentes vistas de datos para mostrar modelos. Nuestra barra de menús mostrará los menús en una lista, con el encabezado mostrando una fila con los nombres de los menús. La lista de menús se declara dentro de un VisualItemModel. El elemento VisualItemModel contiene elementos que ya tienen vistas, como elementos Rectangle y elementos de Interfaz de Usuario importados. Otrostipos de modelo como el elemento ListModel necesitan un delegate para mostrar su información.


<span class="caps">QML</span> tiene diferentes vistas de datos para mostrar modelos. Nuestra barra de menús mostrará los menús en una lista, con el encabezado mostrando una fila con los nombres de los menús. La lista de menús se declara dentro de un VisualItemModel. El elemento VisualItemModel contiene elementos que ya tienen vistas, como elementos Rectangle y elementos de Interfaz de Usuario importados. Otrostipos de modelo como el elemento ListModel necesitan un delegate para mostrar su información.
Declaramos dos elementos visuales en el menuListModel, el FileMenu y el EditMenu. Personalizamos los dos menús y los mostramos utilizando una ListView. El archivo MenuBar.qml contiene las declaraciones QML y en EditMenu.qml un simple menu edit está definido.


Declaramos dos elementos visuales en el menuListModel, el FileMenu y el EditMenu. Personalizamos los dos menús y los mostramos utilizando una ListView. El archivo MenuBar.qml contiene las declaraciones <span class="caps">QML</span> y en EditMenu.qml un simple menu edit está definido.
<code>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 />}</code>


El elemento ListView mostrará un modelo de acuerdo a un delegate. El delegate declarará los elemento del modelo de manera que se muestren en un elemento Row o en un grid. Nuestro menuListModel ya tiene elementos visibles, por lo tanto, no necesitamos declarar un delegate.
El elemento ListView mostrará un modelo de acuerdo a un delegate. El delegate declarará los elemento del modelo de manera que se muestren en un elemento Row o en un grid. Nuestro menuListModel ya tiene elementos visibles, por lo tanto, no necesitamos declarar un delegate.
<code>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 />}</code>


Adicionalmente, ListView hereda de Flickable, haciendo que la lista responda al arrastre del mouse y otros gestos. La última porción del código de arriba establece las propiedades de Flickable para crear el movimiento de deslizamiento (flicking) que deseamos en nuestra vista. En particular, la propiedad highlightMoveDuration cambia la duración de la transición de deslizamiento. Un valor más alto de la propiedad highlightMoveDuration da como resultado un cambio de menú más lento.
Adicionalmente, ListView hereda de Flickable, haciendo que la lista responda al arrastre del mouse y otros gestos. La última porción del código de arriba establece las propiedades de Flickable para crear el movimiento de deslizamiento (flicking) que deseamos en nuestra vista. En particular, la propiedad highlightMoveDuration cambia la duración de la transición de deslizamiento. Un valor más alto de la propiedad highlightMoveDuration da como resultado un cambio de menú más lento.
Line 98: Line 126:


El rectángulo labelList tiene valor z de 1, denotando que será mostrado frente a la barra de menús. Los elementos con un valor de z más alto se muestran por sobre elementos con valores menores de z. El valor por defecto para z es 0.
El rectángulo labelList tiene valor z de 1, denotando que será mostrado frente a la barra de menús. Los elementos con un valor de z más alto se muestran por sobre elementos con valores menores de z. El valor por defecto para z es 0.
<code>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 />}</code>


Podemos acceder a los menús de la barra de herramientas que acabamos de crear deslizando hacia los menús o presionando los nombres de los menús de la parte superior. El cambio entre las pantallas del menú se siente intuitivo y responsivo.
Podemos acceder a los menús de la barra de herramientas que acabamos de crear deslizando hacia los menús o presionando los nombres de los menús de la parte superior. El cambio entre las pantallas del menú se siente intuitivo y responsivo.


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


==Construyendo un Editor de Texto==
== Construyendo un Editor de Texto ==


===Declarando un Área de Texto (TextArea)===
=== Declarando un Área de Texto (TextArea) ===


Nuestro editor de texto no es un editor de texto si no contiene un área para editar texto. El elemento TextEdit de <span class="caps">QML</span> permite la declaración de un área multilínea de texto editable. TextEdit es diferente de un elemento Text, el cual no permite al usuario editar el texto directamente.
Nuestro editor de texto no es un editor de texto si no contiene un área para editar texto. El elemento TextEdit de QML permite la declaración de un área multilínea de texto editable. TextEdit es diferente de un elemento Text, el cual no permite al usuario editar el texto directamente.


El editor tiene establecidas las propiedades de color y ajuste de texto. El área de edición de texto está dentro de un área deslizable que desplazará el texto si el cursor está fuera del área visible. La función ensureVisible() verificará si el rectángulo del cursor está fuera de los límites de visibilidad y moverá el área de texto de acuerdo a esto. <span class="caps">QML</span> utiliza sintáxist de Javascript para sus scripts, y como se menciono previamente, los archivos Javascript se pueden importar y utilizar en un archivo <span class="caps">QML</span>.
<code>TextEdit{<br /> id: textEditor<br /> anchors.fill:parent<br /> width:parent.width; height:parent.height<br /> color:&quot;midnightblue&amp;quot;<br /> focus: true


===Combinando Componentes para el Editor de Texto===
wrapMode: TextEdit.Wrap


Ahora estamos listos para crear el diseño de nuestro editor de texto utilizando <span class="caps">QML</span>. El editor de texto tiene dos componentes, la barra de menús que creamos y el área de texto. <span class="caps">QML</span> nos permite reutilizar componentes, haciendo nuestro código más simple, importanto componentes y personalizándolos cuándo sea necesario. Nuestro editor de texto divide la ventana en dos; un tercio de la pantalla está dedicado a la barra de menús y dos tercios de la pantalla muestran el área de texto. La barra de menús se muestra en frente de cualquier otro elementos.
onCursorRectangleChanged: flickArea.ensureVisible(cursorRectangle)<br />}</code>


Mediante la importación de componentes reutilizables, el código de nuestro Editor de Texto se ve mucho más simple. Ahora podemos personalizar la aplicación principal sin preocuparnos acerca de propiedades que ya tiene comportamientos definidos. Utilizando este enfoque, se puede crear fácilmente tanto el diseño de la aplicación como componentes de UI.
El editor tiene establecidas las propiedades de color y ajuste de texto. El área de edición de texto está dentro de un área deslizable que desplazará el texto si el cursor está fuera del área visible. La función ensureVisible() verificará si el rectángulo del cursor está fuera de los límites de visibilidad y moverá el área de texto de acuerdo a esto. QML utiliza sintáxist de Javascript para sus scripts, y como se menciono previamente, los archivos Javascript se pueden importar y utilizar en un archivo QML.


[[Image:qml-texteditor3_texteditor.png]]
<code>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 />}</code>


==Decorando el Editor de texto==
=== Combinando Componentes para el Editor de Texto ===


===Implementando una Interfaz Drawer===
Ahora estamos listos para crear el diseño de nuestro editor de texto utilizando QML. El editor de texto tiene dos componentes, la barra de menús que creamos y el área de texto. QML nos permite reutilizar componentes, haciendo nuestro código más simple, importanto componentes y personalizándolos cuándo sea necesario. Nuestro editor de texto divide la ventana en dos; un tercio de la pantalla está dedicado a la barra de menús y dos tercios de la pantalla muestran el área de texto. La barra de menús se muestra en frente de cualquier otro elementos.


Nuestro Editor de Texto parece simple y por lo tanto es necesario que lo decoremos. Utilizando <span class="caps">QML</span>, podemos declarar las transiciones y la animación de nuestro Editor de Texto. Nuestra barra de menú está ocupando un tercio de la pantalla y seria bueno que solo apareciera cuando lo deseemos.
<code>Rectangle{


Podemos añadir una Interfaz Drawer, que minimice o expanda la barra de menú cuando se hace click. En nuestra implementación, tenemos un rectángulo delgado que responde a los click del mouse. El drawer, así como la aplicación, tienen dos estados: el estado “drawer is open” y el estado “drawer is closed”. El elemento drawer es una franja del rectángulo con una pequeña altura. Hay un elemento anidado Imagen que declara que un icono arrow será centrado dentro del drawer. El drawer asigna un estado a toda la aplicación, con el identificador de pantalla(screen), cada vez que un usuario haga clic en el área del mouse.
id: screen<br /> width: 1000; height: 1000


Un estado es simplemente una colección de configuraciones las cuales son declaradas en un elemento '''State'''. Una lista de los estados pueden ser listadas y ligadas a la propiedad states. En nuestras aplicación, los dos estados son lamados <span class="caps">DRAWER</span>_OPEN Y <span class="caps">DRAWER</span>_CLOSED. Las configuraciones de los elementos son declaradas en la PorpertyChanges. En el estados <span class="caps">DRAWER</span>_OPEN, hay cuatro elementos que recibirán los cambios de propiedad (PropertyChanges). El primer objeto, menuBar cambiará su '''y''' propiedad a 0. Del mismo modo, el objeto textArea descenderá auna nueva posición cuando el estado <span class="caps">DRAWER</span>_OPEN este activado. La textArea, el drawer, y el icono de drawer se someterán a los cambios de propiedad para cumplir con el estado actual.
//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


Los cambios de estado son bruscos por ello es recomendable aplicar transiciones para suavizarlos. Las transiciones entre los estados se definen mediante el elemento '''Transition''', que puede enlazarse a los elementos dentro de la propiedad '''transitions'''. Nuestro editor de texto tiene una transición de estado cuando el estado cambia a <span class="caps">DRAWER</span>_OPEN o <span class="caps">DRAWER</span>_CLOSED. Es importante destacar que es necesario un estado de transición '''from''' y un '''to''', pero para nuestra transición, podemos utilizar el símbolo * para indicar que la transición se aplica a todos los cambios de estado.
MenuBar{<br /> id:menuBar<br /> height: partition<br /> width:parent.width<br /> z: 1<br /> }


Durante las transiciones, podemos asignar animaciones a los cambios de propiedad. Nuestra menuBar cambia de la posición de y:0 a y:-partition y se puede animar esta transición mediante el elemento '''NumberAnimation'''. Declaramos que las propiedades de los objetos van a animarse por un período de tiempo determinado y con una curva de aceleración determinada. Una curva de aceleración controla el comportamiento de las tasas de animación y la interpolación en las transiciones de estado. La curva de aceleración que elegimos es '''Easing.OutQuint''', que retarda el movimiento hacia el final de la animación. Lea atentamente el artículo [http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html <span class="caps">QML</span>’s Animation] ''[doc.qt.nokia.com]''.
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 />}</code>


Otra manera de animar a los cambios de propiedad es declarando un elemento de comportamiento ([http://doc.qt.nokia.com/4.7/qml-behavior.html Behavior] ''[doc.qt.nokia.com]''). Una transición sólo funciona durante los cambios de estado y el comportamiento puede establecer una animación para un cambio de propiedad en general. En el editor de texto, la flecha tiene un comportamiento NumberAnimation que anima su propiedad rotation cada vez que cambia la propiedad.
Mediante la importación de componentes reutilizables, el código de nuestro Editor de Texto se ve mucho más simple. Ahora podemos personalizar la aplicación principal sin preocuparnos acerca de propiedades que ya tiene comportamientos definidos. Utilizando este enfoque, se puede crear fácilmente tanto el diseño de la aplicación como componentes de UI.


Volviendo a nuestros componentes con el conocimiento de los estados y las animaciones, podemos mejorar la apariencia de los componentes. En Button.qml, podemos añadir los cambios a la propiedad color y scale cuando se pulsa el botón. Los tipos color son animados usando ColorAnimation y los números son animados con NumberAnimation. La sintaxis de propertyName on que aparecen a continuación es de gran ayuda al elegir una sola propiedad.
[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor3_texteditor.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor3_texteditor.png]]


Además, podemos mejorar la apariencia de nuestros componentes <span class="caps">QML</span> mediante la adición de efectos de color tales como gradientes y efectos de opacidad. La declaración de un elemento '''Gradient''' anulará la propiedad color del elemento. Usted puede declarar un color en el gradient mediante el elemento '''GradientStop'''. El gradiente se coloca utilizando una escala, entre 0.0 y 1.0.
== Decorando el Editor de texto ==


Este gradiente es utilizado por la barra de menús para mostrar una simulación del gradiente de profundidad. El primer color empieza en 0.0 y el último color es de 1.0.
=== Implementando una Interfaz Drawer ===


====A dónde ir desde aquí====
Nuestro Editor de Texto parece simple y por lo tanto es necesario que lo decoremos. Utilizando QML, podemos declarar las transiciones y la animación de nuestro Editor de Texto. Nuestra barra de menú está ocupando un tercio de la pantalla y seria bueno que solo apareciera cuando lo deseemos.


Hemos terminado la construcción de la interfaz de usuario de un editor de texto muy simple. En el futuro, se completara la interfaz de usuario, y podemos aplicar la lógica de la aplicación haciendo uso regular de Qt y C++. <span class="caps">QML</span> funciona muy bien como una herramienta de creación de prototipos, que separa la lógica de la aplicación de distancia de el diseño de interfaz de usuario.
Podemos añadir una Interfaz Drawer, que minimice o expanda la barra de menú cuando se hace click. En nuestra implementación, tenemos un rectángulo delgado que responde a los click del mouse. El drawer, así como la aplicación, tienen dos estados: el estado &quot;drawer is open&amp;quot; y el estado &quot;drawer is closed&amp;quot;. El elemento drawer es una franja del rectángulo con una pequeña altura. Hay un elemento anidado Imagen que declara que un icono arrow será centrado dentro del drawer. El drawer asigna un estado a toda la aplicación, con el identificador de pantalla(screen), cada vez que un usuario haga clic en el área del mouse.


[[Image:qml-texteditor4_texteditor.png]]
<code> Rectangle{<br /> id:drawer<br /> height:15


===Extendiendo <span class="caps">QML</span> utilizando C++===
Image{<br /> id: arrowIcon<br /> source: &quot;images/arrow.png&amp;quot;<br /> anchors.horizontalCenter: parent.horizontalCenter<br /> }


Ahora que tenemos el diseño de nuestro editor de textos, podemos implementar su funcionalidad utilizando C++. Utilizar <span class="caps">QML</span> con C++ nos permite crear la lógica de nuestra aplicación utilizando Qt. Podemos crear un contexto <span class="caps">QML</span> en una aplicación C++ utilizando las clases de Qt Declarative y mostrar los elementos utilizando un Graphics Scene. De manera alternativa, podemos exportar nuestro código C++ en un plugin que la herramienta qmlviewer puede leer. Para nuestra aplicación, implementaremos las funciones abrir y guardar en C++ y las exportaremos como un plugin. De esta manera, podremos cargar el archivo <span class="caps">QML</span> de manera directa en lugar de utilizar un ejecutable.
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 /> }</code>


====Exponiendo clases C++ a <span class="caps">QML</span>====
Un estado es simplemente una colección de configuraciones las cuales son declaradas en un elemento '''State'''. Una lista de los estados pueden ser listadas y ligadas a la propiedad states. En nuestras aplicación, los dos estados son lamados DRAWER_OPEN Y DRAWER_CLOSED. Las configuraciones de los elementos son declaradas en la PorpertyChanges. En el estados DRAWER_OPEN, hay cuatro elementos que recibirán los cambios de propiedad (PropertyChanges). El primer objeto, menuBar cambiará su '''y''' propiedad a 0. Del mismo modo, el objeto textArea descenderá auna nueva posición cuando el estado DRAWER_OPEN este activado. La textArea, el drawer, y el icono de drawer se someterán a los cambios de propiedad para cumplir con el estado actual.


Implementaremos la apertura y guardado de archivos utilizando Qt y C++. Al registrar las clases y funciones de C++ podemos utilizarlas en <span class="caps">QML</span>. La clase necesita ser compilada como un plugin de Qt y el archivo <span class="caps">QML</span> necesita saber en dónde se localiza el plugin.
<code>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>


Para nuestra aplicación, necesitamos crear los siguientes elementos:
Los cambios de estado son bruscos por ello es recomendable aplicar transiciones para suavizarlos. Las transiciones entre los estados se definen mediante el elemento '''Transition''', que puede enlazarse a los elementos dentro de la propiedad '''transitions'''. Nuestro editor de texto tiene una transición de estado cuando el estado cambia a DRAWER_OPEN o DRAWER_CLOSED. Es importante destacar que es necesario un estado de transición '''from''' y un '''to''', pero para nuestra transición, podemos utilizar el símbolo * para indicar que la transición se aplica a todos los cambios de estado.


# Una clase Directory que se encargará de las operaciones relacionadas con los directorios
Durante las transiciones, podemos asignar animaciones a los cambios de propiedad. Nuestra menuBar cambia de la posición de y:0 a y:-partition y se puede animar esta transición mediante el elemento '''NumberAnimation'''. Declaramos que las propiedades de los objetos van a animarse por un período de tiempo determinado y con una curva de aceleración determinada. Una curva de aceleración controla el comportamiento de las tasas de animación y la interpolación en las transiciones de estado. La curva de aceleración que elegimos es '''Easing.OutQuint''', que retarda el movimiento hacia el final de la animación. Lea atentamente el artículo &quot;QML's Animation&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html.
# Una clase File el cual es un QObject, que simula la lista de archivos en un directorio
# Una clase plugin que registrará la clase en el contexto <span class="caps">QML</span>
# Un archivo de proyecto de Qt para compilar el plugin
# Un archivo qmldir que le indique a la herramienta qmlviewer dónde encontrar el plugin


====Construyendo un plugin de Qt====
<code>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>


Para construir un plugin, necesitamos establecer lo siguiente en un archivo de proyecto de Qt. Primero, es necesario agregar los archivos de encabezado, de código fuente y los módulos de Qt en nuestro archivo de proyecto. Todos los archivos de proyecto y de código C++ están ene el directorio filedialog.
Otra manera de animar a los cambios de propiedad es declarando un elemento de comportamiento (&quot;Behavior&amp;quot;:http://doc.qt.nokia.com/4.7/qml-behavior.html). Una transición sólo funciona durante los cambios de estado y el comportamiento puede establecer una animación para un cambio de propiedad en general. En el editor de texto, la flecha tiene un comportamiento NumberAnimation que anima su propiedad rotation cada vez que cambia la propiedad.


En particular, compilamos Qt con el módulo declarativo y lo configuramos como un plugin, para esto necesitamos utilizar una plantilla de biblioteca (lib). Pondremos el plugin en el directorio de plugins del padre.
<code>In TextEditor.qml:


===Registrando una Clase en <span class="caps">QML</span>===
Behavior{<br /> NumberAnimation{property: &quot;rotation&amp;quot;;easing.type: Easing.OutExpo }<br /> }<br /></code>


Nuestra clase plugin, DialogPlugin es una subclase de [http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html QDeclarativeExtensionPlugin] ''[doc.qt.nokia.com]''. Necesitamos implementar la función heredada, registerTypes(). El archivo dialogPlugin.cpp es similar a esto:
Volviendo a nuestros componentes con el conocimiento de los estados y las animaciones, podemos mejorar la apariencia de los componentes. En Button.qml, podemos añadir los cambios a la propiedad color y scale cuando se pulsa el botón. Los tipos color son animados usando ColorAnimation y los números son animados con NumberAnimation. La sintaxis de propertyName on que aparecen a continuación es de gran ayuda al elegir una sola propiedad.


La función [http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registerTypes()] ''[doc.qt.nokia.com]'' registra nuestras clase File y Directory en <span class="caps">QML</span>. Esta función necesita el nombre de la clase para su plantilla, un número de versión mayor, un número de versión menor y un nombre para nuestras clases.
<code>In Button.qml:<br />


Necesitamos exportar el complemento utilizando la macro [http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2#q-export-plugin2 Q_EXPORT_PLUGIN2] ''[doc.qt.nokia.com]'' macro. Note que en nuestro archivo dialogPlugin.h, tenemos la macro [http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT Q_OBJECT] ''[doc.qt.nokia.com]'' en la parte superior de nuestra clase. Y también, necesitamos ejecutar qmake sobre el archivo del proyecto para generar el código meta-objeto necesario.
color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor<br /> Behavior on color { ColorAnimation{ duration: 55} }


===Creando Propiedades <span class="caps">QML</span> en una clase C++===
scale: buttonMouseArea.pressed ? 1.1 : 1.00<br /> Behavior on scale { NumberAnimation{ duration: 55} }<br /></code>


Podemos crear elementos y propiedades <span class="caps">QML</span> usando el [http://doc.qt.nokia.com/4.7/metaobjects.html Sistema de Meta-Objetos de Qt] ''[doc.qt.nokia.com]''. Podemos implementar propiedades utilizando signals y slots, haciendo que Qt esté conciente de estas propiedades. Entonces estas propiedades podrán ser utilizadas en <span class="caps">QML</span>.
Además, podemos mejorar la apariencia de nuestros componentes QML mediante la adición de efectos de color tales como gradientes y efectos de opacidad. La declaración de un elemento '''Gradient''' anulará la propiedad color del elemento. Usted puede declarar un color en el gradient mediante el elemento '''GradientStop'''. El gradiente se coloca utilizando una escala, entre 0.0 y 1.0.


Para el editor de texto, necesitamos ser capaces de cargar y guardar archivos. For the text editor, we need to be able to load and save files. Típicamente, estas funciones están contenidas en un diálogo de archivo. Afortunadamente, podemos utilizar [http://doc.qt.nokia.com/4.7/qdir.html QDir] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qfile.html QFile] ''[doc.qt.nokia.com]'', y [http://doc.qt.nokia.com/4.7/qtextstream.html QTextStream] ''[doc.qt.nokia.com]'' para implementar la lectura de directorios y flujos de entrada/salida.
<code>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>


La clase Directory utiliza el Sistema de Meta-Objetos de Qt para registrar propiedades que necesita para realizar el manejo de archivos. La clase Directory se exporta como un plugin y es utilizable en <span class="caps">QML</span> como el elemento Directory. Cada una de las propiedades listadas usando la macro [http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY Q_PROPERTY] ''[doc.qt.nokia.com]'' es una propiedad <span class="caps">QML</span>.
Este gradiente es utilizado por la barra de menús para mostrar una simulación del gradiente de profundidad. El primer color empieza en 0.0 y el último color es de 1.0.


La macro [http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY Q_PROPERTY] ''[doc.qt.nokia.com]'' declara una propiedad y sus funciones de lectura y escritura en el Sistema de Meta-Objetos de Qt. Por ejemplo, la propiedad filename, de tipo QString, puede ser leída utilizando la función filename() y puede ser escrita utilizando la función setFilename(). Adicionalmente, hay una señal asociada a la propiedad filename llamada filenameChanged(), la cual se emite cuando la propiedad cambia. Las funciones de lectura y escritura están declaradas como públicas en el archivo de encabezado.
==== A dónde ir desde aquí ====


De manera similar, tenemos las otras propiedades declaradas de acuerdo a sus usos. La propiedad filesCount indica el número de archivos en un directorio. La propiedad filename property se establece con el nombre del archivo seleccionado actualmente y el contenido del archivo guardado/cargado se almacena en la propiedad fileContent.
Hemos terminado la construcción de la interfaz de usuario de un editor de texto muy simple. En el futuro, se completara la interfaz de usuario, y podemos aplicar la lógica de la aplicación haciendo uso regular de Qt y C+''. QML funciona muy bien como una herramienta de creación de prototipos, que separa la lógica de la aplicación de distancia de el diseño de interfaz de usuario.
<br />[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor4_texteditor.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor4_texteditor.png]]
<br />h3. Extendiendo QML utilizando C''+


La propiedad files en una lista de todos los archivos filtrados en un directorio. La clase Directory se implementa para filtrar archivos de texto no válidos; solo los archivos con extensión .txt son válidos. Además, las [http://doc.qt.nokia.com/4.7/qlist.html QLists] ''[doc.qt.nokia.com]'' se pueden utilizar en archivos <span class="caps">QML</span> al declararlas como QDeclarativeListProperty en C++. El objeto plantilla necesita heredar de QObject, por lo tanto, la clase File también debe heredar de QObject. En la clase Directory, la lista de objetos File se almacena en una QList llamada m_fileList.
Ahora que tenemos el diseño de nuestro editor de textos, podemos implementar su funcionalidad utilizando C+''. Utilizar QML con C''+ nos permite crear la lógica de nuestra aplicación utilizando Qt. Podemos crear un contexto QML en una aplicación C++ utilizando las clases de Qt Declarative y mostrar los elementos utilizando un Graphics Scene. De manera alternativa, podemos exportar nuestro código C++ en un plugin que la herramienta qmlviewer puede leer. Para nuestra aplicación, implementaremos las funciones abrir y guardar en C++ y las exportaremos como un plugin. De esta manera, podremos cargar el archivo QML de manera directa en lugar de utilizar un ejecutable.


Las propiedades pueden entonces utilizarse en <span class="caps">QML</span> como parte de las propiedades del elemento Directory. Note que no necesitamos crear una propiedad identificador id en nuestro código C++.
==== Exponiendo clases C++ a QML ====


Las funciones normales de C++ también son accesibles desde <span class="caps">QML</span>. Las funciones cargar y guardar un archvio están implementadas en C++ y se declaran utilizando la macro [http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE Q_INVOKABLE] ''[doc.qt.nokia.com]''. De manera alternativa, podemos declarar las funciones como una ranura y las funciones serán accesibles desde <span class="caps">QML</span>.
Implementaremos la apertura y guardado de archivos utilizando Qt y C+''. Al registrar las clases y funciones de C''+ podemos utilizarlas en QML. La clase necesita ser compilada como un plugin de Qt y el archivo QML necesita saber en dónde se localiza el plugin.


La clase Directory también tiene que notificar a otros objetos cuando el contenido del directorio cambie. Esta función se realiza utilizando una signal. Como se mencionó previamente, las signals de <span class="caps">QML</span> tienen un manejador correspondiente con sus nombres precedidos por “on”. La signal tiene el nombre de directoryChanged y se emite cuando ocurre una actualización en un directorio. La actualización simplemente carga el contenido del directorio y actualiza la lista de archivos válidos en el directorio. Los elementos de <span class="caps">QML</span> pueden entonces ser notificados asignando una acción al manejador de signal onDirectoryChanged.
Para nuestra aplicación, necesitamos crear los siguientes elementos:


Las propiedades tipo lista necesitan se exploradas un poco más. Esto es porque las propiedades tipo lista utilizan callbacks para acceder y modificar los contenidos de la lista. La propiedad lista es de tipo QDeclarativeListProperty&lt;File&gt;. Siempre que se accede a la lista, la función de acceso necesita devolver una QDeclarativeListProperty&lt;File&gt;. El tipo plantilla, File, necesita heredar de QObject. Además, para crear una [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty] ''[doc.qt.nokia.com]'', los métodos de acceso y modificación de la lista necesitan enviarse al constructor como apuntadores a función. La lista, una QList en nuestro caso, también necesita ser una lista de apuntadores a File.
# Una clase Directory que se encargará de las operaciones relacionadas con los directorios
# Una clase File el cual es un QObject, que simula la lista de archivos en un directorio
# Una clase plugin que registrará la clase en el contexto QML
# Un archivo de proyecto de Qt para compilar el plugin
# Un archivo qmldir que le indique a la herramienta qmlviewer dónde encontrar el plugin


El constructor de [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html QDeclarativeListProperty] ''[doc.qt.nokia.com]'' y la implementación de Directory:
==== Construyendo un plugin de Qt ====


El constructor envía apuntadores a funciones que agregan elementos al final de la lista, cuentan sus elementos, obtienen un elemento utilizando un índice y vacían la lista. Solo la función de agregar es obligatoria. Note que los apuntadores a función deben coincidir con la definición de [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AppendFunction-typedef AppendFunction] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#CountFunction-typedef CountFunction] ''[doc.qt.nokia.com]'', [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#AtFunction-typedef AtFunction] ''[doc.qt.nokia.com]'', o [http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef ClearFunction] ''[doc.qt.nokia.com]''.
Para construir un plugin, necesitamos establecer lo siguiente en un archivo de proyecto de Qt. Primero, es necesario agregar los archivos de encabezado, de código fuente y los módulos de Qt en nuestro archivo de proyecto. Todos los archivos de proyecto y de código C++ están ene el directorio filedialog.


Para simplificar nuestro diálogo de archivo, la clase Directory filtra los archivos de texto no válidos, los cuales son archivos que no tienen una extensión .txt. Si un nombre de archivo no tiene la extensión .txt, entonces el archivo no aparecerá en nuestro diálogo de archivo. También, la implementación se asegura que los archivos guardados tengan una extensión .txt en el nombre del archivo. La clase Directory utiliza QTextStream para leer el archivo y para sacar el contenido del archivo a otro archivo.
<code> In cppPlugins.pro:


Con nuestro elemento Directory, podemos obtener los archivos como una lista, sabiendo cuantos archivos de texto hay en el directorio de la aplicación, obtener el nombre del archivo y su contenido como una cadena de caracteres, y ser notificados cuando ocurra algún cambio en el contenido del directorio.
TEMPLATE = lib<br /> CONFIG ''= qt plugin<br /> QT''= declarative


Para compilar el plugin, ejecutamos qmake sobre el archivo de proyecto cppPlugins.pro, luego ejecutamos make para compilar y transferir el complemento al directorio plugins.
DESTDIR ''= ../plugins<br /> OBJECTS_DIR = tmp<br /> MOC_DIR = tmp
<br /> TARGET = FileDialog
<br /> HEADERS''= directory.h  file.h  dialogPlugin.h


===Importando un Plugin en <span class="caps">QML</span>===
SOURCES += directory.cpp  file.cpp  dialogPlugin.cpp<br /></code>


La herramienta qmlviewer importa archivos que están en el mismo directorio de la aplicación. También podemos crear un archivo qmldir que contengan las ubicaciones de los archivos <span class="caps">QML</span> que queremos importar. El archivo qmldir puede almacenar también las ubicaciones de plugins y otros recursos.
En particular, compilamos Qt con el módulo declarativo y lo configuramos como un plugin, para esto necesitamos utilizar una plantilla de biblioteca (lib). Pondremos el plugin en el directorio de plugins del padre.
 
El plugin que recién creamos se llama FileDialog, como se indica en el campo <span class="caps">TARGET</span> en el archivo del proyecto. El plugin compilado está en el directorio plugins.
 
===Integrando un Diálogo Archivo en el Menú Archivo===
 
Nuestro FileMenu necesita mostrar el elemento FileDialog, el cual contiene una lista de archivos de texto en un directorio, esto permite al usuario seleccionar el archivo al hacer click en la lista. También necesitamos asignar los botones guardar, abrir y nuevo a sus respectivas acciones. FileMenu contiene un campo de texto de entrada editable que permite al usuario capturar el nombre de un archivo utilizando el teclado.


El elemento Directory se utiliza en el archivo FileMenu.qml y notifica al elemento FileDialog que el directorio actualizó su contenido. Esta notificación se realiza en el manejador de signal, onDirectoryChanged.
=== Registrando una Clase en QML ===


Manteniendo la simplicidad de nuestra aplicación, el diálogo de archivo siempre estará visible y no mostrará nombres de archivos no válidos, los cuales no tienen una extensión .txt en sus nombres.
<code> In dialogPlugin.h:


El elemento FileDialog mostrará el contenido de un directorio al leer su propiedad tipo lista llamados archivos. Los archivos se usan como el modelo de un elemento GridView, el cual muestra elementos de datos en una rejilla de acuerdo a un delegate. El delegate maneja la apariencia del modelo y nuestro diálogo de archivo simplemente creará una rejilla con el texto centrado en el medio. Hacer click en el nombre del archivo resultará en la aparición del rectángulo resaltando el nombre del archivo. El elemento FileDialog se notifica cuando se emite la signal notifyRefresh, recargando los archivos en el directorio.
#include &lt;QtDeclarative/QDeclarativeExtensionPlugin&amp;gt;


Nuestro FileMenu ahora puede conectarse con sus respectivas acciones. El elemento saveButton transferirá el texto de TextEdit a la propiedad fileContent del directorio, y luego copiará su nombre de archivo de la entrada de texto editable. Finalmente, el botón llama a la función saveFile(), guardando el archivo. La función sloadButton tiene una ejecución similar. También, la acción New vacía el contenido del elemento TextEdit.
class DialogPlugin : public QDeclarativeExtensionPlugin<br /> {<br /> Q_OBJECT


Además, los botones EditMenu se conectan a la funciones TextEdit para copiar, pegar y seleccionar todo el texto en el editor de texto.
public:<br /> void registerTypes(const char *uri);


[[Image:qml-texteditor5_filemenu.png]]
};</code>


===Finalización del Editor de Texto===
Nuestra clase plugin, DialogPlugin es una subclase de &quot;QDeclarativeExtensionPlugin&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html. Necesitamos implementar la función heredada, registerTypes(). El archivo dialogPlugin.cpp es similar a esto:


[[Image:qml-texteditor5_newfile.png]]
<code> DialogPlugin.cpp:


La aplicación puede funcionar como un simple editor de texto, capaz de aceptar texto y guardar el texto en un archivo. El editor de texto también puede cargar contenido desde un archivo y realizar manipulación de texto.
#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;


'''''Visita la segunda parte de este tutorial introductorio''''' [[GettingStartedQML Spanish p2|Introducción a la Programación con <span class="caps">QML</span> Parte 2]]
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);</code>
<br />La función &quot;registerTypes()&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registra nuestras clase File y Directory en QML. Esta función necesita el nombre de la clase para su plantilla, un número de versión mayor, un número de versión menor y un nombre para nuestras clases.
<br />Necesitamos exportar el complemento utilizando la macro &quot;Q_EXPORT_PLUGIN2&amp;quot;:http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2#q-export-plugin2 macro. Note que en nuestro archivo dialogPlugin.h, tenemos la macro &quot;Q_OBJECT&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT en la parte superior de nuestra clase. Y también, necesitamos ejecutar qmake sobre el archivo del proyecto para generar el código meta-objeto necesario.
<br />h3. Creando Propiedades QML en una clase C++
<br />Podemos crear elementos y propiedades QML usando el &quot;Sistema de Meta-Objetos de Qt&amp;quot;:http://doc.qt.nokia.com/4.7/metaobjects.html. Podemos implementar propiedades utilizando signals y slots, haciendo que Qt esté conciente de estas propiedades. Entonces estas propiedades podrán ser utilizadas en QML.
<br />Para el editor de texto, necesitamos ser capaces de cargar y guardar archivos. For the text editor, we need to be able to load and save files. Típicamente, estas funciones están contenidas en un diálogo de archivo. Afortunadamente, podemos utilizar &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, y &quot;QTextStream&amp;quot;:http://doc.qt.nokia.com/4.7/qtextstream.html para implementar la lectura de directorios y flujos de entrada/salida.
<br /><code> 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 /> …</code>
<br />La clase Directory utiliza el Sistema de Meta-Objetos de Qt para registrar propiedades que necesita para realizar el manejo de archivos. La clase Directory se exporta como un plugin y es utilizable en QML como el elemento Directory. Cada una de las propiedades listadas usando la macro &quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY es una propiedad QML.
<br />La macro &quot;Q_PROPERTY&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY declara una propiedad y sus funciones de lectura y escritura en el Sistema de Meta-Objetos de Qt. Por ejemplo, la propiedad filename, de tipo QString, puede ser leída utilizando la función filename() y puede ser escrita utilizando la función setFilename(). Adicionalmente, hay una señal asociada a la propiedad filename llamada filenameChanged(), la cual se emite cuando la propiedad cambia. Las funciones de lectura y escritura están declaradas como públicas en el archivo de encabezado.
<br />De manera similar, tenemos las otras propiedades declaradas de acuerdo a sus usos. La propiedad filesCount indica el número de archivos en un directorio. La propiedad filename property se establece con el nombre del archivo seleccionado actualmente y el contenido del archivo guardado/cargado se almacena en la propiedad fileContent.
<br /><code> Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )<code>
<br />La propiedad files en una lista de todos los archivos filtrados en un directorio. La clase Directory se implementa para filtrar archivos de texto no válidos; solo los archivos con extensión .txt son válidos. Además, las &quot;QLists&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html se pueden utilizar en archivos QML al declararlas como QDeclarativeListProperty en C+''. El objeto plantilla necesita heredar de QObject, por lo tanto, la clase File también debe heredar de QObject. En la clase Directory, la lista de objetos File se almacena en una QList llamada m_fileList.
<br /></code> class File : public QObject{
<br /> Q_OBJECT<br /> Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
<br /> …<br /> };<code>
<br />Las propiedades pueden entonces utilizarse en QML como parte de las propiedades del elemento Directory. Note que no necesitamos crear una propiedad identificador id en nuestro código C.
<br /></code> Directory{<br /> id: directory
<br /> filesCount<br /> filename<br /> fileContent<br /> files
<br /> files[0].name<br /> }<code>
<br />Como QML usa sintaxis y estructura de Javascript, podemos iterar a través de la lista de archivos y obtener sus propiedades. Para obtener la propiedad nombre del primer archivo, podemos llamar a files[0].name.
<br />Las funciones normales de C''+ también son accesibles desde QML. Las funciones cargar y guardar un archvio están implementadas en C++ y se declaran utilizando la macro &quot;Q_INVOKABLE&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE. De manera alternativa, podemos declarar las funciones como una ranura y las funciones serán accesibles desde QML.
<br /></code> In Directory.h:
<br /> &quot;Q_INVOKABLE&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE void saveFile&amp;amp;#40;&amp;#41;;<br /> Q_INVOKABLE void loadFile&amp;amp;#40;&amp;#41;;<br /><code>
<br />La clase Directory también tiene que notificar a otros objetos cuando el contenido del directorio cambie. Esta función se realiza utilizando una signal. Como se mencionó previamente, las signals de QML tienen un manejador correspondiente con sus nombres precedidos por &quot;on&amp;quot;. La signal tiene el nombre de directoryChanged y se emite cuando ocurre una actualización en un directorio. La actualización simplemente carga el contenido del directorio y actualiza la lista de archivos válidos en el directorio. Los elementos de QML pueden entonces ser notificados asignando una acción al manejador de signal onDirectoryChanged.
<br />Las propiedades tipo lista necesitan se exploradas un poco más. Esto es porque las propiedades tipo lista utilizan callbacks para acceder y modificar los contenidos de la lista. La propiedad lista es de tipo QDeclarativeListProperty&amp;lt;File&amp;gt;. Siempre que se accede a la lista, la función de acceso necesita devolver una QDeclarativeListProperty&amp;lt;File&amp;gt;. El tipo plantilla, File, necesita heredar de QObject. Además, para crear una &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html, los métodos de acceso y modificación de la lista necesitan enviarse al constructor como apuntadores a función. La lista, una QList en nuestro caso, también necesita ser una lista de apuntadores a File.
<br />El constructor de &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html y la implementación de Directory:
<br /></code> 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 );<code>


===Categories:===
El constructor envía apuntadores a funciones que agregan elementos al final de la lista, cuentan sus elementos, obtienen un elemento utilizando un índice y vacían la lista. Solo la función de agregar es obligatoria. Note que los apuntadores a función deben coincidir con la definición de &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, o &quot;ClearFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef.


* [[:Category:Learning|Learning]]
</code> 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>
* [[:Category:Spanish|Spanish]]
<br />Para simplificar nuestro diálogo de archivo, la clase Directory filtra los archivos de texto no válidos, los cuales son archivos que no tienen una extensión .txt. Si un nombre de archivo no tiene la extensión .txt, entonces el archivo no aparecerá en nuestro diálogo de archivo. También, la implementación se asegura que los archivos guardados tengan una extensión .txt en el nombre del archivo. La clase Directory utiliza QTextStream para leer el archivo y para sacar el contenido del archivo a otro archivo.
<br />Con nuestro elemento Directory, podemos obtener los archivos como una lista, sabiendo cuantos archivos de texto hay en el directorio de la aplicación, obtener el nombre del archivo y su contenido como una cadena de caracteres, y ser notificados cuando ocurra algún cambio en el contenido del directorio.
<br />Para compilar el plugin, ejecutamos qmake sobre el archivo de proyecto cppPlugins.pro, luego ejecutamos make para compilar y transferir el complemento al directorio plugins.
<br />h3. Importando un Plugin en QML
<br />La herramienta qmlviewer importa archivos que están en el mismo directorio de la aplicación. También podemos crear un archivo qmldir que contengan las ubicaciones de los archivos QML que queremos importar. El archivo qmldir puede almacenar también las ubicaciones de plugins y otros recursos.
<br /></code> In qmldir:
<br /> Button ./Button.qml<br /> FileDialog ./FileDialog.qml<br /> TextArea ./TextArea.qml<br /> TextEditor ./TextEditor.qml<br /> EditMenu ./EditMenu.qml
<br /> plugin FileDialog plugins<br /><code>
<br />El plugin que recién creamos se llama FileDialog, como se indica en el campo TARGET en el archivo del proyecto. El plugin compilado está en el directorio plugins.
<br />h3. Integrando un Diálogo Archivo en el Menú Archivo
<br />Nuestro FileMenu necesita mostrar el elemento FileDialog, el cual contiene una lista de archivos de texto en un directorio, esto permite al usuario seleccionar el archivo al hacer click en la lista. También necesitamos asignar los botones guardar, abrir y nuevo a sus respectivas acciones. FileMenu contiene un campo de texto de entrada editable que permite al usuario capturar el nombre de un archivo utilizando el teclado.
<br />El elemento Directory se utiliza en el archivo FileMenu.qml y notifica al elemento FileDialog que el directorio actualizó su contenido. Esta notificación se realiza en el manejador de signal, onDirectoryChanged.
<br /></code> In FileMenu.qml:
<br /> Directory{<br /> id:directory<br /> filename: textInput.text<br /> onDirectoryChanged: fileDialog.notifyRefresh()<br /> }<br /><code>
<br />Manteniendo la simplicidad de nuestra aplicación, el diálogo de archivo siempre estará visible y no mostrará nombres de archivos no válidos, los cuales no tienen una extensión .txt en sus nombres.
<br /></code> In FileDialog.qml:
<br /> signal notifyRefresh()<br /> onNotifyRefresh: dirView.model = directory.files<br /><code>
<br />El elemento FileDialog mostrará el contenido de un directorio al leer su propiedad tipo lista llamados archivos. Los archivos se usan como el modelo de un elemento GridView, el cual muestra elementos de datos en una rejilla de acuerdo a un delegate. El delegate maneja la apariencia del modelo y nuestro diálogo de archivo simplemente creará una rejilla con el texto centrado en el medio. Hacer click en el nombre del archivo resultará en la aparición del rectángulo resaltando el nombre del archivo. El elemento FileDialog se notifica cuando se emite la signal notifyRefresh, recargando los archivos en el directorio.
<br /></code> In FileMenu.qml:
<br /> 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 /> }<code>
<br />Nuestro FileMenu ahora puede conectarse con sus respectivas acciones. El elemento saveButton transferirá el texto de TextEdit a la propiedad fileContent del directorio, y luego copiará su nombre de archivo de la entrada de texto editable. Finalmente, el botón llama a la función saveFile&amp;amp;#40;&amp;#41;, guardando el archivo. La función sloadButton tiene una ejecución similar. También, la acción New vacía el contenido del elemento TextEdit.
<br />Además, los botones EditMenu se conectan a la funciones TextEdit para copiar, pegar y seleccionar todo el texto en el editor de texto.
<br />[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_filemenu.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor5_filemenu.png]]
<br />h3. Finalización del Editor de Texto
<br />[[Image:http://doc.qt.nokia.com/4.7/images/qml-texteditor5_newfile.png|http://doc.qt.nokia.com/4.7/images/qml-texteditor5_newfile.png]]
<br />La aplicación puede funcionar como un simple editor de texto, capaz de aceptar texto y guardar el texto en un archivo. El editor de texto también puede cargar contenido desde un archivo y realizar manipulación de texto.
<br />'''''Visita la segunda parte de este tutorial introductorio''* [[GettingStartedQML_Spanish_p2|Introducción a la Programación con QML Parte 2]]

Revision as of 14:29, 23 February 2015


Introducción a la Programación con QML

Bienvenido al mundo de QML, el lenguaje declarativo de Interfaces de Usuario (UI). En esta guía de introducción, crearemos una simple aplicación de editor de texto utilizando QML. Después de leer esta guía, usted debería estar listo para desarrollar sus propias aplicaciones utilizando QML y Qt C+.
h2. QML para crear interfaces de usuario
La aplicación que estamos construyendo es un editor de texto simple que va a cargar, guardar y realizar alguna manipulación de texto. Esta guía constará de dos partes. La primera parte consistirá en diseñar la interfaz de la aplicación y sus comportamientos (behaviors) utilizando lenguaje declarativo en QML. En la segunda parte, agregaremos funcionalidad para cargar y guardar un archivo mediante Qt C. Usaremos Meta-Object System de Qt para exponer funciones C+ como propiedades para que puedan ser usadas por elementos QML. Al utilizar QML y Qt C++ podemos desacoplar eficientemente la lógica de la interfaz de usuario, de la lógica de la aplicación.

http://doc.qt.nokia.com/4.7/images/qml-texteditor5_editmenu.png

Para ejecutar el código de ejemplo de QML, simplemente provea el archivo QML como argumento a la herramienta qmlviewer incluida. La porción de C++ de este tutorial asume que el lector posee conocimiento básico sobre el procedimiento de compilación de Qt.

Capítulos del tutorial:
# Definiendo un Botón y un Menú
# Implementando una Barra de Menús
# Construyendo un Editor de Texto
# Decorando el Editor de Texto
# Extendiendo QML utilizando Qt C++

Definiendo un Botón y un Menú

Componente Básico - un Botón

Comenzamos nuestro editor de textos construyendo un botón. Funcionalmente, un botón tiene un área sensitiva al mouse y una etiqueta. Los botones realizan acciones cuando un usuario los presiona.

En QML, el elemento visual básico es el elemento Rectangle (Rectángulo). El elemento Rectangle tiene propiedades para controlar su apariencia y ubicación.

Primero, la importación de Qt 4.7 permite que la herramienta qmlviewer importe los elementos QML que usaremos más tarde. Esta línea debe existir para cada archivo QML.
Note que la versión de los módulos de Qt se incluye en sentencia de importación

Este simple rectángulo tiene un identificador único, simplebutton (botón simple), el cual está ligado a la propiedad id. Las propiedades del elemento Rectangle se enlazan con valores listando la propiedad seguida de dos puntos ':', y después el valor. En el código de ejemplo, el color gris está ligado con la propiedad color del Rectángulo. De manera similar, enlazamos el ancho y el alto del Rectángulo

El elemento Text (Texto) es un campo de texto no editable. Nombramos a este elemento Text como buttonLabel. Para establecer el contenido del campo de texto, enlazamos un valor a su propiedad text. La etiqueta está contenida dentro del Rectángulo y con el fin de centrarla, asignamos las anchors (anclas) del elemento Text a su padre, el cual es llamado simplebutton. Las anchors se pueden enlazar con las anchors de otros elementos, permitiendo que las asignaciones de layouts sean más simples.

Vamos a guardar este código como SimpleButton.qml. Ejecutar el qmlviewer con este archivo como argumento mostrará el rectángulo gris con una etiqueta de texto.

http://doc.qt.nokia.com/4.7/images/qml-texteditor1_simplebutton.png

Para implementar la funcionalidad de click del botón, podemos utilizar el manejo de eventos de QML. El manejo de eventos de QML es muy similar a el mecanismo de Signals y Slots (Señales y Ranuras) de Qt. Las Signals se emiten y el Slot conectado es invocado.

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 />}

Incluimos un elemento MouseArea (Área de Mouse) en nuestro elemento simplebutton. El elemento MouseArea describe el área interactiva en dónde los movimientos del mouse son detectados. Para nuestro botón, anclamos el MouseArea completa a su padre, el cual es simplebutton. La sintaxis anchors.fill es una manera de acceder a una propiedad específica llamada fill dentro de un grupo de propiedades llamadas anchors. QML utiliza layouts basados en anchors en dónde los items se pueden anclar a otros items, creando layouts robustos.

El MouseArea tiene muchos manejadores (handlers) de signals que son llamados durante los movimientos del mouse realizados dentro de los límites especificados por el MouseArea. Uno de ellos es onClicked, el cual es llamado cuando el botón de aceptar del mouse se presiona, siendo el botón izquierdo el botón aceptar por defecto. Podemos enlazar acciones al manejador onClicked. En nuestro ejemplo, console.log() imprime texto en pantalla cada vez que se hace click sobre el área de mouse. La función console.log() es una herramienta útil para propósitos de depuración y para mostrar texto en pantalla.

El código en SimpleButton.qml es suficiente para mostrar un botón en la pantalla e imprimir texto en pantalla cada vez que se hace click con el mouse sobre el botón.

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 />}

Un botón completamente funcional se encuentra en Button.qml. En el fragmento de código de este artículo se omite cierto código, el cual se denota por puntos suspensivos, debido a que se presentó en secciones anteriores o a que es irrelevante para la discusión del código de la sección actual.

Las propiedades personalizadas se declaran utilizando la sintaxis tipo de propiedad, nombre. En el código, la propiedad buttonColor (Color de Botón), de tipo color, se declara y enlaza al valor "lightblue&quot; (azul claro). La propiedad buttonColor se utiliza más tarde en una operación condicional para determinar el color de relleno del botón. Note que la asignación de un valor a una propiedad es posible utilizando el signo igual '=', en adición al enlace de de valores utilizando el carácter dos puntos ':'. Las propiedades personalizadas permiten que los elementos internos sean accesibles desde fuera del ámbito del Rectángulo. Existen tipos básicos QML como int, string, real y también un tipo llamado variant.

Mediante el enlace de los manejadores de señal onEntered y onExited, el borde de los botones cambiará a amarillo cuando el mouse se coloque encima del botón y el cambio de color se revertirá cuando el mouse salga del área de mouse.

La signal buttonClick está declarada en Button.qml mediante la colocación de la palabra clave signal frente al nombre de la signal Los manejadores de las signals se crean automáticamente con su nombre comenzando con on. Como resultado, onButtonClick es el manejador de buttonClick. Entonces a onButtonClick se le asigna una acción para realizar. En nuestro ejemplo de botón, el manejador de onClicked simplemente invocará onButtonClick, el cual mostrará algún texto. onButtonClick permite que los objetos externos accedan al área de mouse del botón de manera sencilla. (?)Por ejemplo, los elementos podrían tener más una declaración de MouseArea y una signal buttonClick puede mejorar la distinción entre los distintos manejadores de signals del MouseArea(?).

Ahora tenemos el conocimiento básico para implementar elementos en QML que puedan manejar movimientos básicos del mouse. Creamos una etiqueta de Texto dentro de un Rectángulo, personalizamos sus propiedades, e implementamos comportamientos que responden a los movimientos del mouse. Está idea de crear elementos dentro de elementos se repite a través de toda la aplicación del editor de textos.

Este botón no es útil a menos que se utilice como componente para realizar una acción. En la siguiente sección, pronto crearemos un menú que contenga varios de estos botones.

http://doc.qt.nokia.com/4.7/images/qml-texteditor1_button.png

Creando una Página de Menú

Hasta este momento, hemos cubierto como crear elementos y asignar comportamientos dentro de un sólo archivo QML. En esta sección, cubriremos como importar elementos QML y como reutilizar algunos de los componentes creados para construir otros componentes.

Los Menús muestran el contenido de una lista, cada elemento posee la habilidad de realizar alguna acción. En QML, podemos crear un menú de varias maneras. Primero, crearemos un menú que contenga botones, los cuales eventualmente realizarán diferentes acciones. El código del menú está en FileMenu.qml

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 />

La sintaxis mostrada arriba muestra como utilizar la palabra clave import. Ésto se requiere para utilizar archivos JavaScript o QML que no están en el mismo directorio. Debido a que Button.qml está en el mismo directorio que FileMenu.qml, no necesitamos importar el archivo Button.qml para utilizarlo. Podemos directamente crear un elemento Button declarando Button{}, similar a la declaración de Rectangle{}.

En 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 />}

En FileMenu.qml, declaramos tres elementos Button. Están declarados dentro de un elemento Row (Fila), el cual posicionará a sus hijos a lo largo de una fila vertical. La declaración del Botón reside en Button.qml, el cual es el mismo Button.qml que utilizamos en la sección previa. Se pueden declarar nuevos enlaces de propiedades dentro de los nuevos botones creados, sobrescribiendo efectivamente las propiedades establecidas en Button.qml. El botón llamado exitButton (Botón Salir) cerrará la ventana y terminará la aplicación cuando se presione. Note que el manejador de signal onButtonClick en Button.qml será invocado en adición al manejador onButtonClick en exitButton.

http://doc.qt.nokia.com/4.7/images/qml-texteditor1_filemenu.png

La declaración de Row está declarada dentro de un Rectangle, creando un rectángulo contenedor para las filas de botones. Este rectángulo adicional crea una manera indirecta de organizar las filas de botones dentro de un menú

La declaración del menú edit (editar) es muy similar en esta etapa. El menú tiene botones con las etiquetas: Copy (Copiar), Paste (Pegar), y Select All (Seleccionar Todo).

http://doc.qt.nokia.com/4.7/images/qml-texteditor1_editmenu.png

Armados con nuestro conocimiento de importar y personalizar componentes previamente creados, ahora podemos combinar estas páginas de menú para crear una barra de menús, que consiste en botones para seleccionar el menú, y mire como podemos estructurar datos utilizando QML.

Implementando una Barra de Menús

Nuestra aplicación de editor de textos necesitará una manera de mostrar menús utilizando una barra de menús. La barra de menús realizará los cambios entre los diferentes menús y el usuario puede elegir cual menú desplegar.
El cambió de menú implica que los menús necesitan más estructura que simplemente mostrarlos en una fila. QML utiliza modelos y vistas para estructurar datos y mostrar los datos estructurados.

Utilizando Modelos de Datos y Vistas

QML tiene diferentes vistas de datos para mostrar modelos. Nuestra barra de menús mostrará los menús en una lista, con el encabezado mostrando una fila con los nombres de los menús. La lista de menús se declara dentro de un VisualItemModel. El elemento VisualItemModel contiene elementos que ya tienen vistas, como elementos Rectangle y elementos de Interfaz de Usuario importados. Otrostipos de modelo como el elemento ListModel necesitan un delegate para mostrar su información.

Declaramos dos elementos visuales en el menuListModel, el FileMenu y el EditMenu. Personalizamos los dos menús y los mostramos utilizando una ListView. El archivo MenuBar.qml contiene las declaraciones QML y en EditMenu.qml un simple menu edit está definido.

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 />}

El elemento ListView mostrará un modelo de acuerdo a un delegate. El delegate declarará los elemento del modelo de manera que se muestren en un elemento Row o en un grid. Nuestro menuListModel ya tiene elementos visibles, por lo tanto, no necesitamos declarar un delegate.

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 />}

Adicionalmente, ListView hereda de Flickable, haciendo que la lista responda al arrastre del mouse y otros gestos. La última porción del código de arriba establece las propiedades de Flickable para crear el movimiento de deslizamiento (flicking) que deseamos en nuestra vista. En particular, la propiedad highlightMoveDuration cambia la duración de la transición de deslizamiento. Un valor más alto de la propiedad highlightMoveDuration da como resultado un cambio de menú más lento.

La ListView mantiene los elementos del modelo a través de un índice y cada elemento visual en el modelo es accesible a través de un índice con el valor del orden en que se declararon los elementos. Cambiar la propiedad currentIndex (índice actual) cambia el elemento resaltado en la ListView. El encabezado de nuestra barra de menú ejemplifica este efecto. Hay dos botones en una fila, ambos cambian el menú actual cuándo se presionan. El fileButton cambia el menú actual al menú file cuando se presiona, el índice será 0 debido a que FileMenu se declara primero en el menuListModel. De manera similar, el editButton cambiará el menú actual a EditMenu cuando se presiona.

El rectángulo labelList tiene valor z de 1, denotando que será mostrado frente a la barra de menús. Los elementos con un valor de z más alto se muestran por sobre elementos con valores menores de z. El valor por defecto para z es 0.

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 />}

Podemos acceder a los menús de la barra de herramientas que acabamos de crear deslizando hacia los menús o presionando los nombres de los menús de la parte superior. El cambio entre las pantallas del menú se siente intuitivo y responsivo.

http://doc.qt.nokia.com/4.7/images/qml-texteditor2_menubar.png

Construyendo un Editor de Texto

Declarando un Área de Texto (TextArea)

Nuestro editor de texto no es un editor de texto si no contiene un área para editar texto. El elemento TextEdit de QML permite la declaración de un área multilínea de texto editable. TextEdit es diferente de un elemento Text, el cual no permite al usuario editar el texto directamente.

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 />}

El editor tiene establecidas las propiedades de color y ajuste de texto. El área de edición de texto está dentro de un área deslizable que desplazará el texto si el cursor está fuera del área visible. La función ensureVisible() verificará si el rectángulo del cursor está fuera de los límites de visibilidad y moverá el área de texto de acuerdo a esto. QML utiliza sintáxist de Javascript para sus scripts, y como se menciono previamente, los archivos Javascript se pueden importar y utilizar en un archivo QML.

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 />}

Combinando Componentes para el Editor de Texto

Ahora estamos listos para crear el diseño de nuestro editor de texto utilizando QML. El editor de texto tiene dos componentes, la barra de menús que creamos y el área de texto. QML nos permite reutilizar componentes, haciendo nuestro código más simple, importanto componentes y personalizándolos cuándo sea necesario. Nuestro editor de texto divide la ventana en dos; un tercio de la pantalla está dedicado a la barra de menús y dos tercios de la pantalla muestran el área de texto. La barra de menús se muestra en frente de cualquier otro elementos.

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 />}

Mediante la importación de componentes reutilizables, el código de nuestro Editor de Texto se ve mucho más simple. Ahora podemos personalizar la aplicación principal sin preocuparnos acerca de propiedades que ya tiene comportamientos definidos. Utilizando este enfoque, se puede crear fácilmente tanto el diseño de la aplicación como componentes de UI.

http://doc.qt.nokia.com/4.7/images/qml-texteditor3_texteditor.png

Decorando el Editor de texto

Implementando una Interfaz Drawer

Nuestro Editor de Texto parece simple y por lo tanto es necesario que lo decoremos. Utilizando QML, podemos declarar las transiciones y la animación de nuestro Editor de Texto. Nuestra barra de menú está ocupando un tercio de la pantalla y seria bueno que solo apareciera cuando lo deseemos.

Podemos añadir una Interfaz Drawer, que minimice o expanda la barra de menú cuando se hace click. En nuestra implementación, tenemos un rectángulo delgado que responde a los click del mouse. El drawer, así como la aplicación, tienen dos estados: el estado "drawer is open&quot; y el estado "drawer is closed&quot;. El elemento drawer es una franja del rectángulo con una pequeña altura. Hay un elemento anidado Imagen que declara que un icono arrow será centrado dentro del drawer. El drawer asigna un estado a toda la aplicación, con el identificador de pantalla(screen), cada vez que un usuario haga clic en el área del mouse.

 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 /> }

Un estado es simplemente una colección de configuraciones las cuales son declaradas en un elemento State. Una lista de los estados pueden ser listadas y ligadas a la propiedad states. En nuestras aplicación, los dos estados son lamados DRAWER_OPEN Y DRAWER_CLOSED. Las configuraciones de los elementos son declaradas en la PorpertyChanges. En el estados DRAWER_OPEN, hay cuatro elementos que recibirán los cambios de propiedad (PropertyChanges). El primer objeto, menuBar cambiará su y propiedad a 0. Del mismo modo, el objeto textArea descenderá auna nueva posición cuando el estado DRAWER_OPEN este activado. La textArea, el drawer, y el icono de drawer se someterán a los cambios de propiedad para cumplir con el estado actual.

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 />

Los cambios de estado son bruscos por ello es recomendable aplicar transiciones para suavizarlos. Las transiciones entre los estados se definen mediante el elemento Transition, que puede enlazarse a los elementos dentro de la propiedad transitions. Nuestro editor de texto tiene una transición de estado cuando el estado cambia a DRAWER_OPEN o DRAWER_CLOSED. Es importante destacar que es necesario un estado de transición from y un to, pero para nuestra transición, podemos utilizar el símbolo * para indicar que la transición se aplica a todos los cambios de estado.

Durante las transiciones, podemos asignar animaciones a los cambios de propiedad. Nuestra menuBar cambia de la posición de y:0 a y:-partition y se puede animar esta transición mediante el elemento NumberAnimation. Declaramos que las propiedades de los objetos van a animarse por un período de tiempo determinado y con una curva de aceleración determinada. Una curva de aceleración controla el comportamiento de las tasas de animación y la interpolación en las transiciones de estado. La curva de aceleración que elegimos es Easing.OutQuint, que retarda el movimiento hacia el final de la animación. Lea atentamente el artículo "QML's Animation&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeanimation.html.

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 />

Otra manera de animar a los cambios de propiedad es declarando un elemento de comportamiento ("Behavior&quot;:http://doc.qt.nokia.com/4.7/qml-behavior.html). Una transición sólo funciona durante los cambios de estado y el comportamiento puede establecer una animación para un cambio de propiedad en general. En el editor de texto, la flecha tiene un comportamiento NumberAnimation que anima su propiedad rotation cada vez que cambia la propiedad.

In TextEditor.qml:

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

Volviendo a nuestros componentes con el conocimiento de los estados y las animaciones, podemos mejorar la apariencia de los componentes. En Button.qml, podemos añadir los cambios a la propiedad color y scale cuando se pulsa el botón. Los tipos color son animados usando ColorAnimation y los números son animados con NumberAnimation. La sintaxis de propertyName on que aparecen a continuación es de gran ayuda al elegir una sola propiedad.

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 />

Además, podemos mejorar la apariencia de nuestros componentes QML mediante la adición de efectos de color tales como gradientes y efectos de opacidad. La declaración de un elemento Gradient anulará la propiedad color del elemento. Usted puede declarar un color en el gradient mediante el elemento GradientStop. El gradiente se coloca utilizando una escala, entre 0.0 y 1.0.

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 />

Este gradiente es utilizado por la barra de menús para mostrar una simulación del gradiente de profundidad. El primer color empieza en 0.0 y el último color es de 1.0.

A dónde ir desde aquí

Hemos terminado la construcción de la interfaz de usuario de un editor de texto muy simple. En el futuro, se completara la interfaz de usuario, y podemos aplicar la lógica de la aplicación haciendo uso regular de Qt y C+. QML funciona muy bien como una herramienta de creación de prototipos, que separa la lógica de la aplicación de distancia de el diseño de interfaz de usuario.
http://doc.qt.nokia.com/4.7/images/qml-texteditor4_texteditor.png
h3. Extendiendo QML utilizando C+

Ahora que tenemos el diseño de nuestro editor de textos, podemos implementar su funcionalidad utilizando C+. Utilizar QML con C+ nos permite crear la lógica de nuestra aplicación utilizando Qt. Podemos crear un contexto QML en una aplicación C++ utilizando las clases de Qt Declarative y mostrar los elementos utilizando un Graphics Scene. De manera alternativa, podemos exportar nuestro código C++ en un plugin que la herramienta qmlviewer puede leer. Para nuestra aplicación, implementaremos las funciones abrir y guardar en C++ y las exportaremos como un plugin. De esta manera, podremos cargar el archivo QML de manera directa en lugar de utilizar un ejecutable.

Exponiendo clases C++ a QML

Implementaremos la apertura y guardado de archivos utilizando Qt y C+. Al registrar las clases y funciones de C+ podemos utilizarlas en QML. La clase necesita ser compilada como un plugin de Qt y el archivo QML necesita saber en dónde se localiza el plugin.

Para nuestra aplicación, necesitamos crear los siguientes elementos:

  1. Una clase Directory que se encargará de las operaciones relacionadas con los directorios
  2. Una clase File el cual es un QObject, que simula la lista de archivos en un directorio
  3. Una clase plugin que registrará la clase en el contexto QML
  4. Un archivo de proyecto de Qt para compilar el plugin
  5. Un archivo qmldir que le indique a la herramienta qmlviewer dónde encontrar el plugin

Construyendo un plugin de Qt

Para construir un plugin, necesitamos establecer lo siguiente en un archivo de proyecto de Qt. Primero, es necesario agregar los archivos de encabezado, de código fuente y los módulos de Qt en nuestro archivo de proyecto. Todos los archivos de proyecto y de código C++ están ene el directorio filedialog.

 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 />

En particular, compilamos Qt con el módulo declarativo y lo configuramos como un plugin, para esto necesitamos utilizar una plantilla de biblioteca (lib). Pondremos el plugin en el directorio de plugins del padre.

Registrando una Clase en QML

 In dialogPlugin.h:

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

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

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

};

Nuestra clase plugin, DialogPlugin es una subclase de "QDeclarativeExtensionPlugin&quot;:http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html. Necesitamos implementar la función heredada, registerTypes(). El archivo dialogPlugin.cpp es similar a esto:

 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);


La función "registerTypes()":http://doc.qt.nokia.com/4.7/qdeclarativeextensionplugin.html#registerTypes registra nuestras clase File y Directory en QML. Esta función necesita el nombre de la clase para su plantilla, un número de versión mayor, un número de versión menor y un nombre para nuestras clases.
Necesitamos exportar el complemento utilizando la macro "Q_EXPORT_PLUGIN2&quot;:http://doc.qt.nokia.com/4.7/qtplugin.html#Q_EXPORT_PLUGIN2#q-export-plugin2 macro. Note que en nuestro archivo dialogPlugin.h, tenemos la macro "Q_OBJECT&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_OBJECT en la parte superior de nuestra clase. Y también, necesitamos ejecutar qmake sobre el archivo del proyecto para generar el código meta-objeto necesario.
h3. Creando Propiedades QML en una clase C++
Podemos crear elementos y propiedades QML usando el "Sistema de Meta-Objetos de Qt&quot;:http://doc.qt.nokia.com/4.7/metaobjects.html. Podemos implementar propiedades utilizando signals y slots, haciendo que Qt esté conciente de estas propiedades. Entonces estas propiedades podrán ser utilizadas en QML.
Para el editor de texto, necesitamos ser capaces de cargar y guardar archivos. For the text editor, we need to be able to load and save files. Típicamente, estas funciones están contenidas en un diálogo de archivo. Afortunadamente, podemos utilizar "QDir&quot;:http://doc.qt.nokia.com/4.7/qdir.html, "QFile&quot;:http://doc.qt.nokia.com/4.7/qfile.html, y "QTextStream&quot;:http://doc.qt.nokia.com/4.7/qtextstream.html para implementar la lectura de directorios y flujos de entrada/salida.


 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 /> 


La clase Directory utiliza el Sistema de Meta-Objetos de Qt para registrar propiedades que necesita para realizar el manejo de archivos. La clase Directory se exporta como un plugin y es utilizable en QML como el elemento Directory. Cada una de las propiedades listadas usando la macro "Q_PROPERTY&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY es una propiedad QML.
La macro "Q_PROPERTY&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_PROPERTY declara una propiedad y sus funciones de lectura y escritura en el Sistema de Meta-Objetos de Qt. Por ejemplo, la propiedad filename, de tipo QString, puede ser leída utilizando la función filename() y puede ser escrita utilizando la función setFilename(). Adicionalmente, hay una señal asociada a la propiedad filename llamada filenameChanged(), la cual se emite cuando la propiedad cambia. Las funciones de lectura y escritura están declaradas como públicas en el archivo de encabezado.
De manera similar, tenemos las otras propiedades declaradas de acuerdo a sus usos. La propiedad filesCount indica el número de archivos en un directorio. La propiedad filename property se establece con el nombre del archivo seleccionado actualmente y el contenido del archivo guardado/cargado se almacena en la propiedad fileContent.


 Q_PROPERTY(QDeclarativeListProperty&amp;lt;File&amp;gt; files READ files CONSTANT )<code>
<br />La propiedad files en una lista de todos los archivos filtrados en un directorio. La clase Directory se implementa para filtrar archivos de texto no válidos; solo los archivos con extensión .txt son válidos. Además, las &quot;QLists&amp;quot;:http://doc.qt.nokia.com/4.7/qlist.html se pueden utilizar en archivos QML al declararlas como QDeclarativeListProperty en C+''. El objeto plantilla necesita heredar de QObject, por lo tanto, la clase File también debe heredar de QObject. En la clase Directory, la lista de objetos File se almacena en una QList llamada m_fileList.
<br />

class File : public QObject{


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



};

<br />Las propiedades pueden entonces utilizarse en QML como parte de las propiedades del elemento Directory. Note que no necesitamos crear una propiedad identificador id en nuestro código C.
<br />

Directory{
id: directory


filesCount
filename
fileContent
files


files[0].name
}

<br />Como QML usa sintaxis y estructura de Javascript, podemos iterar a través de la lista de archivos y obtener sus propiedades. Para obtener la propiedad nombre del primer archivo, podemos llamar a files[0].name.
<br />Las funciones normales de C''+ también son accesibles desde QML. Las funciones cargar y guardar un archvio están implementadas en C++ y se declaran utilizando la macro &quot;Q_INVOKABLE&amp;quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE. De manera alternativa, podemos declarar las funciones como una ranura y las funciones serán accesibles desde QML.
<br />

In Directory.h:
"Q_INVOKABLE&quot;:http://doc.qt.nokia.com/4.7/qobject.html#Q_INVOKABLE void saveFile&amp;#40;&#41;;
Q_INVOKABLE void loadFile&amp;#40;&#41;;

<br />La clase Directory también tiene que notificar a otros objetos cuando el contenido del directorio cambie. Esta función se realiza utilizando una signal. Como se mencionó previamente, las signals de QML tienen un manejador correspondiente con sus nombres precedidos por &quot;on&amp;quot;. La signal tiene el nombre de directoryChanged y se emite cuando ocurre una actualización en un directorio. La actualización simplemente carga el contenido del directorio y actualiza la lista de archivos válidos en el directorio. Los elementos de QML pueden entonces ser notificados asignando una acción al manejador de signal onDirectoryChanged.
<br />Las propiedades tipo lista necesitan se exploradas un poco más. Esto es porque las propiedades tipo lista utilizan callbacks para acceder y modificar los contenidos de la lista. La propiedad lista es de tipo QDeclarativeListProperty&amp;lt;File&amp;gt;. Siempre que se accede a la lista, la función de acceso necesita devolver una QDeclarativeListProperty&amp;lt;File&amp;gt;. El tipo plantilla, File, necesita heredar de QObject. Además, para crear una &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html, los métodos de acceso y modificación de la lista necesitan enviarse al constructor como apuntadores a función. La lista, una QList en nuestro caso, también necesita ser una lista de apuntadores a File.
<br />El constructor de &quot;QDeclarativeListProperty&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html y la implementación de Directory:
<br />

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

El constructor envía apuntadores a funciones que agregan elementos al final de la lista, cuentan sus elementos, obtienen un elemento utilizando un índice y vacían la lista. Solo la función de agregar es obligatoria. Note que los apuntadores a función deben coincidir con la definición de &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, o &quot;ClearFunction&amp;quot;:http://doc.qt.nokia.com/4.7/qdeclarativelistproperty.html#ClearFunction-typedef.

void appendFiles(QDeclarativeListProperty&lt;File&gt; * property, File * file)
File* fileAt(QDeclarativeListProperty&lt;File&gt; * property, int index)
int filesSize(QDeclarativeListProperty&lt;File&gt; * property)
void clearFilesPtr(QDeclarativeListProperty&lt;File&gt;
property)

<br />Para simplificar nuestro diálogo de archivo, la clase Directory filtra los archivos de texto no válidos, los cuales son archivos que no tienen una extensión .txt. Si un nombre de archivo no tiene la extensión .txt, entonces el archivo no aparecerá en nuestro diálogo de archivo. También, la implementación se asegura que los archivos guardados tengan una extensión .txt en el nombre del archivo. La clase Directory utiliza QTextStream para leer el archivo y para sacar el contenido del archivo a otro archivo.
<br />Con nuestro elemento Directory, podemos obtener los archivos como una lista, sabiendo cuantos archivos de texto hay en el directorio de la aplicación, obtener el nombre del archivo y su contenido como una cadena de caracteres, y ser notificados cuando ocurra algún cambio en el contenido del directorio.
<br />Para compilar el plugin, ejecutamos qmake sobre el archivo de proyecto cppPlugins.pro, luego ejecutamos make para compilar y transferir el complemento al directorio plugins.
<br />h3. Importando un Plugin en QML
<br />La herramienta qmlviewer importa archivos que están en el mismo directorio de la aplicación. También podemos crear un archivo qmldir que contengan las ubicaciones de los archivos QML que queremos importar. El archivo qmldir puede almacenar también las ubicaciones de plugins y otros recursos.
<br />

In qmldir:


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


plugin FileDialog plugins

<br />El plugin que recién creamos se llama FileDialog, como se indica en el campo TARGET en el archivo del proyecto. El plugin compilado está en el directorio plugins.
<br />h3. Integrando un Diálogo Archivo en el Menú Archivo
<br />Nuestro FileMenu necesita mostrar el elemento FileDialog, el cual contiene una lista de archivos de texto en un directorio, esto permite al usuario seleccionar el archivo al hacer click en la lista. También necesitamos asignar los botones guardar, abrir y nuevo a sus respectivas acciones. FileMenu contiene un campo de texto de entrada editable que permite al usuario capturar el nombre de un archivo utilizando el teclado. 
<br />El elemento Directory se utiliza en el archivo FileMenu.qml y notifica al elemento FileDialog que el directorio actualizó su contenido. Esta notificación se realiza en el manejador de signal, onDirectoryChanged.
<br />

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

<br />Manteniendo la simplicidad de nuestra aplicación, el diálogo de archivo siempre estará visible y no mostrará nombres de archivos no válidos, los cuales no tienen una extensión .txt en sus nombres.
<br />

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

<br />El elemento FileDialog mostrará el contenido de un directorio al leer su propiedad tipo lista llamados archivos. Los archivos se usan como el modelo de un elemento GridView, el cual muestra elementos de datos en una rejilla de acuerdo a un delegate. El delegate maneja la apariencia del modelo y nuestro diálogo de archivo simplemente creará una rejilla con el texto centrado en el medio. Hacer click en el nombre del archivo resultará en la aparición del rectángulo resaltando el nombre del archivo. El elemento FileDialog se notifica cuando se emite la signal notifyRefresh, recargando los archivos en el directorio.
<br />

In FileMenu.qml:


Button{
id: newButton
label: "New&quot;
onButtonClick:{
textArea.textContent = ""
}
}
Button{
id: loadButton
label: "Load&quot;
onButtonClick:{
directory.filename = textInput.text
directory.loadFile&amp;#40;&#41;
textArea.textContent = directory.fileContent
}
}
Button{
id: saveButton
label: "Save&quot;
onButtonClick:{
directory.fileContent = textArea.textContent
directory.filename = textInput.text
directory.saveFile&amp;#40;&#41;
}
}
Button{
id: exitButton
label: "Exit&quot;
onButtonClick:{
Qt.quit()
}
}
Nuestro FileMenu ahora puede conectarse con sus respectivas acciones. El elemento saveButton transferirá el texto de TextEdit a la propiedad fileContent del directorio, y luego copiará su nombre de archivo de la entrada de texto editable. Finalmente, el botón llama a la función saveFile&amp;#40;&#41;, guardando el archivo. La función sloadButton tiene una ejecución similar. También, la acción New vacía el contenido del elemento TextEdit.
Además, los botones EditMenu se conectan a la funciones TextEdit para copiar, pegar y seleccionar todo el texto en el editor de texto.
http://doc.qt.nokia.com/4.7/images/qml-texteditor5_filemenu.png
h3. Finalización del Editor de Texto
http://doc.qt.nokia.com/4.7/images/qml-texteditor5_newfile.png
La aplicación puede funcionar como un simple editor de texto, capaz de aceptar texto y guardar el texto en un archivo. El editor de texto también puede cargar contenido desde un archivo y realizar manipulación de texto.
Visita la segunda parte de este tutorial introductorio* Introducción a la Programación con QML Parte 2