Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Borrado y creación dinámica de elementos (https://www.clubdelphi.com/foros/showthread.php?t=95670)

Angel.Matilla 29-04-2022 18:53:15

Borrado y creación dinámica de elementos
 
A lo mejor me estoy complicando la vida innecesariamente; no lo sé.
Tengo esta pantalla:


En función de la opción pulsada (salvo la segunda) monto estas otras:

Con este código:
Código:

AnsiString cEspecial[3] = {"Cargos electos afiliados", "Cualquier cargo electo", "Afiliados activos"};
TCheckListBox *CheckListBox;
TControl *Control;
TLabeledEdit *Edit;
TRadioButton *Button = static_cast<TRadioButton *>(Sender);
TRadioButton *Radio;
TStaticText *Static;

Panel2->Visible = false;
for (nItem = 0; nItem < Panel2->ControlCount; nItem ++)
{
    Control = Panel2->Controls[nItem];
    if (Control->ClassNameIs("TCheckListBox") || Control->ClassNameIs("TStaticText") || Control->ClassNameIs("TLabeledEdit") || Control->ClassNameIs("TRadioButton"))
          delete Control;
}
Panel2->Refresh();

fMenu->Auxiliar->Close();
switch (Button->Tag)
{
    case 0:
          fMenu->Auxiliar->SQL->Text = "SELECT DISTINCT Periodo, PerPago, MAX(Fecha) FROM Rc03 WHERE CodPrv = :PrvIns AND UPPER(Forma) NOT LIKE :Literal AND UPPER(Periodo) NOT LIKE :Literal GROUP BY Periodo, PerPago ORDER BY Periodo";
          fMenu->Auxiliar->ParamByName("PrvIns")->AsString  = PrvIns;
          fMenu->Auxiliar->ParamByName("Literal")->AsString = cDesconocido;
          fMenu->Auxiliar->Open();

          if (fMenu->Auxiliar->IsEmpty())
          {
              Mensaje(4, "No hay recibos de este tipo pendientes de facturar.", "Volver");
              return;
          }

          Label2->Caption = "Seleccione periodicidades";
          CheckListBox = new TCheckListBox(Panel2);
          CheckListBox->Align        = alClient;
          CheckListBox->BorderStyle  = bsNone;
          CheckListBox->Color        = Panel2->Color;
          CheckListBox->Name        = "CheckListBox1";
          CheckListBox->Parent      = Panel2;
          CheckListBox->OnClickCheck = CheckListBox1ClickCheck;

          for (; !fMenu->Auxiliar->Eof; fMenu->Auxiliar->Next())
              CheckListBox->Items->AddObject(fMenu->Auxiliar->FieldByName("Periodo")->AsString, (TObject *)fMenu->Auxiliar->FieldByName("PerPago")->AsInteger);
          break;
    case 1:
          [Esta opción no tiene pantalla especial. Por eso quito el código]
          return;
    case 2:
          fMenu->Auxiliar->Close();
          fMenu->Auxiliar->SQL->Text = "SELECT MIN(A.Fecha) MinFec, MAX(A.Fecha) MaxFec FROM Recibos A, Persona B WHERE A.CodPrv = :PrvIns AND A.Situacion IN (SELECT Valor FROM Instalacion WHERE Etiqueta = 'SitRec' AND Situacion = 1) AND A.Fecha <> :FechaNula AND A.CodPrv = B.CodPrv AND A.Codigo = B.Codigo AND B.Situacion IN (SELECT Valor FROM Instalacion WHERE Etiqueta = 'Situacion' AND Situacion = 1)";
          fMenu->Auxiliar->ParamByName("PrvIns")->AsString      = PrvIns;
          fMenu->Auxiliar->ParamByName("FechaNula")->AsDateTime = dFechaNula;
          fMenu->Auxiliar->Open();

          if (fMenu->Auxiliar->IsEmpty())
          {
              Mensaje(4, "No hay recibos devueltos.", "Volver");
              return;
          }
          dMaxFec = fMenu->Auxiliar->FieldByName("MaxFec")->AsDateTime;
          dMinFec = fMenu->Auxiliar->FieldByName("MinFec")->AsDateTime;

          Label2->Caption = "Indique el rango de fechas";
          Static = new TStaticText(Panel2);
          Static->Align      = alBottom;
          Static->Caption    = dMinFec.FormatString("'Del 'dd/mm/yyyy") + dMaxFec.FormatString("' al 'dd/mm/yyyy");
          Static->Font->Style = TFontStyles() << fsBold;
          Static->Parent      = Panel2;
          Static->Align      = alTop;

          for (nItem = 0; nItem < 2; nItem ++)
          {
              Edit = new TLabeledEdit(Panel2);
              Edit->BevelKind              = bkFlat;
              Edit->BorderStyle            = bsNone;
              Edit->EditLabel->Caption    = nItem == 0 ? (String)"Desde" : (String)"Hasta";
              Edit->EditLabel->Font->Style = TFontStyles() << fsBold;
              Edit->LabelPosition          = lpAbove;
              Edit->Left                  = 15 + 80 * nItem;
              Edit->Parent                = Panel2;
              Edit->Text                  = "";
              Edit->Top                    = 55;
              Edit->Width                  = 75;
              Edit->OnExit                = Edit1Exit;
          }
          break;
    case 3:
          Label2->Caption = "Emitir recibos para";
          for (nItem = 0; nItem < 3; nItem ++)
          {
              Radio = new TRadioButton(Panel2);
              Radio->Caption = cEspecial[nItem];
              Radio->Left    = 2;
              Radio->Parent  = Panel2;
              Radio->Tag    = nItem;
              Radio->Top    = 18 + 17 * nItem;
              Radio->Width  = 170;
              Radio->OnClick = RadioButton5Click;
          }
          break;
}
Panel2->Visible = true;
Screen->Cursor  = crArrow;

Como se ve al entrar en el evento en que se montan las pantallas; en teoría lo primero que hago es borrar los elementos anteriores que pudiera haber y, en función del TRadioButton pulsado, se montan las tres pantallas. Pero como se pueden ver en las dos últimas imágenes no se eliminan todos los elementos del montaje anterior: en la penúltima por debajo del TRadioButton se ve el TLabeledEdit creado antes y en la última ocurre la inversa.

¿Qué estoy haciendo mal? Porque no quiero, salvo que no quede más remedio, montar tres pantallas distintas.

Angel.Matilla 29-04-2022 19:26:00

Creo que he encontrado la respuesta y está en el bucle donde busco los elementos a borrar for (nItem = 0; nItem < Panel2->ControlCount; nItem ++).

Evidentemente, cada vez que se borra un elemento el ControlCount disminuye en una unidad y llega un momento que se cumple la condición sin haber repasado todos los elementos.

escafandra 29-04-2022 20:41:28

El bucle de borrado debe usar TComponent en lugar de TControl y sólo incrementar cuando no se borra un componente ya que la lista de componentes se decrementa al borrar uno:

Código PHP:

for(nItem 0nItem Panel2->ComponentCount;){
  
TComponent *Component Panel2->Components[nItem];
  if (
Component->ClassNameIs("TCheckListBox") || Component->ClassNameIs("TStaticText") || Component->ClassNameIs("TLabeledEdit") || Component->ClassNameIs("TRadioButton"))
    
delete Component;
  else
    
nItem++;




Saludos.

Angel.Matilla 30-04-2022 09:52:05

Gracias. Esa opción no se me había ocurrido. Lo resolví haciéndolo al revés:
Código:

int nComp = Panel2->ComponentCount - 1;
TComponent *Source;
for (nItem = nComp; nItem >= 0; nItem --)
{
    Source = Panel2->Components[nItem];
    if (Source->ClassNameIs("TCheckListBox") || Source->ClassNameIs("TStaticText") || Source->ClassNameIs("TLabeledEdit") || Source->ClassNameIs("TRadioButton"))
          delete Source;
}



La franja horaria es GMT +2. Ahora son las 17:54:41.

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