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 )

10 comentarios:

Anónimo dijo...

Excelente y muy útil.

Biel Maimó dijo...

Gracias Carlos, se agradecen los comentarios, y animan a seguir escribiendo mas entradas.

Anónimo dijo...

Gracias por el código, y sigue posteando que somos muchos los que te leemos.

Anónimo dijo...

Amigo muchas gracias por el codigo de verdad que si. Este genial. Pero te tengo un par de pregunticas. Sera que me puedes ayudar.

1-necesito refrescar los niveles de un treeview en tiempo de ejecucción. Sabes como lo puedo hacer?

Al mismo tiempo necesito saber como ejecutar una acción al hacer doble clic sobre un item del arbol?

De antemano gracias.

Biel Maimó dijo...

1.-
La manera de poder cambiar el contenido del treview, es cambiando los tTvItem deseados. Recuerda que el tree es un conedor de items.
Lo primero que necesitaras, es saber que item es el que quieres modificar.
Suponiendo que quieres cambiar el item actual, podrias hacerlo de la sieuiente manera.
oTree:bChanged := {|o,i| i:=o:GetSelected(),i:SetText('Nuevo caption')}

2.- Esto es más facil, lo que tienes que hacer es definir el codeblock bLDblClick, con lo que quieras que se ejecute al hacer doble click.
oTree:bLDblClick :={||MsgStop('Se ha pulsado doble click')}
Este data pertenece ha la clase tWindow, recuerda que siempre tienes disponibles los datas y metodos de las clase de donde hereda la que estas usando, en este caso tTreeView->tControl->tWindow.

Anónimo dijo...

Amigo muchas gracias como siempre por responder. Pero te hago otra preguntica?

Como hago para agregar un item nuevo?. Cuando agrego un registro a la base de datos en tiempo de ejecuccion?. Como lo manejas?

LEANDRO ALFONSO

Biel Maimó dijo...

Para añadir un nuevo item por debajo del item que tienes seleccionanado

oTree:GetSelected():Add(cPrompt, nImage, Cargo)

Para borrar, en la version que tengo yo de FW, no tiene para eliminar items individuales, solo tiene para borrar ramas, pero tienes un aporte de Carles Aubia ( http://fivetechsoft.com/forums/viewtopic.php?t=6235), que añadiendo un metodo a la clase tTvItem, permite eliminar items. Puede que las ultimas versiones este metodo ya este incluido, lo desconozco.

La forma de ejeuctarlos


oTree:GetSelected():Delete()
oTree:GetSelected():DeleteBranches()

Elias Abrão Júnior dijo...

Caro amigo, voce poderia mandar o codigo completo para o meu email

eajunior.fw@gmail.com

Anónimo dijo...

Ola, what's up amigos? :)
In first steps it is really good if someone supports you, so hope to meet friendly and helpful people here. Let me know if I can help you.
Thanks and good luck everyone! ;)

Anónimo dijo...

Hi, guantanamera121212