您现在的位置:首页 >> VCL >> VCL >> 内容

Delphi的Controls问题

时间:2011/9/3 16:26:16 点击:

  核心提示:原来的代码大致是这样的: var nIndex: Integer; cTmp: TControl;begin for nIndex:= 0 to Self.Controls.Count - 1 do...
原来的代码大致是这样的:

 var
    nIndex: Integer;
    cTmp: TControl;
begin
    for nIndex:= 0 to Self.Controls.Count - 1 do
    begin
      cTmp:= Self.Controls[nIndex];
      if cTmp Is TCustomEdit then
      begin
        with TLable.Create(Self) do
        begin
          Caption:= 'A' + IntToStr(nIndex);
          Left:= cTmp.Left - Width;
          Top:= cTmp.Top + 10;
           Color:= clRed;
           Visible:= true;
           AutoSize:= true;
           Parent:= Self;
        end;
      end;
    end;
end;

       跟踪发现在delphi内部,没有句柄的控件和有句柄的控件是被分别保存到了两个列表中FControls和FWinContrls两个列表中。

      取控件的时候(省略异常保护代码),也就是通过: 对象.Controls[nIndex] 访问对象的时候:
function GetControl(Index: Integer): TControl;
var
 N: Integer;
begin
 N:= FControls.Count;

 if Index < N then
    Result:= FControls[Index]          // 这里
 else
    Result:= FWinControls[Index - N];  // 关键在这里
end;

    添加的时候(仅仅写关键代码),在设置 对象.Parent:= 父控件 的时候会调用到:
Insert(ACtrl: TControl)
  if ACtrl Is TWinControl then
  begin
    ListAdd(FWinControls, ACtrl);
  end
  else
    ListAdd(FControls, ACtrl);

现在的代码中:
  ..
  cTmp := Self.Controls[I];  // 这时会去调用GetControl函数
  ...
  C1.Parent:= FWinControl;       // c1即创建的TLabel实例,这时会调用Insert把该控件添加到FControls<如果是TLabel>

分析一个过程就知道问题在哪里了(假设窗体上有4个WinControl<有句柄>, 0个Control<无句柄>):
此时:FControls.Count    0    FWinControls.Count  4

循环过程中:

I = 0 GetControl将获取的是: C:= 对象.FWinControls[0 - 0] 即第0个WinControl
      假设FWinControls[0]就是TEdit控件,那么你会添加一个TLabel, 在FControls中增加一个控件此时: FControls.Count = 1  FWinControls.Count = 4
I = 1 GetControl将获取的是: 对象.FWinControls[1 - 1] 还是第0个WinControl
      同样,你会再去创建一个Label,这个Lable的位置就跟前一个一样了。该轮循环完成时:FControls.Count = 2  FWinControls.Count = 4
I = 2 ....  C:= 对象.FWinControls[2 - 2];
....
       接下来的情况就跟前面的一样了,自己分析一下就知道了。所以,我们每次获取到的C:= FWinControl.Controls[I]是同一个。

      如果把TLabel换成TEdit就不一样了,这时只会在TWinControls中增加了,就不一样了。有兴趣的自己可以分析一下。

      一般来说,我们不会也不应当这样访问,一边在窗体上去添加控件,一边去访问窗体上的控件列表。

这样修改一下就实现的要求了(但是最好不要这么做):
var
  I: Integer;
  C: TControl;
  C1: TLabel;
  nCnt: Integer;
begin
  nCnt:= 0;

  for I:=0 to FWinControl.ControlCount-1 do
  begin
    C := FWinControl.Controls[I + nCnt];
    if C is TCustomEdit then
    begin
      C1 := TLabel.Create(FWinControl);
      C1.Parent := FWinControl;
      C1.Visible := True;
      C1.Caption := 'A'+IntToStr(I);
      C1.Left := C.Left-C1.Width;
      C1.Top := C.Top+10;
      C1.Color := clRed;
      C1.AutoSize := True;

      inc(nCnt);
    end;
  end;
end;

以上分析是基于Delphi 7的分析。

看来以后使用的时候的注意了。不过 对象.Components倒是在一个FComponents列表中保存的。

Tags:问题 
作者:etomahawk 来源:转载
共有评论 0相关评论
发表我的评论
  • 大名:
  • 内容:
本类推荐
  • 没有
本类固顶
  • 没有
  • 盒子文章(www.2ccc.com) © 2020 版权所有 All Rights Reserved.
  • 沪ICP备05001939号