Подтвердить что ты не робот

Есть ли способ получить все элементы управления контейнером?

У меня есть форма с кучей элементов управления на ней, и я хотел выполнить итерацию всех элементов управления на определенной панели и включить/отключить их.

Я пробовал это:

var component: TComponent;
begin
  for component in myPanel do
    (component as TControl).Enabled := Value;
end;

Но это ничего не делало. Оказывается, все компоненты находятся в коллекции компонентов формы, а не в их родительском объекте. Так кто-нибудь знает, есть ли способ получить все элементы управления внутри элемента управления? (Помимо уродливого обходного пути вроде этого, что я и должен был сделать):

var component: TComponent;
begin
  for component in myPanel do
    if (component is TControl) and (TControl(component).parent = myPanel) then
      TControl(component).Enabled := Value;
end;

Кто-нибудь, пожалуйста, скажите мне, куда лучше...

4b9b3361

Ответ 1

Вы ищете массив TWinControl.Controls и сопутствующее свойство ControlCount. Это для детей с непосредственным контролем. Чтобы получить внуков и т.д., Используйте стандартные рекурсивные методы.

Вам не нужен массив Components (который повторяется итерацией цикла for - in), поскольку он вообще не имеет отношения к отношениям parent-child. Компоненты могут владеть вещами, которые не имеют дочерних отношений, а элементы управления могут иметь детей, которых они не имеют.

Также обратите внимание, что отключение элемента управления также неявно отключает все его дочерние элементы. Вы не можете взаимодействовать с детьми отключенного управления; ОС не отправляет им входные сообщения. Однако, чтобы отключить их, вы должны отключить их отдельно. То есть, чтобы кнопка имела серый текст, этого недостаточно, чтобы отключить родительский элемент, даже если кнопка не будет реагировать на щелчки мыши. Вам нужно отключить кнопку, чтобы она сама отображалась "отключена".

Ответ 2

Если вы отключите панель, все элементы управления на ней также отключены.

Рекурсивное решение с анонимными методами:

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;

Ответ 3

Вот путь 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;

Ответ 4

Просто

Panel.Enabled := Value;

Ответ 5

Он находит все элементы управления, также вложенные в фреймы и т.д., И указывает на них через список.  Будьте осторожны, чтобы впоследствии освободить список.

Function AllControls(form : tForm) : tList<tControl>;
Procedure Add(Control : tControl );
var i : integer;
begin
  if Control is TWinControl then
  with TWinControl(Control) do
  for i := 0 to Controlcount-1 do
    Add(Controls[i]);

    if Control <> form  then
    result.Add(Control);
  end;
 begin
   result := tlist<tControl>.create;
   add(form);
 end;

 var contrls : tlist<tcontrol>;
     c : tcontrol;
 begin
    try
      contrls := AllControls(form1);
      for c in ctrls do Visit(c);  // Do something
    finally
      contrls.free;
    end;
 end;

И если вам нужна универсальная версия, где вы можете запросить конкретный тип элемента управления, вы можете использовать это:

Procedure TForm1.Addcontrols( control : tcontrol; list : tlist<tcontrol>);
var i : integer;
begin
  if control is twincontrol then
  with twincontrol(control) do
    for i := 0 to controlcount-1 do
    addControl(controls[i], list);
    list.Add(control)
end;

Function TForm1.GetControls<T>(f : tform) : tlist<T>;
var list : tlist<tcontrol>;
    c : tcontrol;
begin
  list := tlist<tcontrol>.Create;
  addControls(f, list);
  result := tlist<t>.create;
  for c in list do
  if c <> f  then
  if c is t then
  result.Add(c);
  list.free;
end;

procedure TForm1.FormCreate(Sender: TObject);
VAR List : TList<TRadioButton>;
begin
  List := GetControls<TRadioButton>(self);
end;

end.

Используйте

  List := GetControls<TControl>(self);

чтобы получить все элементы управления..

Ответ 6

Я знаю, что этот пост немного стар, но я пришел сюда на основе поиска той же информации. Вот код С++, который я разработал для всех, кого это интересует.

// 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 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);
}