Field Field Name Type Width Dec Index Collate Nulls 1 NOMBRE Character 30 No 2 CARGO Character 30 No 3 ID Integer 4 Asc Machine No 4 REPORTA Integer 4 Asc Machine NoY hazle un append from ... delimited con estos datos:
"Juan Fernández","Vendedor",20,17 "Laura Trelles","Vendedor",19,17 "Máximo Carelli","Vendedor",18,17 "Héctor Chiozza","Jefe de Ventas",17,14 "Mabel Arias","Mercadotecnia",16,14 "Anibal Lázaro","Promociones",15,14 "Cecilia Faioli","Gerente de Ventas",14,3 "Ramona Barrales","Jefa de depósito",13,21 "Pedro Echeveste","Encargado de depósito",12,13 "Armando Castro","Encargado de depósito",11,13 "Berta Serrano","Control de Despacho",10,21 "Jorge Larralde","Auditor Contable",9,5 "Marta Fernández","Auxiliar contable",8,9 "Rita Jordán","Auxiliar contable",7,9 "Mario Loureiro","Facturista",6,5 "Federico Reitman","Gerente Administrativo",5,3 "Flavia González","Gerente Financiera",4,3 "Ramiro Lagrán","Control Financiero",6,4 "Rosario Montoya","Directora Administrativa",3,1 "Mauro Cardoso","Director de Operaciones",2,1 "Carlos Cruz","Gerente General",1,0 "Claudia Maqueda","Gerente de Logística",21,2Esto no es más que un pequeño organigrama que usaremos de muestra. Contiene el nombre de cada persona en una empresa, su cargo, un id, y el id de la persona a quien reporta (su jefe).
PROCEDURE Load USE arbol Order reporta * El cursor Tabla es una copia de la tabla, pero ordenada * jerárquicamente y con campos adicionales Create Cursor Tabla ( ; signo C( 1), ; nombre C(30), ; cargo C(30), ; id I, ; reporta I, ; cadena C(250), ; visible L ) ENDPROC PROCEDURE Init Select Arbol Locate for Empty( reporta ) && Busca al nodo principal (no tiene jefe) thisform.CargaArbol( id, 0, ";" ) && Método recursivo que carga el árbol Select Tabla && Se ubica en el primer registro locate ENDPROC PROCEDURE cargaarbol * ID del nodo, nivel de profundidad, cadena de jerarquía lParameters tnID, tnNivel, tcCadena Local lnRegistro Select Arbol Scatter memvar && Copia los datos m.nombre = Replicate( "·", 3 * tnNivel ) + m.nombre && indenta el nombre según el nivel m.cadena = tcCadena m.visible = .t. && Inicia mostrando todo el árbol Insert into Tabla from memvar if Seek( tnID ) && Si tiene subordinados replace in Tabla signo with "-" && Indica que lo tiene Scan while reporta = tnID && Recorre los subordinados lnRegistro = Recno() && Guarda el registro para poder continuar reocrriendo * Entra en el siguiente nivel de recursión para agregar al subordinado * El último parámetro es una cadena que contiene el "árbol genealógico" de cada nodo * ATENCION: Esto implica que hay un límite en el nivel de profundidad a manejar thisform.CargaArbol( Arbol.Id, tnNivel + 1, tcCadena + Transform(reporta) +";" ) Go lnRegistro && Como en la recursión puede haberse movido, vuelve a donde estaba EndScan endif ENDPROC PROCEDURE expande * Esto es llamado solamente al hacer doble click en un + ó un - en la grilla Lparameters tnID, tcSigno If !Empty( signo ) && Si no hay + ni - no hace nada Set filter to && Quita todo el filtro * Marca como visible (si había un +) o invisible (si había un -) * a todos los subordinados (a todo nivel) del nodo indicado replace all visible with (tcSigno = "+") for ";"+ Transform( tnID ) +";" $ cadena Set Filter To visible && Vuelve a filtrar los no visibles Locate for id = tnID && Regresa al registro del click replace signo with Iif( tcSigno = "+", "-", "+" ) && Cambia el signo EndIf thisform.Refresh() && Refresca el formulario, así vemos lo que pasó finalmente ENDPROCDoubleClick del textbox de la primer columna:
* Solamente llama al método del formulario * No, poner todo es código aquí sería una salvajada. * En un evento no debe haber más de dos o tres líneas thisform.expande( Tabla.id, Tabla.signo )¿Se entiende lo que hago?