Existe alguma maneira de obter todos os controles em um controle de recipiente?
Pergunta
Eu tenho um formulário com um monte de controles sobre ele, e eu queria para percorrer todos os controles em um determinado painel e ativar / desativar-los.
Eu tentei isso:
var component: TComponent;
begin
for component in myPanel do
(component as TControl).Enabled := Value;
end;
Mas isso não fez nada. Acontece que todos os componentes estão em coleta de componente do formulário, não o seu objeto pai é. Então, alguém sabe se há alguma maneira de obter todos os controles dentro de um controle? (Além de uma solução feio como este, que é o que eu acabei tendo que fazer):
var component: TComponent;
begin
for component in myPanel do
if (component is TControl) and (TControl(component).parent = myPanel) then
TControl(component).Enabled := Value;
end;
Alguém por favor me diga que não há uma maneira melhor ...
Solução
Você está procurando a matriz TWinControl.Controls
ea propriedade ControlCount
que o acompanha. Aqueles são para filhos imediatos de um controle. Para obter netos etc., usar técnicas recursiva padrão.
Você não quer realmente a matriz Components
(que é o que o loop for
-in
itera sobre) uma vez que nada tem a ver, em geral, com a relação pai-filho. Os componentes podem possuir coisas que não têm relação criança, e controles podem ter filhos que eles não possuem.
Além disso, note que a desativação um controle desativa implicitamente todos os seus filhos, também. Você não pode interagir com os filhos de um controle desabilitado; o sistema operacional não envia mensagens de entrada para eles. Para torná-los olhar desativada, porém, você precisa desativá-los separadamente. Isto é, fazer um botão tem texto a cinzento, não é suficiente para desativar seu pai, mesmo que o botão não responderá aos cliques do mouse. Você precisa desativar o próprio botão para torná-lo pintar a si mesmo "disabledly."
Outras dicas
Se você desativar um painel, ao controles sobre ele são muito deficientes.
solução recursiva com 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;
Aqui está uma maneira 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;
Simplesmente
Panel.Enabled := Value;
Eu sei que este post é um pouco velho, mas eu vim aqui com base em uma pesquisa para a mesma informação. Aqui está um código C ++ que eu trabalhei para qualquer pessoa interessada.
// 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);
}