Gtk.TreeView: Ejemplos útiles.
Gtk.TreeView: Ejemplos útiles.
Este es el esquema:
Bueno, en este artículo voy a mostrar algunas de las capacidades ocultas del widget TreeView de Gtk#. El TreeView de Gtk es un componente muy util, si bien es un poco intimidante en los primeros pasos, con la práctica, podemos llegar a dominarlo de alguna forma, o por lo menos entenderlo un poco, de manera que nuestras próximas experiencias no sean tan complicadas.
Hoy voy a mostrar un par de ejemplos de un TreeView, utilizando el modelo de lista de elementos.
Hoy voy a mostrar un par de ejemplos de un TreeView, utilizando el modelo de lista de elementos.
Teoría: la teoría no le gusta a nadie, pero en este caso es necesaria aunque sea un poco. Para poder generar un listado con el TreeView hay que tener presentes 3 puntos principales, los cuales están muy relacionados y son todos necesarios:
1 - TreeView: el widget principal, actua como punto de conexion de los dos componentes que abajo describo para lograr una vista de la información directamente hacia el usuario.
2 - TreeModel: el tree model, es el modelo de datos que vamos a utilizar. Define como se almacenan los datos, por ejemplo una Lista (ListStore) o un arbol (TreeStore).
Al crear un TreeModel, debemos informarle que tipos de datos va a contener; Si creamos un ListStore, por ejemplo debemos informarle el tipo de cada uno de los campos. Abajo muestro el constructor:
entonces podemos hacer lo siguiente:
o
3 - CellRenderer: como su nombre lo indica, es el encargado de dibujar cada celda en el TreeView. Dependiendo de la naturaleza de los datos que vamos a mostrar debemos elegir entre uno de varios cell renderers: CellRendererText para texto, CellRendererPixbuf para imagenenes, etc. Es interesante saber que cada celda puede contener mas de un CellRenderer, permitiendo mostrar por ejemplo una imagen y texto a su lado, o las combinaciones que se requieran.
Nombrados estos tres explico un poco como funcionan:
El TreeView es el widget principal, el cual es el encargado de interactuar con el usuario. Cada TreeView debe tener asociado a el un TreeModel (2), si lo que se va a mostrar es un listado en forma de tabla, entonces será un ListStore. Además, el tree view, contiene un conjunto de columnas, cada columna definirá la configuración de las celdas que contiene, es decir a cada columna le diremos cuales cell renderers deben utilizar sus celdas entre otras cosas.
1 - TreeView: el widget principal, actua como punto de conexion de los dos componentes que abajo describo para lograr una vista de la información directamente hacia el usuario.
2 - TreeModel: el tree model, es el modelo de datos que vamos a utilizar. Define como se almacenan los datos, por ejemplo una Lista (ListStore) o un arbol (TreeStore).
Al crear un TreeModel, debemos informarle que tipos de datos va a contener; Si creamos un ListStore, por ejemplo debemos informarle el tipo de cada uno de los campos. Abajo muestro el constructor:
public ListStore (params Type [] types);
entonces podemos hacer lo siguiente:
ListStore ngine = new ListStore (typeof(string), typeof(int));
o
Type[] tlist = new Type[] {typeof (string), typeof (int)};
ListStore ngine = new ListStore (tlist);
3 - CellRenderer: como su nombre lo indica, es el encargado de dibujar cada celda en el TreeView. Dependiendo de la naturaleza de los datos que vamos a mostrar debemos elegir entre uno de varios cell renderers: CellRendererText para texto, CellRendererPixbuf para imagenenes, etc. Es interesante saber que cada celda puede contener mas de un CellRenderer, permitiendo mostrar por ejemplo una imagen y texto a su lado, o las combinaciones que se requieran.
Nombrados estos tres explico un poco como funcionan:
El TreeView es el widget principal, el cual es el encargado de interactuar con el usuario. Cada TreeView debe tener asociado a el un TreeModel (2), si lo que se va a mostrar es un listado en forma de tabla, entonces será un ListStore. Además, el tree view, contiene un conjunto de columnas, cada columna definirá la configuración de las celdas que contiene, es decir a cada columna le diremos cuales cell renderers deben utilizar sus celdas entre otras cosas.
Este es el esquema:
TreeViewColumn <----> TreeView <----> TreeModel
|
|
CellRenrer, CellRenderer,...
Bueno, hechas las aclaraciones teóricas principales, restan algunos puntos, que voy a aclarar con los ejemplos, porque va a ser mas facil de entender así.
Visualmente:
En este ejemplo muestro la creacion de un treeview con dos columnas. La primera contiene solo un nombre, mientras que la segunda tiene la tarea de mostrar un campo de fecha. Ademas, ambas columnas van a permitir la edición de sus valores:
- la primera permitirá la edición del nombre
- la segunda permitirá la edición de la fecha, pero la gracia es que lo hara por partes __ / __ / ____, donde las "/" permanecerán fijas, y tendrá una validación de la fecha editada, si es incorrecta, entonces revertirá la edición.
Internamente:
a) Creacion del ListStore:
para compilar:
mcs -pkg:gtk-sharp-2.0 TreeViewExample.cs
a) capacidad de ordenamiento.
b) capacidad de busqueda.
dd /mm/aaaa llegará a dd/mm/aaaa
Ejemplo 1. TreeView Con editor de fecha.
Este demostrará las siguientes características:Visualmente:
En este ejemplo muestro la creacion de un treeview con dos columnas. La primera contiene solo un nombre, mientras que la segunda tiene la tarea de mostrar un campo de fecha. Ademas, ambas columnas van a permitir la edición de sus valores:
- la primera permitirá la edición del nombre
- la segunda permitirá la edición de la fecha, pero la gracia es que lo hara por partes __ / __ / ____, donde las "/" permanecerán fijas, y tendrá una validación de la fecha editada, si es incorrecta, entonces revertirá la edición.
Internamente:
En el interior, este ejemplo muestra como añadir objetos de clases especificas al tree view. Por ejemplo supongamos que tenemos la siguiente clase:
class Persona
{
public string nombre;
public DateTime nacimiento;
public Persona (string nombre, DateTime nacimiento)
{
this.nombre = nombre;
this.nacimiento = nacimiento;
}
}
Entonces lo que haremos será directamente instanciar estos objetos y meterlos
directamente en nuestro tree model. Para esto tenemos que tener en claro varios
puntos.
directamente en nuestro tree model. Para esto tenemos que tener en claro varios
puntos.
a) Creacion del ListStore:
ListStore ngine = new ListStore (typeof (Persona), typeof (Persona));
b) Cada cell renderer deberá saber como mostrar su valor especifico al usuario,
y además en caso de que se haga edición del valor contenido, también debe
conocer como asignar el nuevo valor al objeto Persona correspondiente. Para ello tenemos las siguientes:
y además en caso de que se haga edición del valor contenido, también debe
conocer como asignar el nuevo valor al objeto Persona correspondiente. Para ello tenemos las siguientes:
public void SetCellDataFunc
(CellRenderer cell_renderer,
TreeCellDataFunc func);
public delegate void TreeCellDataFunc
(TreeViewColumn tree_column,
CellRenderer cell,
TreeModel tree_model,
TreeIter iter);
public event EditedHandler Edited; //(del CellRendererText);
La primeras dos sirven para decirle a cada celda en la columna, como debe obtener los datos a mostrar por el cell renderer. Es decir su función está en obtener el objeto Persona indicado de un lugar particular, tomar el atributo a mostrar (por ejemplo nombre), y entregárselo al cell renderer:
Persona p;
// obtengo y asigno el valor a p
((CellRendererText)cell).Markup = p.nombre;
La última es para hacer el camino inverso, al editarse el valor en la celda del tree view (especificamente en el cell renderer), se lanza el evento, entonces actuamos en consecuencia tomando el nuevo valor, y asignándoselo a la instancia de Persona adecuada.
Bueno, sin mas palabras vamos a ver el código:
/*
* Autor: Jonatan Anauati.
* Email: barakawins@gmail.com
* Licencia: LGPL.
*
* Descripcion:
* Este ejemplo muestra un TreeView con el modelo de lista. En una de las
* columnas de dicho TreeView se ven empaquetados mas de un CellRendererText,
* para permitir el ingreso de una fecha parte por parte (dd / mm / yyyy).
* Ademas permite entender el uso del metodo SetCellDataFunc, el cual permite
* definir una manejadora para poder utilizar tipos complejos en el almacen de
* datos subyacente (ListStore).
* Otra cosa que agrego en este, es la capacidad de ordenar valores, que como
* se están utilizando tipos complejos en el ListStore, se pierde inicialmente.
*
*/
namespace TreeViewExample
{
using System;
using Gtk;
class Persona
{
public string nombre;
public DateTime nacimiento;
public Persona (string nombre, DateTime nacimiento)
{
this.nombre = nombre;
this.nacimiento = nacimiento;
}
}
class TreeViewExample
{
// el widget treeview
TreeView tv;
// para contener los datos que el treeview muestra
ListStore ngine;
public TreeView BuildTreeView ()
{
CellRendererText nameCrt, dayCrt, monthCrt, yearCrt,
dateSep1Crt, dateSep2Crt;
TreeViewColumn nameCol, dateCol;
// los cellrenderers, estos son los encargadados de mostrar el
// valor en la celda que se les asigna.
nameCrt = new CellRendererText ();
nameCrt.Editable = true;
dayCrt = new CellRendererText ();
dayCrt.Editable = true;
monthCrt = new CellRendererText ();
monthCrt.Editable = true;
yearCrt = new CellRendererText ();
yearCrt.Editable = true;
dateSep1Crt = new CellRendererText ();
// Markup contiene el valor final a mostrar.
dateSep1Crt.Markup = "/";
dateSep2Crt = new CellRendererText ();
dateSep2Crt.Markup = "/";
// ahora pueden inicializarse las columnas. Cada una de estas
// va a recivir uno o mas cellRenderers, los cuales dibujaran
// los valores en cada una de sus celdas.
nameCol = new TreeViewColumn ();
dateCol = new TreeViewColumn ();
// ahora todo lo importante.
nameCol.PackStart (nameCrt,true);
dateCol.PackStart (dayCrt,false);
dateCol.PackStart (dateSep1Crt,false);
dateCol.PackStart (monthCrt,false);
dateCol.PackStart (dateSep2Crt,false);
dateCol.PackStart (yearCrt,true);
// contenedor de los datos en el bajo nivel. Esta sera la lista
// que va a contener toda la informacion.
this.ngine = new ListStore (typeof (Persona),typeof (Persona));
// contenedor principal.
this.tv = new TreeView (this.ngine);
this.tv.HeadersClickable = false;
this.tv.EnableSearch = false;
this.tv.RulesHint=true;
this.tv.HeadersVisible = true;
this.tv.AppendColumn (nameCol);
this.tv.AppendColumn (dateCol);
// ahora le digo a cada columna como tiene rellenar cada celda de
// el ListStore que le asignamos. Hace el parseo entre el Tipo
// Persona, y la columna correspondiente.
// ListStore -> (Columna,cellrenderer)
nameCol.SetCellDataFunc (nameCrt, new TreeCellDataFunc (showNombrePersona));
dateCol.SetCellDataFunc (dayCrt, new TreeCellDataFunc (showDiaNacPersona));
dateCol.SetCellDataFunc (monthCrt, new TreeCellDataFunc (showMesNacPersona));
dateCol.SetCellDataFunc (yearCrt, new TreeCellDataFunc (showAnoNacPersona));
// ahora el proceso inverso, el usuario edita un cellrt dentro de un column,
// y entonces se lanza el callback necesario para que verifique el valor, y
// ademas si este es valido, se lo asigne al objeto Persona en su atributo
// indicado.
nameCrt.Edited += new Gtk.EditedHandler (nombreCellEdited);
yearCrt.Edited += new Gtk.EditedHandler (yearCellEdited);
monthCrt.Edited += new Gtk.EditedHandler (monthCellEdited);
dayCrt.Edited += new Gtk.EditedHandler (dayCellEdited);
// ahora el toque que faltaba
// propiedades y eventos visuales.
nameCol.Resizable = true;
nameCol.Title = "Nombre";
dateCol.Resizable = true;
dateCol.Title = "Fecha de Nacimiento";
// Genera datos de testing y los carga al treeview.
this.LoadListStore ();
return this.tv;
}
// Cada TreeCellDataFunc, es encargada de:
// 1 - Buscar el objeto correspondiente en el ListStore.
// 2 - Tomar el valor indicado de dicho objeto (nombre o nacimiento).
// 3 - Asignar el valor al CellRenderer, para que se vea dibujado en
// la celda.
public void showNombrePersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
// 0 (cero) indica el numero de columna. Igualmente, creo que es
// bastante claro que aquí puedo utilizar 0 o 1, de forma
// indistinta, ya que nuestro ListStore contiene la misma
// referencia a Persona en ambos cells.
Persona p =(Persona)this.ngine.GetValue (iter,0);
if (p == null) return;
string nom = (p.nombre == null)?"":p.nombre;
// Lo siguiente es mostrar el valor en la celda, Markup como ya
// dije es el atributo cuyo valor se muestra directamente en la
// celda.
((CellRendererText) cell).Markup = nom;
}
public void showDiaNacPersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
Persona p =(Persona)this.ngine.GetValue (iter,1);
if (p == null) return;
DateTime d = p.nacimiento;
string val = d.Day.ToString ().PadLeft (2,'0');
((CellRendererText) cell).Markup = val;
}
public void showMesNacPersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
Persona p =(Persona)this.ngine.GetValue (iter,1);
if (p == null) return;
DateTime d = p.nacimiento;
string val = d.Month.ToString ().PadLeft (2,'0');
((CellRendererText) cell).Markup = val;
}
public void showAnoNacPersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
Persona p =(Persona)this.ngine.GetValue (iter,1);
if (p == null) return;
DateTime d = p.nacimiento;
string val = d.Year.ToString ().PadLeft (4,'0');
((CellRendererText) cell).Markup = val;
}
public void nombreCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,0);
p.nombre = args.NewText;
}
public void yearCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,1);
try
{
int y = int.Parse(args.NewText);
DateTime dt = new DateTime (y,p.nacimiento.Month, p.nacimiento.Day);
p.nacimiento = dt;
}
catch (System.Exception ex)
{ }
}
public void monthCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,1);
try
{
int m = int.Parse(args.NewText);
DateTime dt = new DateTime (p.nacimiento.Year,m, p.nacimiento.Day);
p.nacimiento = dt;
}
catch (System.Exception ex)
{ }
}
public void dayCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,1);
try
{
int d = int.Parse(args.NewText);
DateTime dt = new DateTime (p.nacimiento.Year,p.nacimiento.Month, d);
p.nacimiento = dt;
}
catch (System.Exception ex)
{ }
}
int[,] TestDates = new int[,] { {2000,10,9}, {1980,2, 10}, {1990,5,24}, {1929, 3, 3}, {1993, 12, 7}};
string[] TestNombres= {"Juan Peres", "Jorge Pindocha", "Ernesto Rodrigues","Adrian Dilori","Clemente Tomas Taus"};
public void LoadListStore ()
{
for (int i = 0; i < TestNombres.Length; i++)
{
DateTime nac = new DateTime (TestDates[i,0], TestDates[i,1],TestDates[i,2]);
Persona p = new Persona (TestNombres[i],nac);
this.ngine.AppendValues (p,p);
}
}
}
public class MainClass
{
public static void Main (string[] args)
{
Application.Init ();
Window main = new Window ("TreeView de Ejemplo");
main.DeleteEvent += new DeleteEventHandler (OnDeleteWindow);
TreeView tv = new TreeViewExample().BuildTreeView ();
main.Add (tv);
main.ShowAll();
Application.Run ();
}
static void OnDeleteWindow (object sender, DeleteEventArgs args)
{
Application.Quit ();
}
}
}
para compilar:
mcs -pkg:gtk-sharp-2.0 TreeViewExample.cs
Ejemplo 2. TreeView Con editor de fecha, ordenamiento y busquedas.
Bueno, el ejemplo anterior fué bonito, pero, al hacer todas estas achurías, perdimos dos capacidades muy útiles:b) capacidad de busqueda.
Pero todo tiene solucion, para ello al ejemplo anterior le incorporamos el uso de las siguientes:
public void SetSortFunc
(int sort_column_id, TreeIterCompareFunc sort_func)
public delegate int TreeIterCompareFunc
(TreeModel model, TreeIter a, TreeIter b)
del ListStore, las que utilizamos para para permitir el ordenamiento de las celdas en una columna y además las siguientes:
font >public TreeViewSearchEqualFunc SearchEqualFunc { set; get; }
public delegate bool TreeViewSearchEqualFunc
(TreeModel model, int column, string key, TreeIter iter)
del TreeView, las cuales utilizamos para la búqueda de valores en el treeview por demanda.
Para aprobechar el nivel de personalización que nos brinda el TreeView, a las búsquedas le vamos a agregar el uso de expresiones regulares.
Por ejemplo:
"*eres", llegara a "Juan Peres", y todas los delirios que se quieran: "J.\+s", llegará a "Juan Peres", y todo lo que se quiera.Para aprobechar el nivel de personalización que nos brinda el TreeView, a las búsquedas le vamos a agregar el uso de expresiones regulares.
Por ejemplo:
Por otra parte, también vamos a hacer una lectura mas o menos inteligente de las fechas a buscar
dd-mm-aaaa llegará a dd/mm/aadd /mm/aaaa llegará a dd/mm/aaaa
/*
* Autor: Jonatan Anauati.
* Email: barakawins@gmail.com
* Licencia: LGPL.
*
* Descripcion:
* Este ejemplo muestra un TreeView con el modelo de lista. En una de las
* columnas de dicho TreeView se ven empaquetados mas de un CellRendererText,
* para permitir el ingreso de una fecha parte por parte (dd / mm / yyyy).
* Ademas permite entender el uso del metodo SetCellDataFunc, el cual permite
* definir una manejadora para poder utilizar tipos complejos en el almacen de
* datos subyacente (ListStore).
* Otra cosa que agrego en este, es la capacidad de ordenar valores, que como
* se están utilizando tipos complejos en el ListStore, se pierde inicialmente.
*
*/
namespace TreeViewExample
{
using System;
using Gtk;
using System.Text;
using System.Text.RegularExpressions;
class Persona
{
public string nombre;
public DateTime nacimiento;
public Persona (string nombre, DateTime nacimiento)
{
this.nombre = nombre;
this.nacimiento = nacimiento;
}
}
class TreeViewExample
{
// el widget treeview
TreeView tv;
// para contener los datos que el treeview muestra
ListStore ngine;
public TreeView BuildTreeView ()
{
CellRendererText nameCrt, dayCrt, monthCrt, yearCrt,
dateSep1Crt, dateSep2Crt;
TreeViewColumn nameCol, dateCol;
// los cellrenderers, estos son los encargadados de mostrar el
// valor en la celda que se les asigna.
nameCrt = new CellRendererText ();
nameCrt.Editable = true;
dayCrt = new CellRendererText ();
dayCrt.Editable = true;
monthCrt = new CellRendererText ();
monthCrt.Editable = true;
yearCrt = new CellRendererText ();
yearCrt.Editable = true;
dateSep1Crt = new CellRendererText ();
// Markup contiene el valor final a mostrar.
dateSep1Crt.Markup = "/";
dateSep2Crt = new CellRendererText ();
dateSep2Crt.Markup = "/";
// ahora pueden inicializarse las columnas. Cada una de estas
// va a recivir uno o mas cellRenderers, los cuales dibujaran
// los valores en cada una de sus celdas.
nameCol = new TreeViewColumn ();
dateCol = new TreeViewColumn ();
// ahora todo lo importante.
nameCol.PackStart (nameCrt,true);
dateCol.PackStart (dayCrt,false);
dateCol.PackStart (dateSep1Crt,false);
dateCol.PackStart (monthCrt,false);
dateCol.PackStart (dateSep2Crt,false);
dateCol.PackStart (yearCrt,true);
// contenedor de los datos en el bajo nivel. Esta sera la lista
// que va a contener toda la informacion.
this.ngine = new ListStore (typeof (Persona),typeof (Persona));
// contenedor principal.
this.tv = new TreeView (this.ngine);
this.tv.HeadersClickable = false;
this.tv.EnableSearch = true;
this.tv.RulesHint=true;
this.tv.HeadersVisible = true;
this.tv.AppendColumn (nameCol);
this.tv.AppendColumn (dateCol);
// ahora le digo a cada columna como tiene rellenar cada celda de
// el ListStore que le asignamos. Hace el parseo entre el Tipo
// Persona, y la columna correspondiente.
// ListStore -> (Columna,cellrenderer)
nameCol.SetCellDataFunc (nameCrt, new TreeCellDataFunc (showNombrePersona));
dateCol.SetCellDataFunc (dayCrt, new TreeCellDataFunc (showDiaNacPersona));
dateCol.SetCellDataFunc (monthCrt, new TreeCellDataFunc (showMesNacPersona));
dateCol.SetCellDataFunc (yearCrt, new TreeCellDataFunc (showAnoNacPersona));
// ahora el proceso inverso, el usuario edita un cellrt dentro de un column,
// y entonces se lanza el callback necesario para que verifique el valor, y
// ademas si este es valido, se lo asigne al objeto Persona en su atributo
// indicado.
nameCrt.Edited += new Gtk.EditedHandler (nombreCellEdited);
yearCrt.Edited += new Gtk.EditedHandler (yearCellEdited);
monthCrt.Edited += new Gtk.EditedHandler (monthCellEdited);
dayCrt.Edited += new Gtk.EditedHandler (dayCellEdited);
// propiedades y eventos visuales.
nameCol.Resizable = true;
nameCol.Title = "Nombre";
dateCol.Resizable = true;
dateCol.Title = "Fecha de Nacimiento";
// Activa el ordenamiento
ngine.SetSortFunc (0, new TreeIterCompareFunc(NombreCompareFunc));
ngine.SetSortFunc (1, new TreeIterCompareFunc(DateCompareFunc));
for (int i=0; i < tv.Columns.Length; i++)
{
this.tv.Columns[i].SortColumnId = i;
this.tv.Columns[i].SortColumnId = i;
}
// Activa la busqueda !
tv.SearchEqualFunc = new TreeViewSearchEqualFunc (treeSearchFcn);
tv.SearchColumn = 0;
foreach (TreeViewColumn tvc in this.tv.Columns)
tvc.Clicked += new System.EventHandler
(OnColumnClickedCallBack);
// Genera datos de testing y los carga al treeview.
this.LoadListStore ();
return this.tv;
}
// Cada TreeCellDataFunc, es encargada de:
// 1 - Buscar el objeto correspondiente en el ListStore.
// 2 - Tomar el valor indicado de dicho objeto (nombre o nacimiento).
// 3 - Asignar el valor al CellRenderer, para que se vea dibujado en
// la celda.
public void showNombrePersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
// 0 (cero) indica el numero de columna. Igualmente, creo que es
// bastante claro que aquí puedo utilizar 0 o 1, de forma
// indistinta, ya que nuestro ListStore contiene la misma
// referencia a Persona en ambos cells.
Persona p =(Persona)this.ngine.GetValue (iter,0);
if (p == null) return;
string nom = (p.nombre == null)?"":p.nombre;
// Lo siguiente es mostrar el valor en la celda, Markup como ya
// dije es el atributo cuyo valor se muestra directamente en la
// celda.
((CellRendererText) cell).Markup = nom;
}
public void showDiaNacPersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
Persona p =(Persona)this.ngine.GetValue (iter,1);
if (p == null) return;
DateTime d = p.nacimiento;
string val = d.Day.ToString ().PadLeft (2,'0');
((CellRendererText) cell).Markup = val;
}
public void showMesNacPersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
Persona p =(Persona)this.ngine.GetValue (iter,1);
if (p == null) return;
DateTime d = p.nacimiento;
string val = d.Month.ToString ().PadLeft (2,'0');
((CellRendererText) cell).Markup = val;
}
public void showAnoNacPersona (
Gtk.TreeViewColumn tree_column,
Gtk.CellRenderer cell,
Gtk.TreeModel tree_model,
Gtk.TreeIter iter )
{
Persona p =(Persona)this.ngine.GetValue (iter,1);
if (p == null) return;
DateTime d = p.nacimiento;
string val = d.Year.ToString ().PadLeft (4,'0');
((CellRendererText) cell).Markup = val;
}
public void nombreCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,0);
p.nombre = args.NewText;
}
public void yearCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,1);
try
{
int y = int.Parse(args.NewText);
DateTime dt = new DateTime (y,p.nacimiento.Month, p.nacimiento.Day);
p.nacimiento = dt;
}
catch (System.Exception ex)
{ }
}
public void monthCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,1);
try
{
int m = int.Parse(args.NewText);
DateTime dt = new DateTime (p.nacimiento.Year,m, p.nacimiento.Day);
p.nacimiento = dt;
}
catch (System.Exception ex)
{ }
}
public void dayCellEdited (object sender, EditedArgs args)
{
TreeIter rowPointer;
TreePath temp_path;
Persona p;
temp_path = new Gtk.TreePath (args.Path);
this.ngine.GetIter (out rowPointer, temp_path);
// tree iter, columna
p = (Persona) this.ngine.GetValue (rowPointer,1);
try
{
int d = int.Parse(args.NewText);
DateTime dt = new DateTime (p.nacimiento.Year,p.nacimiento.Month, d);
p.nacimiento = dt;
}
catch (System.Exception ex)
{ }
}
int[,] TestDates = new int[,] { {2000,10,9}, {1980,2, 10}, {1990,5,24}, {1929, 3, 3}, {1993, 12, 7}};
string[] TestNombres= {"Juan Peres", "Jorge Pindocha", "Ernesto Rodrigues","Adrian Dilori","Clemente Tomas Taus"};
public void LoadListStore ()
{
for (int i = 0; i < TestNombres.Length; i++)
{
DateTime nac = new DateTime (TestDates[i,0], TestDates[i,1],TestDates[i,2]);
Persona p = new Persona (TestNombres[i],nac);
this.ngine.AppendValues (p,p);
}
}
public virtual int NombreCompareFunc (TreeModel model, TreeIter src, TreeIter dst)
{
Persona srcObject=null, dstObject=null;
IComparable srcVal=null, dstVal=null;
int ret=0;
srcObject = (Persona)((ListStore)model).GetValue (src,0);
dstObject = (Persona)((ListStore)model).GetValue (dst,0);
try
{
srcVal = (IComparable)srcObject.nombre;
dstVal = (IComparable)dstObject.nombre;
ret = srcVal.CompareTo (dstVal);
}
catch (InvalidCastException ex)
{
;
}
return ret;
}
public virtual int DateCompareFunc (TreeModel model, TreeIter src, TreeIter dst)
{
Persona srcObject=null, dstObject=null;
IComparable srcVal=null, dstVal=null;
int ret=0;
srcObject = (Persona)((ListStore)model).GetValue (src,1);
dstObject = (Persona)((ListStore)model).GetValue (dst,1);
try
{
srcVal = (IComparable)srcObject.nacimiento;
dstVal = (IComparable)dstObject.nacimiento;
ret = srcVal.CompareTo (dstVal);
}
catch (InvalidCastException ex)
{
;
}
return ret;
}
// busqueda con expresiones regulares !
// lo hacemos de esta forma para no tener que recompilar cada expresion
// en cada busqueda sobre la misma columna.
Regex searchEx= null;
string regex = null;
public bool treeSearchFcn
(TreeModel model, int columnNr, string key, TreeIter iter)
{
try
{
if (this.regex == null || regex != key)
{
StringBuilder sb = new StringBuilder ("^");
sb.Append(key);
sb.Replace ("*",".*");
if (columnNr == 1)
{
sb.Replace ("/","");
sb.Replace ("-","");
sb.Replace (" ","");
}
sb.Append(".*");
this.regex = key;
this.searchEx = new Regex (sb.ToString (),RegexOptions.IgnoreCase);
}
ListStore ngine = null;
Persona row=null;
string cellValue=null;
ngine = (ListStore)model;
// es indistinto si pongo 0 o 1 ya que ambos lugares guardan
// la misma referencia.
row = (Persona) ngine.GetValue (iter, 0);
if (columnNr == 0)
cellValue = row.nombre;
else
cellValue = row.nacimiento.ToString ("%dd%MM%yyyy");
//busqueda incremental seria algo así:
//return !cellValue.StartsWith (key);
//pero..., super busqueda con expresiones regulares !!!
return !this.searchEx.IsMatch (cellValue);
}
catch (ArgumentException argEx)
{
this.regex = null;
return true;
}
}
public void OnColumnClickedCallBack (object sender, EventArgs args)
{
int cnr=0;
foreach (TreeViewColumn tvc in this.tv.Columns)
{
if (sender == tvc) break;
cnr++;
}
this.tv.SearchColumn = cnr;
}
}
public class MainClass
{
public static void Main (string[] args)
{
Application.Init ();
Window main = new Window ("TreeView de Ejemplo");
main.DeleteEvent += new DeleteEventHandler (OnDeleteWindow);
TreeView tv = new TreeViewExample().BuildTreeView ();
main.Add (tv);
main.ShowAll();
Application.Run ();
}
static void OnDeleteWindow (object sender, DeleteEventArgs args)
{
Application.Quit ();
}
}
}
Bueno, espero que estos ejemplos le sean útiles a alguien, porque la verdad es que nunca pude encontrar ningún ejemplo mas o menos completo.
Etiquetas: c sharp, c#, Expresiones regulares con C sharp., Expresiones regulares con mono, Gtk sharp, Gtk#, ListStore, ListView con Gtk sharp, mono, programación, TreeView

0 comentarios:
Publicar un comentario en la entrada
Suscribirse a Enviar comentarios [Atom]
<< Página principal