Llenar un Gtk.TreeView con MySQL


MonoDevelopTratando de ir extendiendo el tema de la conexión con MySQL ya empezamos a entrar en territorio más especifico, y en este artículo intentaré explicar por medio de un ejemplo como podemos tomar las filas devueltas por una consulta de MySQL a un Gtk.TreeView, tratando de emular un "DataGrid". También podremos capturar el ID de la fila seleccionada en un Gtk.Entry.

Este artículo es una extensión de "Conectar a MySQL con MonoDevelop", por lo tanto, me saltaré todo el tema de conexión.

Primero que nada, vamos a crear la tabla que vamos a usar para este ejemplo, en una base de datos llamada "prueba".

-- 
-- Estructura de tabla para la tabla `usuarios`
-- 

DROP TABLE IF EXISTS `usuarios`;
CREATE TABLE `usuarios` (
  `id` int(11) NOT NULL auto_increment,
  `nombre` varchar(150) NOT NULL,
  `apellidos` varchar(200) NOT NULL,
  `telefono` varchar(100) NOT NULL,
  `ciudad` varchar(50) NOT NULL,
  PRIMARY KEY  (`id`)
) TYPE=MyISAM AUTO_INCREMENT=3 COMMENT='Tabla de Usuarios' AUTO_INCREMENT=3 ;

-- 
-- Volcar la base de datos para la tabla `usuarios`
-- 

INSERT INTO `usuarios` VALUES (1, 'Alejandro', 'Garcia', '111-1111111', 'Puebla');
INSERT INTO `usuarios` VALUES (2, 'Carlos', 'Lopez', '222-2222222', 'D.F.');

y agregamos un nuevo usuario llamado "mono" con contraseña "develop" que tenga acceso total a la base de datos "prueba". (En caso de no tenerlo anteriormente).

Ahora es momento de crear nuestro nuevo proyecto Gtk#, como siempre desde el menú "Archivo" en la opción "Nuevo Proyecto...". (Estoy usando la versión 0.12 de MonoDevelop para el desarrollo de este ejemplo).


Les recuerdo que al final del presente artículo se encuentran todos los archivos usados en este proyecto listos para su descarga.

Para este proyecto vamos necesitar usar únicamente dos Widgets; un Gtk.TreeView, que es donde se llenarán las filas de datos, y un Gtk.Entry, que es donde veremos que fila hemos seleccionado en el TreeView, por lo tanto el formulario quedaría más o menos así:


Con las siguientes propiedades.

Gtk.TreeView
    Nombre del widget: "treeviewData"

Gtk.Entry
    Nombre del widget: "entrySeleccionado"
    isEditable: No seleccionado

No hay que olvidar seleccionar cada uno de los Widgets y pulsar sobre el botón "Bind to Field", para que sean declarados en el código fuente.

Ya por último en el diseño del formulario, solo nos queda seleccionar el TreeView y en las "Propiedades del componente" dar de alta la señal "CursorChanged" dándole un nombre al Handler como por ejemplo "treeviewData_cursorChanged", para que posteriormente podamos detectar el ID de alguna fila seleccionada.


Ya es momento de empezar a escribir algo de código, así que para empezar, debemos de realizar la conexión con MySQL, punto que ha quedado explicado en el artículo anterior "Conectar a MySQL con MonoDevelop".

Antes de continuar, quiero recomendar ampliamente leer el manual "TreeView for Kids", o en español "TreeView para niños", el cual fue traducido por Daniel Valcarce, y también poner especial atención en estudiar la versión ampliada que nos proporciona Mono Hispano de TreeView para niños, donde podremos conocer mucho más a detalle de lo que yo puedo, la naturaleza y funcionamiento de este Widget.

Lo primero es crear las columnas de las que se compondrá nuestro listado, en este caso, y basado en nuestra tabla de mysql, estoy pensando en incluir todos los campos (id, nombre, apellidos, telefono, ciudad). Para este efecto usaremos el método "Gtk.TreeView.AppendColumn", quien como su nombre indica, agrega una nueva columna a nuestro TreeView, en este caso vamos agregar 5 columnas de la siguiente forma.

// Se agregan las columnas al treeview
treeviewData.AppendColumn("ID", new Gtk.CellRendererText(), "text", 0);
treeviewData.AppendColumn("Nombre", new Gtk.CellRendererText(), "text", 1);
treeviewData.AppendColumn("Apellidos", new Gtk.CellRendererText(), "text", 2);
treeviewData.AppendColumn("Telefono", new Gtk.CellRendererText(), "text", 3);
treeviewData.AppendColumn("Ciudad", new Gtk.CellRendererText(), "text", 4);

  • El primer parámetro es el nombre que nosotros le asignamos a la columna.
  • El segundo parámetro es un Gtk.CellRenderer, el cual se encarga de manejar la visualización de los datos de cada celda dentro de un TreeView. Existen 3 tipos de CellRenderer: Gtk.CellRendererText, el cual se usa para mostrar solo texto, Gtk.CellRendererPixBuf para el manejo de imágenes y Gtk.CellRendererToggle, con el cual lograremos mostrar un CheckBox, que seguramente nos será de mucha utilidad en campos booleanos.
  • El tercer parámetro es un conjunto de atributos para el tipo de visualización para la columna, donde podemos seleccionar entre tres valores: "text", "pixbuf" y "markup".
  • El cuarto parámetro, es el orden de identificación de las columnas.

Debemos tener muy en cuenta que el Widget TreeView incorpora un patrón MVC, por lo tanto el CellRenderer corresponde al "View".

Retomando el ejemplo que nos concierne, la columna del ID solo la quiero usar para el manejo interno de listado, por lo que la podemos ocultar modificando su visibilidad.

// Oculto la columna del ID
treeviewData.Columns[0].Visible = false;

Ahora es necesario crear el modelo (Model del MVC), usando Gtk.ListStore. Como se puede ver, corresponde a las 5 columnas usadas y se le declara el tipo de datos que se va a usar, para después asignarlo al TreeView de la siguiente forma:

// Se crea el modelo
Gtk.ListStore clientesListStore = new Gtk.ListStore (typeof(int), typeof(string), typeof(string), typeof(string), typeof(string));
		
// Se asigna el modelo al treeview
treeviewData.Model = clientesListStore;

Conectando a MySQL justo como el artículo pasado, y dentro del while, podemos empezar a llenar nuestro TreeView de una forma realmente fácil usando el método Gtk.ListStore.AppendValues, y como el modelo ya se encuentra conectado, el CellRenderer empieza a realizar su trabajo mostrando cada una de las filas.

clientesListStore.AppendValues(myReader["id"], myReader["nombre"].ToString(), myReader["apellidos"].ToString(), myReader["telefono"].ToString(), myReader["ciudad"].ToString());

El siguiente objetivo es poder detectar el ID de una fila de datos seleccionada, para ello usaremos el handler "treeviewData_CursorChanged", incluyendo el siguiente código.

Gtk.TreeModel model;
Gtk.TreeIter iter;
if (treeviewData.Selection.GetSelected(out model, out iter)) {
    entrySeleccionado.Text = "ID Seleccionado: " + model.GetValue(iter, 0).ToString();
}

La idea, aunque algo enredada, es simple, Gtk.TreeView.Selection.GetSelected, nos va a entregar tanto el modelo, como la fila seleccionada, para después poder sacar el valor de la columna.

El código completo quedaría de la siguiente forma

using System;
using Gtk;

// Se agregan las referencias necesarias para conectar a la DB
using System.Data;
using MySql.Data.MySqlClient;

public class MainWindow: Gtk.Window
{
	protected Gtk.TreeView treeviewData;
	protected Gtk.Entry entrySeleccionado;

	
	public MainWindow (): base ("")
	{
		Stetic.Gui.Build (this, typeof(MainWindow));
		
		// Se agregan las columnas al treeview
		treeviewData.AppendColumn("ID", new Gtk.CellRendererText(), "text", 0);
		treeviewData.AppendColumn("Nombre", new Gtk.CellRendererText(), "text", 1);
		treeviewData.AppendColumn("Apellidos", new Gtk.CellRendererText(), "text", 2);
		treeviewData.AppendColumn("Telefono", new Gtk.CellRendererText(), "text", 3);
		treeviewData.AppendColumn("Ciudad", new Gtk.CellRendererText(), "text", 4);
		
		// Oculto la columna del ID
		treeviewData.Columns[0].Visible = false;
		
		// Se crea el modelo
		Gtk.ListStore clientesListStore = new Gtk.ListStore (typeof(int), typeof(string), typeof(string), typeof(string), typeof(string));
		
		// Se asigna el modelo al treeview
		treeviewData.Model = clientesListStore;
		
		// Cadena de Conexion a la DB
		string connectionString =
			"Server=localhost;" +
			"Database=prueba;" +
			"User ID=mono;" +
			"Password=develop;" +
			"Pooling=false";

		// Query para extraer la informacion de la tabla
		string myQuery = "SELECT id, nombre, apellidos, telefono, ciudad FROM usuarios;";

		// Se crea el objeto de conexion
		MySqlConnection myConnection = new MySqlConnection(connectionString);
		
		try
		{
			// Abre la conexion
			myConnection.Open();

			// Crea el objeto de ejecucion del query
			MySqlCommand myCommand = new MySqlCommand(myQuery, myConnection);

			// Ejecuta el query
			MySqlDataReader myReader = myCommand.ExecuteReader();

			// Lee cada uno de los registros devueltos
			while (myReader.Read())
			{
				// Se agrega una linea al treeview
				clientesListStore.AppendValues(myReader["id"], myReader["nombre"].ToString(), myReader["apellidos"].ToString(), myReader["telefono"].ToString(), myReader["ciudad"].ToString());
				Console.WriteLine("ID: " + myReader["id"].ToString());
			}

			// Se cierra el reader
			myReader.Close();

			// Se cierra la conexion con la DB
			myConnection.Close();
		}
		
		catch(Exception myError)
		{
			// En caso de algun error lo veremos en la consola de depuracion
			Console.WriteLine(myError.ToString());
		}

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

	protected virtual void treeviewData_CursorChanged(object sender, System.EventArgs e)
	{
		Gtk.TreeModel model;
		Gtk.TreeIter iter;
		if (treeviewData.Selection.GetSelected(out model, out iter)) {
			entrySeleccionado.Text = "ID Seleccionado: " + model.GetValue(iter, 0).ToString();
		}
	}

}

Llegó la hora de ejecutar el proyecto.


Por el momento eso es todo, espero que este artículo sea de utilidad. Saludos.

El proyecto y código relacionado a este artículo, están disponibles en los siguientes archivos.

AdjuntoTamaño
MySQLTreeView.tar.gz5.66 KB
prueba.sql.gz557 bytes



Imagen de Anónimo

Felicitaciones por la pagina y gracias por este ejemplo.

Podrias, porfavor, hacer lo mismo pero con un combo box

gracias!!

Imagen de nexus
Muy buena idea, voy a empezar a trabajarlo y lo publico en cuanto tenga tiempo.

Saludos
Imagen de Anónimo

gracias por tu ejemplo, es muy bueno

Imagen de Anónimo

hola,
a mimme da error en la consola, con la sentencia:
Console.WriteLine("ID: " + myReader["id"].ToString());
pero si me aparece el Id :

(slnMySqlTreeView:8630): Gtk-WARNING **: /build/buildd/gtk+2.0-2.12.9/gtk/gtkliststore.c:608: Unable to convert from guint to gint

ID: 1

(slnMySqlTreeView:8630): Gtk-WARNING **: /build/buildd/gtk+2.0-2.12.9/gtk/gtkliststore.c:608: Unable to convert from guint to gint

ID: 2

y en el treeview la columna Id me aparece con valor cero, y ademas cambia de nombre,por ejemplo en la BD el campo es "id" y en treeview aparece :"ID", pero, como repito, con valort cero.
Sin embrago si hago la consulta con MySql Query Browser me aparece todom correctamente..

A que se deberá esto...el codigo no lo he cambiado todo esta igual..

Gracias.

Imagen de Anónimo

Hola, yo escribi acerca de unos errores que me daban, bueno he preguntado en el canal irc #mono y me han dado la respuesta :
mhutch: try Gtk.ListStore (typeof(uint)
mhutch:I assume mysql is returning uints
mhutch:so when they're loaded into the store, GTK# marshals them to guint mhutch:whereas in the store definition, the typeof(int) is understood as a gint
mhutch: and a uint32 cannot be implicitly converted to/from an int32
mhutch:basically, the probalem arises because ethe GTK# liststore binding uses "object"
mhutch: we should make a generic liststore, which would catch this at compile-time :-)

copio esto por si acaso le sirve a alguien

Imagen de Anónimo

Hola,
puese un campo "Dueño" en una tabla y la monento de hacer la consulta
no lo encuentra, asi que no trae nada, aunque si guarda, ademas, tengo una tabla llamada Dueño y me hace las consultas bien...Durante horas con este problema y al fin lo he encontrado, tan simple, no se debe poner un nombre en los campos que contenga la letra "ñ".
Quiza esto sirva de algo a alguien...por otro lado, sera esto un bug?
y eso que estoy usando la ultima version de MySql

Imagen de arcangeldoc
void creacion_del_combobox(int tipocombobox, string solicitadopor, string concargoa)
{
	idtipointernamiento = idcentrocosto;
	// Llenado de combobox1
	combobox_tipo_admision.Clear();
	CellRendererText cell1 = new CellRendererText();
	combobox_tipo_admision.PackStart(cell1, true);
	combobox_tipo_admision.AddAttribute(cell1,"text",0);

	ListStore store1 = new ListStore( typeof (string), typeof (int));
	combobox_tipo_admision.Model = store1;

	combobox_tipo_admision2.Clear();
	CellRendererText cell2 = new CellRendererText();
	combobox_tipo_admision2.PackStart(cell2, true);
	combobox_tipo_admision2.AddAttribute(cell2,"text",0);

	ListStore store2 = new ListStore( typeof (string), typeof (int));
	combobox_tipo_admision2.Model = store2;

	string accesocentrocosto = "";
	bool primero = true;

	if(tipocombobox == 1){
		foreach (int i in this.array_idtipoadmisiones){
			if (primero == true){
				accesocentrocosto = i.ToString();
				primero = false;
			}else{
				accesocentrocosto = accesocentrocosto + "','"+i.ToString();
			}
		}

		// lleno de la tabla de his_tipo_de_admisiones
		NpgsqlConnection conexion;
		conexion = new NpgsqlConnection (connectionString+nombrebd);
		// Verifica que la base de datos este conectada
		try{
			conexion.Open ();
			NpgsqlCommand comando;
			comando = conexion.CreateCommand ();
			comando.CommandText = "SELECT * FROM hscmty_his_tipo_admisiones "+
								"WHERE id_tipo_admisiones IN('"+accesocentrocosto+"')"+
								"ORDER BY descripcion_admisiones;";

			NpgsqlDataReader lector = comando.ExecuteReader ();
			while (lector.Read()){
				if((int) lector["id_tipo_admisiones"] == idtipointernamiento){
					store1.AppendValues ((string) lector["descripcion_admisiones"], (int) lector["id_tipo_admisiones"]);
				}
				store2.AppendValues ((string) lector["descripcion_admisiones"], (int) lector["id_tipo_admisiones"]);
			}
		}catch (NpgsqlException ex){
			MessageDialog msgBoxError = new MessageDialog (MyWinError,DialogFlags.DestroyWithParent,
			MessageType.Error,ButtonsType.Close,"PostgresSQL error: {0}",ex.Message);
			msgBoxError.Run ();				msgBoxError.Destroy();
		}
		conexion.Close ();
	}else{
		store1.AppendValues ((string) solicitadopor,0);
		store2.AppendValues ((string) concargoa,0);
	}

	TreeIter iter1;
	if (store1.GetIterFirst(out iter1)){
		//Console.WriteLine(iter2);
		combobox_tipo_admision.SetActiveIter (iter1);
	}

	TreeIter iter2;
	if (store2.GetIterFirst(out iter2)){
		//Console.WriteLine(iter2);
		combobox_tipo_admision2.SetActiveIter (iter2);
	}

	combobox_tipo_admision.Changed += new EventHandler (onComboBoxChanged_tipo_admision);

	combobox_tipo_admision2.Changed += new EventHandler (onComboBoxChanged_tipo_admision2);

// fin de llenado de los combobox
}
Imagen de Anónimo

un buen tuto en español

probadoo y funciona al 100

gracias

Enviar un comentario nuevo

  • Etiquetas HTML permitidas: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <pre>
  • Saltos automáticos de líneas y de párrafos.
Más información sobre opciones de formato

Captcha Image: you will need to recognize the text in it.
Igrese las letras que puede ver en la imagen superior