Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   OOP (https://www.clubdelphi.com/foros/forumdisplay.php?f=5)
-   -   Acceder al data de un treeview (https://www.clubdelphi.com/foros/showthread.php?t=79282)

lbidi 21-06-2012 18:03:39

Acceder al data de un treeview
 
Estimados todos.

He revisado varios hilos sobre este tema pero no he logrado hacer que funcione.

Tengo un query que lee de una base que tiene 2 campos, nivel y texto, es un catalogo de ropa
en la cual el nivel indicaria el nodo del arbol y texto , el contenido.

ej :

01 HOMBRES
0101 PANTALONES
010101 CUERO
02 MUJER
0201 VESTIDOS

etc,
etc

El codigo que tengo para leer esto es el siguiente.

Código Delphi [-]
var
    nodo0, nodo1, nodo2, nodo3, nodo4 : TTreeNode;
    n : Integer;

begin
    nodo0 := tv_Catalogo.Items.AddFirst( nil, 'ARTICULOS' );

    Qry_Cata.SQL.Clear;
    Qry_Cata.SQL.Add('Select * from Catalogo');
    Qry_Cata.SQL.Add('Order by Nivel');
    Qry_Cata.Open;
    while not Qry_Cata.Eof do
    begin
        n := Length( Qry_Cata.FieldByName('Nivel').AsString ) ) ;
        case n of
            2 :
            begin
                nodo1      := tv_Catalogo.Items.AddChild( nodo0, Qry_Cata['Texto'] );
                nodo1.Data := Pointer( Qry_Cata.FieldByName('Nivel').AsString);
                nodo1.MakeVisible;
            end;
            4 :
            begin
                nodo2      := tv_Catalogo.Items.AddChild( nodo1, Qry_Cata['Texto'] );
                nodo2.Data := Pointer( Qry_Cata.FieldByName('Nivel').AsString);
                nodo2.MakeVisible;
            end;
            6 :
            begin
                nodo3      := tv_Catalogo.Items.AddChild( nodo2, Qry_Cata['Texto'] );
                nodo3.Data := Pointer( Qry_Cata.FieldByName('Nivel').AsString);
                nodo3.MakeVisible;
            end;
            8 :
            begin
                nodo4      := tv_Catalogo.Items.AddChild( nodo3, Qry_Cata['Texto'] );
                nodo4.Data := Pointer( Qry_Cata.FieldByName('Nivel').AsString);
                nodo4.MakeVisible;
            end;
        end;
        Qry_Cata.Next;
    end;

Funciona bien y arma perfectamente el arbol.

Lo que necesito hacer luego es volver a grabar el arbol en la base de datos, por las modificaciones que pudo haber tenido.

Como hago para obtener el valor "nivel" almacenado en la propiedad data del nodo ?

Gracias.

Casimiro Noteví 21-06-2012 18:06:24

Una pequeña búsqueda, a ver si te sirve.

lbidi 21-06-2012 19:07:57

Gracias Casimiro.

Habia visto ya ese post, pero como vi que que en la solucion utiliza una clase definida por el usuario llamada "miclase" y no vi como estaba definida y al no conocer mucho sobre clases, es que decidi escribir la consulta.

Si alguien me puede guiar sobre como crear esa clase, seria de muchisima ayuda.

Mil gracias.

ecfisa 21-06-2012 20:23:28

Hola lbidi.

Cita:

Si alguien me puede guiar sobre como crear esa clase, seria de muchisima ayuda.
Revisa este mensaje

Pero en tu caso no es necesario crear una clase para acceder a el valor almacenado en la propiedad Data.

Ejemplo:
Código Delphi [-]
procedure TForm1.tvCatalogoClick(Sender: TObject);
var
  Nodo: TTreeNode;
begin
  Nodo:= tvCatalogo.Selected;
  if Assigned(Nodo) then
   ShowMessage(String(Nodo.Data)); // aquí se accede a Nivel
end;

Saludos.

lbidi 22-06-2012 14:12:59

Gracias ecfisa por responder. He tratado de hacer como tu indicas, pero no funciona como yo necesito.

Con el codigo que tu pusistes, el resultado que me devuelve es variable y no se porque.

A veces me devuelve el texto de la rama del arbol seleccionada y en otras veces, el texto de otra
rama, pero nunca el nivel que yo necesito.

Muchas gracias.

Seguiremos intentando.

Saludos

ecfisa 22-06-2012 18:47:11

Hola Ibidi.

Me pregunto si el campo Nivel no será numerico...

Proba de este modo:
Código Delphi [-]
...
begin
  nodo0:= tvCatalogo.Items.AddFirst(nil, 'ARTICULOS');
  while not Qry_Cata.Eof do
  begin
    case Length(Qry_Cata.FieldByName('Nivel').AsString) of
      2:begin
          nodo1:= tvCatalogo.Items.AddChild(nodo0, Qry_Cata.FieldByName('Texto').AsString);
          nodo1.Data:= Pointer(Qry_Cata.FieldByName('Nivel').AsInteger);
        end;
      4:begin
          nodo2:= tvCatalogo.Items.AddChild(nodo0, Qry_Cata.FieldByName('Texto').AsString);
          nodo2.Data:= Pointer(Qry_Cata.FieldByName('Nivel').AsInteger);
        end;

        ...

    end;
    Qry_Cata.Next;
  end;
  tvCatalogo.FullExpand;
end;
...

procedure TForm1.tvCatalogoClick(Sender: TObject);
var
  Nodo: TTreeNode;
begin
  Nodo:= tvCatalogo.Selected;
  if Assigned(Nodo) and (Nodo.Level > 0) then
    ShowMessage(IntToStr(Integer(Nodo.Data)));
end;

Saludos.

lbidi 26-06-2012 20:56:36

Hola, ecfisa.

Gracias por responder..

El campo NIVEL no es numerico. A proposito lo cree del tipo string para que su ordenacion me quedara
como quiero que quede el arbol.

Sigo probando..

Saludos y gracias otra vez.

Leonardo

ecfisa 27-06-2012 02:06:57

Hola Leonardo.

Código Delphi [-]
....
implementation

var
  Nivel: TStrings;

procedure TForm1.FormCreate(Sender: TObject);
var
  nodo0,nodo1,nodo2,nodo3,nodo4: TTreeNode;
  ix: Integer;
begin
  Nivel:= TStringList.Create;
  ix:=0;
  nodo0:= tvCatalogo.Items.AddFirst(nil, 'ARTICULOS');
  while not Qry_Cata.Eof do
  begin
    Nivel.Add(Qry_Cata.FieldByName('Nivel').AsString);
    case Length(Nivel[ix]) of
      2: nodo1:= tvCatalogo.Items.AddChildObject(nodo0,
            Qry_Cata.FieldByName('Texto').AsString, Pointer(Nivel[ix]));
      4: nodo2:= tvCatalogo.Items.AddChildObject(nodo0,
            Qry_Cata.FieldByName('Texto').AsString,Pointer(Nivel[ix]));
      6: nodo3:= tvCatalogo.Items.AddChildObject(nodo0,
            Qry_Cata.FieldByName('Texto').AsString,Pointer(Nivel[ix]));
      8: nodo4:= tvCatalogo.Items.AddChildObject(nodo0,
            Qry_Cata.FieldByName('Texto').AsString,Pointer(Nivel[ix]));
    end;
    Qry_Cata.Next;
    Inc(ix);
  end;
  tvCatalogo.FullExpand;
end;
procedure TForm1.tvCatalogoClick(Sender: TObject);
begin
  with tvCatalogo do
    if Assigned(Selected) and (Selected.Level > 0) then
       ShowMessage(string(Selected.Data));
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Nivel.Free;
end;

Saludos. :)

lbidi 28-06-2012 15:53:35

Muchisimas gracias ecfisa. Con el codigo que tu pusistes , funciona como lo necesitaba.

Ahora tengo que molestarte por una consulta mas, espero que sea la ultima de este post ;).

En el caso que el usuario necesite crear mas nodos y subnodos al arbol, como puedo hacer
para ir grabando el "nivel" dentro del nodo, para asi luego grabarlo en la bd.? Me explico?

si tengo creados 2 niveles.

01 - Hombres
02 - Mujeres

y el usuario me crea un nivel dentro de hombres, quedaria

01 - Hombres
0101 - Pantalones <-- como saber que numero asignarle a este nivel? y los sucesivos?
02 - Mujeres

Te agradezco nuevamente por tu invalorable aporte.

saludos

Leonardo

roman 28-06-2012 16:27:48

Cita:

Empezado por lbidi (Mensaje 436253)
En el caso que el usuario necesite crear mas nodos y subnodos al arbol, como puedo hacer
para ir grabando el "nivel" dentro del nodo, para asi luego grabarlo en la bd.? Me explico?

El nodo de un árbol tiene la propiedad Level que indica su nivel de profundidad en el árbol. Ese sería el nivel.

// Saludos

lbidi 28-06-2012 20:48:58

Hola roman, gracias por responder y perdon por mi ignorancia.

Es la primera vez que uso los treeview.

Ahora, siguiendo un poco mi problema, y viendo tu respuesta, como hapo para que los "niveles" o
levels de cada nodo que voy agregando me queden grabados en el nodo para luego volcarlos a la
bd ?

Necesito una rutina en la cual el usuario pueda hacer un "ABM" del arbol y volcarlo en la bd.

Mil gracias por tu colaboracion y por la existencia de este foro.

Saludos

ecfisa 29-06-2012 20:29:52

Cita:

Empezado por lbidi (Mensaje 436253)
En el caso que el usuario necesite crear mas nodos y subnodos al arbol, como puedo hacer
para ir grabando el "nivel" dentro del nodo, para asi luego grabarlo en la bd.? Me explico?

si tengo creados 2 niveles.

01 - Hombres
02 - Mujeres

y el usuario me crea un nivel dentro de hombres, quedaria

01 - Hombres
0101 - Pantalones <-- como saber que numero asignarle a este nivel? y los sucesivos?
02 - Mujeres

Hola Ibidi.

Bueno, en ese caso usando TStrings nos quedamos cortos...

Fijate si te sirve este ejemplo:
Código Delphi [-]
uses Contnrs;

type
  TClase = class(TObject)
   Nivel: string;
   Texto: string;
   Level: string;
  end;

var
 ObjLst: TObjectList;
 Clase: TClase;

procedure TForm1.FormCreate(Sender: TObject);
var
  nodo0,nodo1,nodo2,nodo3,nodo4: TTreeNode;
begin
  ObjLst:= TObjectList.Create;
  nodo0:= tvCatalogo.Items.AddFirst(nil, 'ARTICULOS');
  while not Qry_Cata.Eof do
  begin
    Clase:= TClase.Create;
    ObjLst.Add(Clase);
    Clase.Nivel:= Qry_Cata.FieldByName('Nivel').AsString;
    Clase.Texto:= Qry_Cata.FieldByName('Texto').AsString;
    Clase.Level:= '01';  { Aca iría el nivel a asignar }
    case Length(Clase.Nivel) of
      2: nodo1:= tvCatalogo.Items.AddChildObject(nodo0,Clase.Texto,Clase);
      4: nodo2:= tvCatalogo.Items.AddChildObject(nodo0,Clase.Texto,Clase);
      6: nodo3:= tvCatalogo.Items.AddChildObject(nodo0,Clase.Texto,Clase);
      8: nodo4:= tvCatalogo.Items.AddChildObject(nodo0,Clase.Texto,Clase);
    end;
    Qry_Cata.Next;
  end;
  tvCatalogo.FullExpand;
end;

procedure TForm1.btnAddNodeClick(Sender: TObject);
var
  nodo: TTreeNode;
begin
  Clase:= TClase.Create;
  ObjLst.Add(Clase);
  Clase.Nivel:= 'Nuevo valor nivel';
  Clase.Texto:= 'Nuevo valor texto';
  { Concatenar niveles ( 010203... ) }
  with tvCatalogo do
  begin
    Clase.Level:= TClase(Selected.Data).Level +
     StringOfChar('0', 2-Length(IntToStr(Selected.Level+1))) +
     IntToStr(Selected.Level+1);
    nodo:= Items.AddChildObject(Selected,Clase.Texto,Clase)
  end;
end;

procedure TForm1.tvCatalogoClick(Sender: TObject);
begin
   with tvCatalogo do
    if Assigned(Selected) and (Selected.Level > 0) then
      with TClase(Selected.Data) do
       Caption:=Format('Nivel: %s ~ Texto: %s ~ Level: %s',[Nivel,Texto,Level]);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
   ObjLst.Free;
end;

Saludos.

lbidi 04-07-2012 17:03:57

Muchas gracias ecfisa por tu pronta respuesta y tu colaboracion.

He probado con tu nuevo codigo , asignandole una clase pero me da un error de memoria cuando creo un nuevo nodo.

En esta parte del codigo

Código Delphi [-]
procedure TForm1.btnAddNodeClick(Sender: TObject);
var
  nodo: TTreeNode;
begin
  Clase:= TClase.Create;
  ObjLst.Add(Clase);
  Clase.Nivel:= 'Nuevo valor nivel';
  Clase.Texto:= 'Nuevo valor texto';
  { Concatenar niveles ( 010203... ) }
  with tvCatalogo do
  begin
    Clase.Level:= TClase(Selected.Data).Level +
     StringOfChar('0', 2-Length(IntToStr(Selected.Level+1))) +
     IntToStr(Selected.Level+1);   <---------- aqui me salta cuando lo ejecuto, no al compilar.
    nodo:= Items.AddChildObject(Selected,Clase.Texto,Clase)
  end;
end;

Es un error tipo "acceso de violacion....", no puedo ( a menos yo :( ), porque se genera.

Nuevamente mil gracias por tu ayuda.

Saludos.

ecfisa 04-07-2012 18:42:24

Hola Ibidi.

No sé que pueda estar pasando ya que no he recibido nunca esa excepción.

El código de prueba original lo hice sobre Firebird, pero dado lo complicado que sería pasarte la tabla en esa BD, pasé el código a BDE. De ese modo puedo ponerte la tabla junto al código de prueba y a efectos de ejemplificar, servirá igualmente. (disculpa si el manejo de BDE es muy tosco pero no lo uso habitualmente)

Revisalo a ver si comparando el código y la estructura de la tabla podes encontrar el por qué de la excepción.

Saludos. :)

lbidi 05-07-2012 22:56:59

1 Archivos Adjunto(s)
Hola ecfisa, gracias por el codigo. Modifique parte de mi programa con el tuyo, pero sigo sin poder obtener el resultado deseado.

Como podras ver en la imagen que adjunto ( si lo hago bien ), cuando agrego un nodo nuevo al nodo inicial el "nivel" no queda bien. Mi idea es que cada rama siga una numeracion correlativa, y asi dentro de cada rama, para luego volcarla a una bd. Tiene que ser algo dinamico en la cual el usuario pueda crear y modificar nuevas categorias dentro de este catalogo.

Ej:
00 - ARTICULOS
0001 - HOMBRES
000101 - Camisas
000102 - Pantalones
0002 - MUJERES
000201 - Vestidos
0003 - NIÑOS

Cuando agrego nodos nuevos con tu codigo , los "niveles" no quedan correlativos, y no encuentro el "bendito" error !! :eek::eek::eek:

Tengo que grabarlos de esta manera, para que la proxima vez que lea la tabla, me arme el arbol de la misma manera que lo tenia previamente, no se si me explico correctamente.

Saludos y mil gracias por tu colaboracion.

ecfisa 05-07-2012 23:18:13

Hola.

Creo entenderte... probá haciendo:
Código Delphi [-]
procedure TForm1.btnAddNodeClick(Sender: TObject);
var
  nodo: TTreeNode;
begin
  Clase:= TClase.Create;
  ObjLst.Add(Clase);
  Clase.Nivel:= 'Nuevo nivel';
  Clase.Texto:= 'Nuevo texto';
  with tvCatalogo do
  begin
    Clase.Level:= TClase(Selected.Data).Level +
     StringOfChar('0', 2-Length(IntToStr(Selected.Level+1))) + 
       IntToStr(Selected.Count + 1);  
   nodo:= Items.AddChildObject(Selected,Clase.Texto,Clase)
  end;
end;
La propiedad Count de TTreeNode contiene la cantidad de nodos hijos que contiene un TreeNode determinado.

Saludos.

lbidi 06-07-2012 20:17:11

Estimado ecfisa.. Muchisimas gracias por tu codigo y molestia.

Ahora si funciona como pretendia. De lujo.

Con esta ultima pregunta, espero ya terminar este post :).

Siguiendo tu codigo, como puedo hacer ahora para recorrer todo el arbol y sus ramas, para guardarlas en una bd ? He tratado viendo algunos posts de este foro, pero no me recorre todo el arbol.

He hecho un for recorriendo todo el arbol, pero me quedan dudas si debo utilizar esa clase o ir creando
nodos para obtener el valor del text y del level que son los que debo grabar.

Gracias nuevamente por tu invalorable ayuda.

Saludos.

lbidi 09-07-2012 22:59:10

Hola foristas.

Alguien me podria ayudar con el ultimo post que he puesto ?
Necesito grabar el arbol en una bd con los datos de la clase pero no se como recorrerlo.

Muchas gracias.

Saludos

ecfisa 10-07-2012 00:09:14

Hola Ibidi.

Son muchas las formas en que podes desear guardar esos nodos...

De todos modos te pongo un ejemplo (muy simple) que añade secuencialmente los nodos en un TDataSet:
Código Delphi [-]
procedure TForm1.btAddToDataSetClick(Sender: TObject);
var
  i: Integer;
begin
  TargetDataSet.Open;
  tvCatalogo.Items.GetFirstNode;
  for i := 1 to tvCatalogo.Items.Count - 1 do
  begin
    TargetDataSet.Append;
    with TClase(tvCatalogo.Items[i].Data) do
    begin
      TargetDataSet.FieldByName('Nivel').AsString:= Nivel;
      TargetDataSet.FieldByName('Texto').AsString:= Texto;
      ...
    end;
    TargetDataSet.Next;
  end;
  TargetDataSet.Close;
end;
Espero que al menos sirva como para orientarte un poco.

Saludos.

lbidi 11-07-2012 16:44:41

Muchas gracias , ecfisa..

Anduvo de maravillas.

Saludos cordiales..

Leo


La franja horaria es GMT +2. Ahora son las 03:03:00.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi