treeview for kids

18
Tutorial Gtk.TreeView L1 Introducción Título: “TreeView para niños” El control TreeView es el más usado del conjunto de herramientas Gtk+; es la única forma de mostrar un serie de datos en tu aplicación de una forma lógica. Casi todas las aplicaciones que se ejecutan en Gnome/Gtk usan al menos un objeto TreeView para mostrar la información. Empecemos Antes que nada, crea tu propia aplicación e inserta un control TreeView. Si estas utilizando MonoDevelop y escogiste crear un proyecto Glade#, ya tienes una referencia al recurso de Glade en tu ventana de Solución: simplemente haz doble click en el recurso “gui.glade” para abrir Glade y coloca un control treeview desde la paleta de Glade:

Upload: jonathanvanks4643

Post on 10-Apr-2015

503 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: TreeView for Kids

Tutorial Gtk.TreeView L1Introducción

Título: “TreeView para niños”

El control TreeView es el más usado del conjunto de herramientas Gtk+; es la única forma de mostrar un serie de datos en tu aplicación de una forma lógica. Casi todas las aplicaciones que se ejecutan en Gnome/Gtk usan al menos un objeto TreeView para mostrar la información.

Empecemos

Antes que nada, crea tu propia aplicación e inserta un control TreeView. Si estas utilizando MonoDevelop y escogiste crear un proyecto Glade#, ya tienes una referencia al recurso de Glade en tu ventana de Solución:

simplemente haz doble click en el recurso “gui.glade” para abrir Glade y coloca un control treeview desde la paleta de Glade:

Page 2: TreeView for Kids

al final debes tener una ventana principal con un treeview dentro:

En MonoDevelop hay una plantilla de código que automáticamente enlaza el recurso de Glade con la aplicación en tiempo de ejecución así puedes usar tu GUI; en el  Constructor de tu clase principal debería haber:

...Application.Init ();Glade.XML gxml = new Glade.XML (null, "gui.glade", "window1", null);gxml.Autoconnect (this);Application.Run ();...

donde “window1” es el nombre del control principal que asignaste en Glade.

Para referenciar el control que proviene del recurso “gui.glade”, debes declararlos de la siguiente forma (¡¡no es necesario el operador new!!):

...[Widget] Gtk.Window window1;[Widget] Gtk.TreeView treeview1;...

Si construyes y ejecutas la solución verás una ventana con un área vacía dentro; esto es el TreeView sin ningún dato que mostrar.

Si no quieres utilizar Glade# en tu proyecto, simplemente crea un archivo “tutorial.cs” con las siguientes líneas.

...Gtk.Window window1 = new Gtk.Window ("Laas Tutorial");Gtk.TreeView treeview1 = new Gtk.TreeView ();window1.Add (treeview1);...

Esto es todo.

Page 3: TreeView for Kids

Por último, me gusta crear mi GUI usando Glade porque:– Todos los controles están disponibles en la paleta de Glade.– Es posible previsualizar el diseño de la aplicación.– Las principales propiedades de cada control están visibles.– Es fácil asignar manejadores de eventos a cada control.– Otras.

Si no usas MonoDevelop, recuerda enlazar la librería Gtk a la hora de compilar.

Page 4: TreeView for Kids

Tutorial Gtk.TreeView L2Propiedades principales

Propiedades principales del TreeView

Esta sección no cubre todas las propiedades disponibles del control TreeView, tan solo las que he usado en mis aplicaciones. Esto no es una “referencia en profundidad”, tan solo unas “notas de desarrollador”.

HeadersVisible (boolean – true/false)Con esta propiedad es posible controlar la visibilidad de la cabecera de la columna. En muchos casos la cabecera de la columna es útil para identificar los datos almacenados en el control (p.e. una libreta de direcciones con una columna para cada tipo de información como puede ser Nombre de cuenta, teléfono, móvil, fax, etc...); en otros casos la cabecera de la columna no es necesaria (p.e. un treeview de los archivos del sistema).

RulesHint (boolean – true/false)Si esta propiedad la pones a true, tu treeview irá alternando el sombreado en cada fila.

Model (ListStore / TreeStore)Utiliza esta propiedad para indicar el Model del treeview; es posible poner esta propiedad con dos tipos de objetos, ambos implementando la interfaz TreeModel (con el modelo puedes decidir como se muestra y se trata la información en el TreeView):ListStore: Almacena la información en una jerarquía de un nivel. La imagen anterior es una muestra del modo “plano” de este tipo de Model.TreeStore: Almacena los datos en un árbol:

Más adelante trataré el modelo del TreeView más detalladamente.

Page 5: TreeView for Kids

Selection (readonly – devuelve un TreeSelection)Esta es un propiedad muy importante. Es usada para recibir las filas del treeview. Veremos la propiedad en detalle más adelante.

Page 6: TreeView for Kids

Tutorial Gtk.TreeView L3El ListStore

ListStore

El objeto ListStore, asignado a un TreeView mediante la propiedad Model es responsable de como se mostrará la información en el control. Como ya dije en la página anterior, el modelo ListStore produce una visualización plana de los datos.

Cuando creas una instancia de la clase ListStore, puedes especificar el tipo de datos que que se almacenarán en las columnas del treeview enlazado. Así si quieres mostrar, en un treeview de 2 columnas, una lista de datos “Username/Password”, debes crear un ListStore con la siguiente sintaxis y entonces enlazarlo con la vista (el mismo treeview).

...TreeView userList = new TreeView(); ListStore treeViewEngine = 

new ListStore(typeof (string),typeof (string));userList.Model = treeViewEngine; ...

Para indicar como se mostrarán los datos en una columna, hay que seguir varios pasos:1. Crear un objeto TreeViewColumn para cada columna.2. Crear un objeto CellRenderer para cada columna.3. Añadir el atributo para el tipo de visualización al TreeViewColumn.4. Añadir la columna al TreeView.

Veamos le punto 4 en profundidad:

1. El objeto TreeViewColumn representa... ...la columna del TreeView. Puedes usar simplemente el constructor por defecto sin parámetros para crear una instancia de la clase. El objeto se añadirá al TreeView.

2. El objeto CellRenderer determinará el tipo de objeto que se mostrará en una sola celda (Cell). Las clases más útiles que derivan directamente de esta son: CellRendererText (para mostrar solo texto), CellRendererPixBuf (para mostrar imágenes en la celda) y CellRendererToggle (para mostrar una caja de validación (checkbox) en la celda).

3. De acuerdo con el tipo de CellRenderer que hayas escogido en el paso anterior, ahora hay que añadir el atributo para el tipo de visualización a la columna. Primero de todo añade el CellRenderer al TreeViewColumn con el método PackStart; este método toma dos parámetros, el primero es el objeto CellRenderer y el último es un valor boleano que determina como la celda aceptará un valor que sea más largo que su ancho (true = expandir / false = mantener tamaño).

Para añadir el atributo del tipo de visualización a la columna debemos usar el método AddAttribute. Este método toma 3 parámetros; el segundo es el tipo de visualización; los tipos más comunes son “text”, “pixbuf” y “markup”. El último tipo es útil cuando quieres 

Page 7: TreeView for Kids

crear una celda que muestre texto con estilo (de acuerdo con las definiciones de Cairo).

4. Finalmente, agrega la columna al TreeView.

Veamos el código completo de esta fase de “puesta a punto”:

...TreeViewColumn col = new TreeViewColumn();CellRendererText cellrt = new CellRendererText();col.Title = "Username"; // titulo de la cabecera de la columna, si está visiblecol.PackStart(cellrt, true);col.AddAttribute (cellrt, "text", 0); // la siguiente columna será 1 en vez de 0userList.AppendColumn(col); ...

Cuidado: Si inviertes las líneas 4 y 5 (las líneas de PackStart y AddAtribute), a la hora de ejecutar recibirás una serie de Warnings desde el entorno.

En este momento puedes indicar que las columnas ordenen el contenido del TreeView:

...treeViewEngine.SetSortColumnId(0,Gtk.SortType.Ascending);...

Añadiendo elementos

El objeto ListStore se usa para añadir datos al TreeView. De acuerdo con el tipo de columna y su CellRenderer, es posible usar el método AppendValues como en el siguiente ejemplo:

...string []userName = {"Admin","Root","Guest","Nobody"};string []passWord= {"test","blank","Guest","password"};

for(int k=0;k<userName.Length;k++) {treeViewEngine.AppendValues( userName[k] , passWord[k] );

}...

Seleccionando elementos

La mejor forma de manejar la selección en un TreeView es añadiendo una función Event Handler (usando delegados) al evento Changed de la propiedad Selection del TreeView.Este evento se lanza cuando el usuario hace click en una fila del TreeView; para manejar el evento de Doble Click tienes que escribir código para el evento RowActivated.Echa un vistazo al siguiente trozo de código:

Page 8: TreeView for Kids

.../*userList es el TreeViewonItemSelected es la función delegada*/userList.Selection.Changed += onItemSelected;......// después en el código...private void onItemSelected(object o, EventArgs args){

TreeModel model;string actualSelectedItem;if(((TreeSelection)o).GetSelected (out model, out iterSelected)) {

actualSelectedItem = (string) model.GetValue (iterSelected, 0);} 

} ......

¡nuevo! Para cada fila...

¿Cómo ir desde el primer elemento del TreeView hasta el último? Tan solo necesitas un TreeIter para “iterar” en todos los objetos almacenados por el ListStore (o TreeStore), como en el siguiente ejemplo:

...TreeIter tmpIter = new TreeIter();treeViewEngine.GetIterFirst(out tmpIter);string item = (string) treeViewEngine.GetValue(tmpIter,0); // este es el primer elemento

while(treeViewEngine.IterNext(ref tmpIter)) {  item = (string) treeViewEngine.GetValue(tmpIter,0); // los demás elementos}...

Añadiendo un objeto al TreeView

En los ejemplos anteriores, la forma de añadir elementos al treeview era “columna a columna”. Con Gtk es posible añadir un objeto completo a un ListStore usando funciones delegadas.Considera el TreeView del tutorial, y considera tener una clase “User” que contenga dos miembros: “Username” y “Password”. La clase debería parecerse a esta:

Page 9: TreeView for Kids

...public class User {

public string username;public string password;

...}...

Ok, ok!!! La información que no es necesaria ahora está oculta!!

Si quieres añadir un objeto del tipo User al treeview, simplemente sigue las instrucciones:

...col = new TreeViewColumn ();cellrt = new CellRendererText();col.AddAttribute (cellrt, "text", 1); col.PackStart(cellrt, true); col.SetCellDataFunc(colr, new TreeCellDataFunc(objUname)); // *userList.AppendColumn (col); ...

La línea con * es el enlace entre el objeto User y el TreeView. Finalmente tienes que definir la función objUname:

...private void objUname (

Gtk.TreeViewColumn tree_column, Gtk.CellRenderer cell, Gtk.TreeModel tree_model, Gtk.TreeIter iter

){

User X = (User) treeViewEngine.GetValue(iter,0);((CellRendererText) cell).Markup = X.username;

} ...

De esta forma, cada vez que añadas un objeto de la clase User  al TreeView, la función objUname se usará para obtener el contenido de la celda. Si estás visualizando una imagen, la función debe devolver un Pixbuf; naturalmente tienes que escribir la función delegada para cada columna del TreeView.

Otros métodos útiles

La clase ListStore tiene muchos métodos útiles para manejar datos. Aquí encontrarás una breve descripción de los miembros que utilizo más en mi aplicación.

Clear: Se usa para eliminar todos los elementos del ListStore. Usando este método, el TreeView 

Page 10: TreeView for Kids

relacionado se vaciará.

GetIterFirst: Asigna el primer elemento de la lista (el primero de arriba) al objeto TreeIter.

IterNext: Usado con el anterior te permite desplazarte hacia abajo en la lista analizando cada fila.

ForEach: Con este método es posible llamar una función (delegada) en cada fila.

GetValue: Este métdo toma por entrada un TreeIter definiendo la fila actual y el índice de la columna en el cuál la aplicación encontrará el valor.

Page 11: TreeView for Kids

Tutorial Gtk.TreeView L4El TreeStore

TreeStore

El TreeStore se usa como una alternativa al ListStore (visto en la lección anterior). El TreeStore es asignado a la propiedad Model del TreeView y muestra los datos en forma de “árbol”.Esto es útil para mostrar datos de forma jerárquica.

Todo lo que has leído sobre ListStore es válido para el TreeStore. Para obtener una visualización de los datos del árbol, TreeStore dispone de un montón de métodos AppendValues sobrecargados. En muchos casos el primer argumento del método es un objeto TreeIter que será el padre del objeto actual. 

Quizá un ejemplo sea mucho más claro:

...1. private void readDir(string path,TreeIter father){2.  TreeIter child;3.  string[] dirList = Directory.GetDirectories(path);4.  for(int j=0;j<dirList.Length;j++){5.  string nm = getDirName(dirList[j]);6.  child = store.AppendValues(father,nm,cFolder,dirList[j]);7.  readDir(dirList[j],child);8.  }9. }...

¿Qué hace esta función? Analicemos su código usando como referencia los números de línea:

1. Declaración de la función, el primer argumento path es la ruta inicial del sistema de ficheros; el segundo argumento es el Iter donde quiero añadir el hijo.

2. Declaración de la variable.

3. Obtiene la lista de ficheros y directorios contenidos en el path actual, recuerda añadir al comienzo del archivo la declaración “using Sysem.IO”.

4. Comienza un bucle for para iterar en cada elemento del array dirList por una función habitual getDirName que extrae el nombre del fichero desde la ruta completa.

5. Recibe el nombre del elemento actual.

6. Inicializa la variable de tipo TreeIter y añade su contenido (un string) al TreeView usando el objeto store (una instancia de la clase TreeStore).

7. La función se llama así misma declarando el objeto TreeIter del paso anterior como el padre de los próximos elementos.

Page 12: TreeView for Kids

¿Cuál es el resultado de llamar a esta función? Simplemente que puedes llenar el TreeView con una visualización en árbol de tus archivos del sistema. Solo llama a la función así:

...string MyHomeDir = System.Environment.GetEnvironmentVariable("HOME");readDir(MyHomeDir, rootIter); ...

Esto es todo.

Page 13: TreeView for Kids

Tutorial Gtk.TreeView L5Cambio de Datos

Como modificar los datos

Usando la clase CellRenderer es posible manejar eventos relacionados con lo que pasa en una celda de un TreeView.En particular el CellRendererText lanza el evento Edited cuando el contenido de la celda es editado. Para manejar este tipo de eventos (de acuerdo además con el tipo de información que se muestra dentro de la celda)  es posible definir  una función delegada que se invoque cuando el evento es lanzado.Para entender este concepto echemos un vistazo al siguiente código:

...TreeViewColumn col;CellRendererText colr;col = new TreeViewColumn ();colr = new CellRendererText();colr.Edited+=modified_fields_username;col.Title = "UserName";col.PackStart(colr, true);col.AddAttribute (colr, "text", 0);mainTreeView.AppendColumn(col); ...

El texto en negrita en el código anterior es la clave del manejo de la celda editada.Cuando el contenido de la celda (la celda de la columna añadida en el código, otra columna en la cual el evento Edited no se manejará evitando cambios automáticamente) se modifica, el evento Edited es lanzado y se llama a la función modified_fields_username.

La función puede ejecutar la validación de los datos y guardar o no el nuevo valor.

Aquí tienes un ejemplo de esta función:

...private void modified_fields_username(object o, Gtk.EditedArgs args){

TreeIter tmp;if(editingEnabled) {

treeViewEngine.GetIter(out tmp, new Gtk.TreePath (args.Path));treeViewEngine.SetValue(tmp,0,args.NewText);

}}...

Donde:– treeViewEngine es el ListStore asociado con el TreeView mainTreeView.– tmp es el TreeIter donde donde se almacena temporalmente la ruta del elemento a modificar.– editingEnabled es un valor boleano que determina si se a producido el cambio. Si el valor es 

false el cambio no se ha efectuado en el contenido de la celda.

Page 14: TreeView for Kids

El método SetValue de la clase ListStore toma 3 argumentos: la ruta del elemento a modificar, el índice de la columna y el nuevo valor.

Page 15: TreeView for Kids

Gtk.TreeView Tutorials L6Finalmente

Para acabar...

El TreeView implementa el Patrón de Diseño MVC (Modelo – Vista ­ Controlador).

El Modelo es “como se almacenan los datos”. En este contexto del TreeView tiene dos tipos de modelo: ListStore y TreeModel.

La Vista es “como se muestran los datos”. En este contexto hemos visto muchos ejemplos relacionados con la clase CellRenderer y otros atributos de las clases implicadas.

El Controlador es “que datos serán mostrados”. Esto implica filtrar, ordenar y otras operaciones.

Consideración Final

Creo que las clases que provee el GTK Toolkit para implementar una “visualización” de datos dentro de una aplicación son muy potentes. No son fáciles de usar, pero cuando entiendes como “hacer eso”, tendrás todo lo necesario para desarrollar tus programas.

La siguiente captura de pantalla se tomó de mi última aplicación Cooka, un sencillo visor de imágenes desarrollado con Mono y MonoDevelop:

En este caso uso un TreeView de 2 columnas con un CellRendererPixbuf para la primera columna y un CellRendererText para la segunda (con el atributo “markup” añadido al ejecutar para obtener el texto formateado.)

En la última parte de este tutorial encontrarás una pequeña aplicación usando las características explicadas en las lecciones anteriores.

¡¡ Espero que lo disfrutes !!

Page 16: TreeView for Kids

Tutorial Gtk.TreeView L7Código de Prueba

Un ejemplousing System;using System.IO;using Gtk;

// La clase principal con el método Main

class MainClass {public static void Main (string[] args) {

Application.Init ();new MyWindow ();Application.Run ();

}}

// La clase que implementa el GUI

public class MyWindow : Window { private Gtk.TreeView fileList;private Gtk.ListStore fileStore;private Gtk.ScrolledWindow treeViewContainer;

public MyWindow () : base ("window1") {this.SetDefaultSize (400, 300);this.DeleteEvent += new DeleteEventHandler (OnMyWindowDelete);setupGUI();fillTreeView();this.ShowAll ();

}

private void setupGUI(){fileList = new TreeView();fileStore = new ListStore(typeof (string));treeViewContainer = new ScrolledWindow();

TreeViewColumn col = new TreeViewColumn();CellRendererText cellrt = new CellRendererText();col.Title = "Resource Name";col.PackStart(cellrt, false);col.AddAttribute (cellrt, "text", 0);

fileList.AppendColumn(col); fileList.Model = fileStore; treeViewContainer.Add(fileList);this.Add(treeViewContainer);

}

Page 17: TreeView for Kids

private void fillTreeView(){string HomeDir = System.Environment.GetEnvironmentVariable("HOME");string[] dirList = Directory.GetDirectories(HomeDir);for(int j=0;j<dirList.Length;j++){

fileStore.AppendValues(dirList[j]);}

void OnMyWindowDelete (object sender, DeleteEventArgs a){Application.Quit ();a.RetVal = true;

}}

El código en funcionamiento...

Page 18: TreeView for Kids

Tutorial Gtk.TreeView L8Como

1. Cambiar la selección en un treeview de forma programada.

Cambiar la selección en un treeview de forma programada.

Para realizar este tipo de operación necesitas usar un cierto tipo de objeto; la clase principal usada es un TreePath, que representa un nodo del TreeView.Lo primero es recuperar el elemento seleccionado actualmente y obtener un TreeIter para recorrer las filas del TreeView:

TreeIter theIter;TreeModel theModel;myTreeView.Selection.GetSelected(out theModel, out theIter); 

Después tienes que instanciar un TreePath y usarlo para mover la selección del TreeView. Si quieres seleccionar la fila anterior o la siguiente (en función de la fila seleccionada actualmente), debes obtener el TreePath actual, moverlo y usar el nuevo “apuntador” para cambiar la selección:

TreePath myPath = theModel.GetPath(theIter);myPath.Prev(); // para mover arribamyPath.Next(); // par mover abajomyTreeView.Selection.SelectPath(myPath);

Si quieres seleccionar la primera fila o la última fila, tu objeto TreePath deberá usar el apuntador absoluto creado:

// para seleccionar la primera filamyPath = new TreePath("0");myTreeView.Selection.SelectPath(myPath);

// para seleccionar la última filamyPath = new TreePath("" + (totalNumbersOfRow ­ 1));myTreeView.Selection.SelectPath(myPath);

Autor: Salvatore Scarciglia (http://laas.altervista.org)Tutorial: “TreeView for kids” (http://laas.altervista.org/tutorials/tview_1.php)

Traducción: Daniel Valcarce (http://davamix.googlepages.com)Tutorial: “Treeview para niños” (http://davamix.googlepages.com/treeview_for_kids)