Sunteți pe pagina 1din 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:
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.
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.
Tutorial Gtk.TreeView L2
Propiedades 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.
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.
Tutorial Gtk.TreeView L3
El 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 
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á visible
col.PackStart(cellrt, true);
col.AddAttribute (cellrt, "text", 0); // la siguiente columna será 1 en vez de 0
userList.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:
...
/*
userList es el TreeView
onItemSelected 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:
...
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 
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.
Tutorial Gtk.TreeView L4
El 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.
¿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.
Tutorial Gtk.TreeView L5
Cambio 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.
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.
Gtk.TreeView Tutorials L6
Finalmente

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 !!
Tutorial Gtk.TreeView L7
Código de Prueba

Un ejemplo
using 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);
}
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...
Tutorial Gtk.TreeView L8
Como

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 arriba
myPath.Next(); // par mover abajo
myTreeView.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 fila
myPath = new TreePath("0");
myTreeView.Selection.SelectPath(myPath);

// para seleccionar la última fila
myPath = 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)

S-ar putea să vă placă și