Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Cargar un TTreeView (https://www.clubdelphi.com/foros/showthread.php?t=93213)

Angel.Matilla 18-06-2018 18:14:02

Cargar un TTreeView
 
Me estoy volviendo un poco loco para cargar un TTreView. El objeto en concreto ya lo conocéis de otro hilo; es este:


para ello uso este query:
Código PHP:

SELECT DISTINCT Partido, Comarca, Municipio, Codigo 
  FROM Dl01 
 WHERE CodPrv 
= (SELECT Literal FROM Instalacion WHERE Etiqueta = 'Provincia') 
 
ORDER BY 1, 2, 3, 4 

que me da este resultado:

El orden del árbol, como se ve en la imagen es Partido > Comarca > Municipio.

Y digo que me estoy volviendo un poco loco porque todavía no he dado en como hace la carga del Tree sin tener que ejecutra tres querys distintos o meter un montón de código, como tengo ahora, con condiciones y variables auxiliares.

Por otra parte me está ocurriendo algo que me está dejando perplejo. Ahora cargo el Tree con este bucle a partir de ese query anterior:
Código PHP:

tNodo newNodo = new TMyRec;
for (; !
fMenu->Query->Eof; fMenu->Query->Next())      for (nItem = 0; nItem < 3; nItem ++)
          if (
Nodo[nItem] == NULL || Nodo[nItem]->Text != fMenu->Query->Fields->FieldByNumber(nItem + 1)->AsString)
               switch (
nItem)
               {
                    case 
0:
                         
LisMun->Items->Add(NULL, fMenu->Query->Fields->FieldByNumber(1)->AsString);
                         
Nodo[0] = LisMun->Items->Item[LisMun->Items->Count - 1];
                         break;
                    case 
1:
                         if (
nIndex == 1)
                              
LisMun->Items->Add(NULL, fMenu->Query->Fields->FieldByNumber(2)->AsString);
                         else
                              
LisMun->Items->AddChild(Nodo[nItem - 1], fMenu->Query->Fields->FieldByNumber(2)->AsString);
                         
Nodo[1] = LisMun->Items->Item[LisMun->Items->Count - 1];
                         break;
                    case 
2:
                         
newNodo         = new TMyRec;
                         
newNodo->Codigo = fMenu->Query->Fields->FieldByNumber(4)->AsInteger;
                         if (
nIndex == 2)
                              
LisMun->Items->AddObject(NULL, fMenu->Query->Fields->FieldByNumber(3)->AsString, newNodo);
                         else
                              
LisMun->Items->AddChildObject(Nodo[nItem - 1], fMenu->Query->Fields->FieldByNumber(3)->AsString, newNodo);
                         
Nodo[2] = LisMun->Items->Item[LisMun->Items->Count - 1];
                         break;
                } 

Ese newNodo es una estructura que está declarada así:
Código PHP:

typedef struct MyRec
{
     
int Codigo;

} 
TMyRec;
typedef TMyRec *tNodo; 

Sé que es un código complejo, pero no se me ocurrió otra manera más sencilla (y de ahí mi pregunta anterior). El probelma viene con la última entrada del TreeView: cuando voy a rescatar el valor de ese código me devuelve SIEMPRE cero por lo que luego no encuentra los datos asociados a ese nodo y me ocurre SÓLO con el último elemento del arbol.

Angel.Matilla 18-06-2018 19:01:42

Me está ocurriendo, además, otra cosa. Cuando cargo el TreeView (por ejemplo el primer registro del query) el valor que se asigna en ese newNodo->Codigo = fMenu->Query->Fields->FieldByNumber(4)->AsInteger es correcto (en ese caso es 1217). Sin embargo cuando voy a rescatarlo con esto:
Código PHP:

fMenu->Auxiliar->Close();
fMenu->Auxiliar->SQL->Text = "SELECT Municipio, Comarca, Partido, Actualiza, Concejales, Partido_alcalde, Constitucion, TlfSede, Sede, Observaciones FROM Dl01 WHERE CodPrv = (SELECT Literal FROM Instalacion WHERE Etiqueta = 'Provincia') AND Codigo = :Codigo";
fMenu->Auxiliar->ParamByName("Codigo")->AsInteger = tNodo(Node->Data)->Codigo;
fMenu->Auxiliar->Open(); 

siendo ese tNodo lo mismo que en el anterior código, me devuelve valores rarísimos como 17550088 o más raros.

bucanero 18-06-2018 19:19:31

No es mi fuerte el C++. Pero con una estructura similar a esta de delphi debe de funcionarte

Código Delphi [-]
var
  nodo1, nodo2, nodo3:TTreeNode;
begin
  Query.First;
  while not Query.eof do begin
    nodo1 := LisMun.Items.AddChild(Nil, Query.fieldByName('a').AsString);
    repeat
      nodo2 := LisMun.Items.AddChild(nodo1, Query.fieldByName('b').AsString);
      repeat
        nodo3 := LisMun.Items.AddChild(nodo2, Query.fieldByName('c').AsString);
        Query.Next;
      until Query.eof or (nodo2.Text <> Query.fieldByName('b').AsString);
    until Query.eof or (nodo1.Text <> Query.fieldByName('a').AsString);
  end;
end;

Angel.Matilla 18-06-2018 19:26:24

Gracias por la sugerencia bucanero. Entiendo el sentido del código que me pones en Delphi, pero me pierdo al pasarlo a Builder. Supongo que la instrucción repeat será el equivalente al Next() de Builder, para que avance al siguiente registro de la tabla o query. Pero si es así hay algo en el código que no me cuadra: Si después de asignar cada nivel del TreeView avanzas un registro dejo sin leer parte de cada fila del query. O estoy interpretando mal la idea.

ecfisa 18-06-2018 21:42:15

Hola.

El resultado que buscas ¿ es algo así ? :



Saludos :)

ecfisa 18-06-2018 22:34:25

Hola.

¡ Donde tengo la cabeza ! olvidé el código del ejemplo :o

Código PHP:

...
void __fastcall TForm1::LoadTreeView(void)
{
  
TTreeNode *nd1, *nd2;
  
AnsiString par("");
  
AnsiString com("");

  while (!
IBQuery1->Eof)
  {
    if (
par != IBQuery1->FieldByName("PARTIDO")->AsString)
      
nd1 = TreeView1->Items->Add(NULL, IBQuery1->FieldByName("PARTIDO")->AsString);

    if (
com != IBQuery1->FieldByName("COMARCA")->AsString)
      
nd2 = TreeView1->Items->AddChild(nd1, IBQuery1->FieldByName("COMARCA")->AsString);

    
TreeView1->Items->AddChild(nd2, IBQuery1->FieldByName("MUNICIPIO")->AsString);

    
com = IBQuery1->FieldByName("COMARCA")->AsString;
    
par = IBQuery1->FieldByName("PARTIDO")->AsString;

    
IBQuery1->Next();
  }

  
TreeView1->FullExpand();
}

void __fastcall TForm1::FormCreate(TObject *Sender)
{
  
IBQuery1->Close();
  
IBQuery1->SQL->Clear();
  
IBQuery1->SQL->Add("SELECT DISTINCT PARTIDO, COMARCA, MUNICIPIO, CODIGO");
  
IBQuery1->SQL->Add("FROM Dl01 ORDER BY PARTIDO, COMARCA, MUNICIPIO, CODIGO");
  
IBQuery1->Open();
  
LoadTreeView();
} 

(Omití la condición de la cláusula WHERE de la sentencia SQL para simplificar el ejemplo)

Saludos :)

bucanero 19-06-2018 10:00:53

Cita:

Empezado por Angel.Matilla (Mensaje 527157)
Gracias por la sugerencia bucanero. Entiendo el sentido del código que me pones en Delphi, pero me pierdo al pasarlo a Builder. Supongo que la instrucción repeat será el equivalente al Next() de Builder, para que avance al siguiente registro de la tabla o query. Pero si es así hay algo en el código que no me cuadra: Si después de asignar cada nivel del TreeView avanzas un registro dejo sin leer parte de cada fila del query. O estoy interpretando mal la idea.

La instrucción repeat es similar al while con la evaluación de la condición al final del bucle, he traducido mi código al similar en C++ con tus nombres de campos y variables:

Código:

  Query->First();
  while ( !fMenu->Query->Eof ) {
    //inserta el nodo del primer campo
    Nodo[0] = LisMun->Items->Add(Nil, fMenu->Query->Fields->FieldByNumber(1)->AsString);
    do {
      //inserta el nodo del segundo campo       
      Nodo[1] = LisMun->Items->Add(Nodo[0], fMenu->Query->Fields->FieldByNumber(2)->AsString);
      do {
        //inserta el nodo del tercer campo                 
        newNodo = new TMyRec;
        newNodo->Codigo = fMenu->Query->Fields->FieldByNumber(4)->AsInteger;         
        Nodo[2] = LisMun->Items->AddChildObject(Nodo[1], fMenu->Query->Fields->FieldByNumber(3)->AsString, newNodo);
        // avanza en la consulta
        fMenu->Query->Next();

        // repite el bucle hasta final de la consulta o
        // hasta que cambie el segundo campo de la tabla
      } while ( !fMenu->Query->Eof &&
                    (Nodo[2]->Text == fMenu->Query->Fields->FieldByNumber(2)->AsString));
      // repite el bucle hasta final de la consulta o
      // hasta que cambie el primer campo de la tabla         
    } while ( !fMenu->Query->Eof &&
                (Nodo[1]->Text == fMenu->Query->Fields->FieldByNumber(1)->AsString));
  }

el código funciona siempre que la consulta SQL este ordenada pro PARTIDO, COMARCA y MUNICIPIO.

Angel.Matilla 19-06-2018 10:16:24

Gracias a los dos por vuestras sugrencias. Voy a probarlas ahora mismo.

Angel.Matilla 19-06-2018 10:45:17

Cita:

Empezado por ecfisa (Mensaje 527162)
¡ Donde tengo la cabeza ! olvidé el código del ejemplo :o

Funciona perfecto. Además, y no sé por qué, el problema que tenía al rescatar el valor del objeto asociado al nodo se ha resuelto el solito. Maravillas de la informática.
Cita:

Empezado por bucanero (Mensaje 527166)
La instrucción repeat es similar al while con la evaluación de la condición al final del bucle, he traducido mi código al similar en C++ con tus nombres de campos y variables

Gracias por el esfuerzo. Dándole vueltas anoche en casa llegue a una conclusión similar a la tuya, pero el código de ecfisa es mucho más sencillo.


La franja horaria es GMT +2. Ahora son las 05:11:06.

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