有没有办法获得容器控件上的所有控件?

时间:2022-08-17 15:54:24

I've got a form with a bunch of controls on it, and I wanted to iterate through all the controls on a certain panel and enable/disable them.

我有一个带有大量控件的表单,我想迭代某个面板上的所有控件并启用/禁用它们。

I tried this:

我试过这个:

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

But that did nothing. Turns out all components are in the form's component collection, not their parent object's. So does anyone know if there's any way to get all the controls inside a control? (Besides an ugly workaround like this, which is what I ended up having to do):

但那没有做任何事情。原来所有组件都在表单的组件集合中,而不是它们的父对象。那么有谁知道是否有任何方法可以获得控件内的所有控件? (除了像这样的丑陋的解决方法,这是我最终必须做的):

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

Someone please tell me there's a better way...

有人请告诉我有更好的方法......

5 个解决方案

#1


You're looking for the TWinControl.Controls array and the accompanying ControlCount property. Those are for a control's immediate children. To get grandchildren etc., use standard recursive techniques.

您正在寻找TWinControl.Controls数组和随附的ControlCount属性。那些是控制的直接孩子。要获得孙子等,请使用标准的递归技术。

You don't really want the Components array (which is what the for-in loop iterates over) since it has nothing to do, in general, with the parent-child relationship. Components can own things that have no child relationship, and controls can have children that they don't own.

你真的不需要Components数组(这是for-in循环迭代的),因为它通常与父子关系无关。组件可以拥有没有子关系的东西,控件可以拥有他们不拥有的子级。

Also note that disabling a control implicitly disables all its children, too. You cannot interact with the children of a disabled control; the OS doesn't send input messages to them. To make them look disabled, though, you'll need to disable them separately. That is, to make a button have grayed text, it's not enough to disable its parent, even though the button won't respond to mouse clicks. You need to disable the button itself to make it paint itself "disabledly."

另请注意,禁用控件也会隐式禁用其所有子控件。你不能与残疾人控制的孩子互动;操作系统不会向它们发送输入消息。但是,要使它们看起来处于禁用状态,您需要单独禁用它们。也就是说,要使按钮具有灰色文本,即使该按钮不响应鼠标单击,也不足以禁用其父项。您需要禁用按钮本身,使其“禁用”自己绘制。

#2


If you disable a panel, al controls on it are disabled too.

如果禁用面板,则对其进行控制也会被禁用。

Recursive solution with anonymous methods:

使用匿名方法的递归解决方案:

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


Here is a Delphi 2007 way:

这是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


Simply

Panel.Enabled := Value;

#5


I know this post is a little old but I came here based on a search for the same information. Here is some C++ code that I worked out for anyone interested.

我知道这篇文章有点旧,但我是根据搜索相同信息来到这里的。这是我为感兴趣的人制定的一些C ++代码。

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

#1


You're looking for the TWinControl.Controls array and the accompanying ControlCount property. Those are for a control's immediate children. To get grandchildren etc., use standard recursive techniques.

您正在寻找TWinControl.Controls数组和随附的ControlCount属性。那些是控制的直接孩子。要获得孙子等,请使用标准的递归技术。

You don't really want the Components array (which is what the for-in loop iterates over) since it has nothing to do, in general, with the parent-child relationship. Components can own things that have no child relationship, and controls can have children that they don't own.

你真的不需要Components数组(这是for-in循环迭代的),因为它通常与父子关系无关。组件可以拥有没有子关系的东西,控件可以拥有他们不拥有的子级。

Also note that disabling a control implicitly disables all its children, too. You cannot interact with the children of a disabled control; the OS doesn't send input messages to them. To make them look disabled, though, you'll need to disable them separately. That is, to make a button have grayed text, it's not enough to disable its parent, even though the button won't respond to mouse clicks. You need to disable the button itself to make it paint itself "disabledly."

另请注意,禁用控件也会隐式禁用其所有子控件。你不能与残疾人控制的孩子互动;操作系统不会向它们发送输入消息。但是,要使它们看起来处于禁用状态,您需要单独禁用它们。也就是说,要使按钮具有灰色文本,即使该按钮不响应鼠标单击,也不足以禁用其父项。您需要禁用按钮本身,使其“禁用”自己绘制。

#2


If you disable a panel, al controls on it are disabled too.

如果禁用面板,则对其进行控制也会被禁用。

Recursive solution with anonymous methods:

使用匿名方法的递归解决方案:

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


Here is a Delphi 2007 way:

这是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


Simply

Panel.Enabled := Value;

#5


I know this post is a little old but I came here based on a search for the same information. Here is some C++ code that I worked out for anyone interested.

我知道这篇文章有点旧,但我是根据搜索相同信息来到这里的。这是我为感兴趣的人制定的一些C ++代码。

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