Gtk+: trabajando con TreeViews

edicion-treeview1

Este post puede ser útil para los que utilicen el widget TreeView de Gtk+ (no importa el lenguaje mientras haya bindings), y necesiten activar por código celdas en modo edición. Hay algunas cuestiones a tener en cuenta.

Para el Proyecto Final de Carrera estamos desarrollando un sistema de nivel operativo, con funciones de facturación y demás. Necesitamos manejar un TreeView con campos editables, y al finalizar la edición de uno de ellos es necesario dar el foco a otro campo en modo edición, listo para que el usuario comience a cargar datos sin tocar el mouse.


Lo primero que hicimos fue conectar un método al evento Edited del CellRendererText de la columna correspondiente. De esta forma, cuando terminamos la edición en el primer campo, podemos colocar allí el código correspondiente para actualizar el modelo del TreeView y otras operaciones más, entre ellas (la que nos interesa) dar el foco al segundo campo en modo edición. La parte final de este método (el evento se activa al finalizar la edición) había quedado así:

/* ... */

this.tvItems.SetCursor(path,
					   this.tvcCodigoProducto,
					   true);

Hay que tener cuidado al utilizar la función SetCursor. En algunos casos, si no la usamos cuidadosamente, el TreeView no se comportará en forma correcta. Esos casos son por ejemplo cuando el usuario, al estar editando el campo, hace click en otra fila. Esto hace que se dispare el evento Edited, y por lo tanto se activa el modo edición en el segundo campo (SetCursor), pero el foco lo tiene otra fila, y esto hace que el funcionamiento sea incorrecto.

La solución es, antes de ejecutar SetCursor, verificar qué tipo de evento ha ocurrido. En nuestro caso, ejecutamos dicha función sólo si se ha oprimido la tecla Return. El código queda así:

/* Una vez editada la cantidad, automáticamente
 * pasamos el foco al campo de 'código' en modo
 * edición, pero en una nueva fila. A esto lo hacemos
 * únicamente si el usuario presionó la tecla Enter */

Gdk.Event ev = Gtk.Application.CurrentEvent;

if (ev.Type == Gdk.EventType.KeyPress) {
	Gdk.EventKey evKey = (Gdk.EventKey)ev;
	
	if (evKey.Key == Gdk.Key.Return)
		this.tvItems.SetCursor(path,
							   this.tvcCodigoProducto,
							   true);
}

Lo cual es más lógico también: si se hace click en otra fila, seguramente es porque se quiere editar otro ítem y por lo tanto no es correcto forzar el foco en otro lugar. Además, como se dijo, esto hacía que el TreeView quede en un estado inconsistente.