【问题标题】:Is there any way to get all the controls on a container control?有什么方法可以获取容器控件上的所有控件?
【发布时间】:2010-09-29 17:15:41
【问题描述】:

我有一个带有一堆控件的表单,我想遍历某个面板上的所有控件并启用/禁用它们。

我试过了:

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;

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

【问题讨论】:

    标签: delphi forms controls iterator vcl


    【解决方案1】:

    这个找到所有控件,也嵌套在框架等中,并通过列表指向它们。 请注意之后释放列表。

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

    获取所有控件..

    【讨论】:

      【解决方案2】:

      我知道这篇文章有点旧,但我是基于对相同信息的搜索来到这里的。这是我为任何感兴趣的人编写的一些 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);
      }
      

      【讨论】:

      【解决方案3】:

      简单

      Panel.Enabled := Value;
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          【解决方案5】:

          如果您禁用面板,其上的所有控件也会被禁用。

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

          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;
          

          【讨论】:

          • 非常好。不幸的是,我们还没有 D2009 在这里工作。 :(
          • 只需稍作调整(摆脱TWinControl),也可以在Firemonkey中工作。
          【解决方案6】:

          您正在寻找 TWinControl.Controls 数组和随附的 ControlCount 属性。这些是针对控件的直系子级的。要获得孙子等,请使用标准递归技术。

          您并不真正想要 Components 数组(这是 for-in 循环迭代的内容),因为它通常与父子关系无关。组件可以拥有没有子关系的事物,而控件可以拥有不属于它们的子项。

          还请注意,禁用控件也会隐式禁用其所有子控件。您不能与禁用控件的子级交互;操作系统不会向他们发送输入消息。但是,要使它们看起来被禁用,您需要单独禁用它们。也就是说,要使按钮具有灰色文本,仅禁用其父级是不够的,即使该按钮不会响应鼠标单击。您需要禁用按钮本身以使其“禁用”自己绘制。

          【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2023-03-23
          • 1970-01-01
          • 1970-01-01
          • 2014-02-23
          • 1970-01-01
          • 2019-12-16
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多