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 PartidoComarcaMunicipioCodigo 
  FROM Dl01 
 WHERE CodPrv 
= (SELECT Literal FROM Instalacion WHERE Etiqueta 'Provincia'
 
ORDER BY 123

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->EoffMenu->Query->Next())      for (nItem 0nItem 3nItem ++)
          if (
Nodo[nItem] == NULL || Nodo[nItem]->Text != fMenu->Query->Fields->FieldByNumber(nItem 1)->AsString)
               switch (
nItem)
               {
                    case 
0:
                         
LisMun->Items->Add(NULLfMenu->Query->Fields->FieldByNumber(1)->AsString);
                         
Nodo[0] = LisMun->Items->Item[LisMun->Items->Count 1];
                         break;
                    case 
1:
                         if (
nIndex == 1)
                              
LisMun->Items->Add(NULLfMenu->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(NULLfMenu->Query->Fields->FieldByNumber(3)->AsStringnewNodo);
                         else
                              
LisMun->Items->AddChildObject(Nodo[nItem 1], fMenu->Query->Fields->FieldByNumber(3)->AsStringnewNodo);
                         
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(NULLIBQuery1->FieldByName("PARTIDO")->AsString);

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

    
TreeView1->Items->AddChild(nd2IBQuery1->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 17:03:30.

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