jueves, 17 de enero de 2008

TreeView con xBrowse

Aunque muchas aplicaciones usan la visualizacion tipo arbol, la verdad es que hasta la fecha nunca lo habia usado en mis programas.
Esta vez tenia muy claro el resultado que queria obtener, pero ni idea de como llegar hasta el.
Queria visualizar un plan de cuentas, con una estructra arbolada a la izquierda y una rejilla con las cuentas a la derecha.
Tree plan de cuentas

Este es el resultado final, y es justo como deseaba que quedase ;-).
La tabla cta esta formada por los siguientes atributos:
CTA Caracter 8
NOM Caracter 45
Image Hosted by ImageShack.us
Y los registros están grabados tal cual se ve en la imagen superior.

Para conseguir nuestro proposito usaremos un splitter vertical, colocando un objeto TreeView a la izquierda y un xBrowse a la derecha.
Creamos el objeto oTree del tipo TreeView
oTree:=TTreeView():New(0,0,oWnd,,,,,300)
y lo procedmos a rellenearlo con los datos que deseamos, para ello llamos a la función AddMayor, pasandole como parametro el propio objeto oTree, y un array vacio(paso el array desde esta funcion para poder darle algun tipo de uso futuro, ahora mismo no lo uso para nada, y podriamos prescindir de pasar el arraym y crearlo como una variable local en la función AddMayor).
Image Hosted by ImageShack.us

En esta función uso un indice condicional 'mayor', que solo contiene las cuentas de mayor y no las subcuentas.
Lo que hago es recorrer todo el fichero, e ir agregando nodos al objeto oTree, la forma de agregar varia si estamos en el nodo raiz, o añadimos a uno ya existente.
Si la longitud del contenido del campo cta es 1, estamos en el nodo raiz, añadimos el elemento con el metodo Add del objeto oTree, que devuelve otro objeto del tipo tvItem.
oTree:Add(AllTrim(Cta->Cta)+' '+Cta->Nom)
Mientras que si no estamos en el nodo raiz(long. cta>1), lo que hacemos es utilizar el metodo Add, pero del objeto tvItem correspondiente.
Buscamos en el array el item que corresponde al valor de cta actaul menos una posicion, y si le añadimos el nuevo elemento con la siguiente instrucción.
aItems[nPos,2]:Add(AllTrim(Cta->Cta)+' '+Cta->Nom,,AllTrim(Cta->Cta))

A medida que voy creando los nodos, guardo el objeto tvItem y el valor de Cta en un array. Este array lo utilizo para posicionarme en el nodo correcto mediante la funcion Ascan.

Si os fijais en cada elemento de cada nodo del objeto tree es un objeto tvItem, el objeto tvItem dispone de un data llamado cargo (presente en muchos otros objetos) que esta diseñado para guardar cualquier dato que quiera el programador, en nuestro caso, grabamos el valor del campo Cta, y nos va a servir para hacer un Scope en el browse, a medida que nos vayamos desplazando por el arbol.
Para conseguirlo usamos el data bChanged, en el cual colocamos un codeblock que sera evaluado cada vez que haya un cambio en el objeto oTree,


CodeBlock bChanged
Este CodeBlock, recupera el elemento seleccionado del oTree, comprueba que no este vacio el Data Cargo, aplica el scope a la tabla, reposiciona y refresca el objeto browse.

El resto de trabajo que nos queda es definer el browse y el spliter, que supongo que todos ya sabreis perfectamente como hacerlo.

Image Hosted by ImageShack.us
Es importante el data nLeft del objeto browse para que quede a la derecha del splitter, y el codeblock bResized de la ventana, para que se reajuste el splitter si cambia el tamaño de la venana.

Espero que os haya gustado la lectura, y os pueda ser de utilidad, todos los comentarios son bienvenidos.

(tTreeView tVItem tXBrowse oTree:bChanged SetRDD )