¿Hay alguna manera de obtener todos los controles en un control de contenedor?
Pregunta
Tengo un formulario con un montón de controles, y quería recorrer todos los controles de un panel determinado y habilitarlos / inhabilitarlos.
He intentado esto:
var component: TComponent;
begin
for component in myPanel do
(component as TControl).Enabled := Value;
end;
Pero eso no hizo nada. Resulta que todos los componentes están en la colección de componentes del formulario, no en su objeto principal. Entonces, ¿alguien sabe si hay alguna manera de obtener todos los controles dentro de un control? (Además de una solución fea como esta, que es lo que terminé por hacer):
var component: TComponent;
begin
for component in myPanel do
if (component is TControl) and (TControl(component).parent = myPanel) then
TControl(component).Enabled := Value;
end;
Alguien, por favor, dime que hay una mejor manera ...
Solución
Está buscando la matriz TWinControl.Controls
y la propiedad ControlCount
que la acompaña. Esos son para los hijos inmediatos de un control. Para obtener nietos, etc., utilice técnicas recursivas estándar.
Realmente no desea que la matriz Components
(que es lo que itera el for
- in
) ya que no tiene nada para Hacer, en general, con la relación padre-hijo. Los componentes pueden poseer cosas que no tienen relación con los hijos, y los controles pueden tener hijos que no tienen.
También tenga en cuenta que deshabilitar un control implícitamente deshabilita todos sus hijos, también. No puedes interactuar con los hijos de un control discapacitado; el sistema operativo no les envía mensajes de entrada. Sin embargo, para hacerlos parecer inhabilitados, deberá deshabilitarlos por separado. Es decir, para hacer que un botón tenga texto en gris, no es suficiente deshabilitar a su padre, aunque el botón no responda a los clics del mouse. Debe deshabilitar el botón para que se pinte " deshabilitado. & Quot;
Otros consejos
Si deshabilita un panel, todos los controles en él también están deshabilitados.
Solución recursiva con métodos anónimos:
type
TControlProc = reference to procedure (const AControl: TControl);
procedure TForm6.ModifyControl(const AControl: TControl;
const ARef: TControlProc);
var
i : Integer;
begin
if AControl=nil then
Exit;
if AControl is TWinControl then begin
for i := 0 to TWinControl(AControl).ControlCount-1 do
ModifyControl(TWinControl(AControl).Controls[i], ARef);
end;
ARef(AControl);
end;
procedure TForm6.Button1Click(Sender: TObject);
begin
ModifyControl(Panel1,
procedure (const AControl: TControl)
begin
AControl.Enabled := not Panel1.Enabled;
end
);
end;
Esta es una forma de Delphi 2007:
procedure TForm6.ModifyControl(const AControl: TControl; const value: Boolean);
var
i: Integer;
begin
if AControl=nil then Exit;
if AControl is TWinControl then begin
for i := 0 to TWinControl(AControl).ControlCount-1 do
ModifyControl(TWinControl(AControl).Controls[i], value);
end;
Acontrol.Enabled := value;
end;
procedure TForm6.Button1Click(Sender: TObject);
begin
ModifyControl(Panel1, true); // true or false
end;
Simplemente
Panel.Enabled := Value;
Sé que esta publicación es un poco antigua, pero vine aquí en base a una búsqueda de la misma información. Aquí hay un código de C ++ que elaboré para cualquier persona interesada.
// DEV-NOTE: GUIForm flattens the VCL controls
// VCL controls are nested. I.E. Controls on a
// Panel would have the Panel as a parent and if
// that Panel is on a TForm, TForm's control count
// does not account for the nested controls on the
// Panel.
//
// GUIControl is passed a Form pointer and an index
// value, the index value will walk the controls on the
// form and any child controls counting up to the idx
// value passed in. In this way, every control has a
// unique index value
//
// You can use this to iterate over every single control
// on a form. Here is example code:
//
// int count = 0;
// TForm *pTForm = some_form
// TControl *pCtrl = 0;
// do
// {
// pCtrl = GUIControl(pTForm, count++);
//
// }while(pCtrl);
TControl *GUIControl(TForm *F, int idx)
{
TControl *rval = 0;
int RunCount = 0;
for(int i=0; i<F->ControlCount && !rval; i++)
{
TControl *pCtl = F->Controls[i];
if(RunCount == idx )
rval = pCtl;
else
rval = GUIChildControl( pCtl, RunCount, idx);
RunCount++;
}
return(rval);
}
TControl *GUIChildControl(TControl *C, int &runcount, int idx)
{
TControl *rval = 0;
TWinControl *pC = dynamic_cast<TWinControl *>(C);
if(pC)
{
for(int i=0; i<pC->ControlCount && !rval; i++)
{
TControl *pCtrl = pC->Controls[i];
runcount++;
if( runcount == idx)
rval = pCtrl;
else
{
TWinControl *pCC = dynamic_cast<TWinControl *>(pCtrl);
if(pCC)
{
if( pCC->ControlCount )
rval = GUIChildControl(pCtrl, runcount, idx);
}
}
}
}
return(rval);
}