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列表中保存的。