標籤:
前兩天編碼遇到了要使用FindChildControl方法擷取指定名稱的TSpeedButton按鈕,結果折騰了半天就是沒得結果(基礎不紮實,呵呵),於是趕緊搜尋了下,補習關於這兩個方法的用法。
TWinControl類的FindChildControl方法在FWinControls中尋找返回指定名稱的可視且有表單的組件(繼承自TWinControl類)。該方法可以確定當前控制項是否含有(contain)指定名稱的繼承自TWinControl類的子控制項,其結果與指定要尋找的控制項的Parent屬性有關。如果未找到返回nil(NULL),該方法只尋找當前控制項的直接子控制項,不會迭代尋找子控制項的子控制項。
TComponent類的FindComponent方法在FComponents中尋找返回指定名稱的組件。該方法可以確定當前組件是否擁有(Own)指定名稱的組件,其結果與指定尋找的組件在建立時指定的Owner屬性有關。表單設計器上的建立的組件其擁有者為表單,所以一般使用Self.FindComponent調用這個方法。該方法參數不區分大小寫。
Parent屬性是指定控制項的父容器,控制項只能在父容器範圍內顯示和移動。Owner屬性是指定組件的所有者,它負責組件的建立和釋放。在表單編輯器中添加組件,則預設地將Owner屬性設定為所屬的表單,所以用表單的FindComponent肯定可以找到。如果動態建立組件,那麼必須指定其Owner和Parent,才可以調用相應方法找得到。而且,如果你放上去的是TWinControl的繼承類,那麼用FindChildControl就可以找到,否則就找不到。
FindComponent非常簡單,下面重點說說FindChildControl這令人糾結的方法【注1】。
這裡先要瞭解下面幾個基類:
1、TComponent 所有組件基類
2、TControl 運行時可視組件(TWinControl和TGraphicControl的基類)
3、TWinControl 可視且有表單的組件的基類
TWincontrol就是Windows控制項陳列庫的基類,從TWinControl繼承下來的控制項,都是具備有控制項控制代碼的,也就是在Windows內部具備有唯一標記,能動態索引找到的。
Delphi使用兩個列表來維護控制項的子控制項:FWinControls和FControls。前者儲存有控制代碼的控制項,即繼承自TWinControl的控制項;後者儲存無控制代碼的控制項,一般繼承自TGraphicControl的控制項。所以控制項的ControlCount屬性值為FWinControls.Count與FControls.Count之和。
[delphi] view plain copy print?
- //ControlCount屬性的讀取方法
- function TWinControl.GetControlCount: Integer;
- begin
- Result := 0;
- if FControls <> nil then Inc(Result, FControls.Count);
- if FWinControls <> nil then Inc(Result, FWinControls.Count);
- end;
在建立子控制項時會調用Insert方法來將子控制項添加到父容器的上述兩個列表。
[delphi] view plain copy print?
- procedure TWinControl.Insert(AControl: TControl);
- begin
- if AControl <> nil then
- begin
- if AControl is TWinControl then
- begin
- ListAdd(FWinControls, AControl);//如果是TWinControl則添加到FWinControls列表
- ...
- end
- else
- ListAdd(FControls, AControl);//否則添加到FControls列表
- ...
- end;
- end;
下面再來看看FindChildControl的實現代碼,可以看到FindChildControl只尋找了FWinControls列表,這就是上面所說的它只尋找可視且有表單的組件,即繼承自TWinControl類的組件。
[delphi] view plain copy print?
- function TWinControl.FindChildControl(const ControlName: string): TControl;
- var
- I: Integer;
- begin
- Result := nil;
- if FWinControls <> nil then
- for I := 0 to FWinControls.Count - 1 do
- if CompareText(TWinControl(FWinControls[I]).Name, ControlName) = 0 then
- begin
- Result := TControl(FWinControls[I]);
- Exit;
- end;
- end;
測試
整個測試介面
1、Self.FindChildControl(表單調用)
測試代碼:
[delphi] view plain copy print?
- //FindChildControl尋找
- procedure TForm1.btn1Click(Sender: TObject);
- var
- c:TControl;
- begin
- memo1.Clear;
- Memo1.Lines.Add(‘FindChildControl尋找‘+Edit1.Text+‘...‘);
- c:=self.FindChildControl(Edit1.Text);//表單調用
- if(c=nil)then
- Memo1.Lines.Add(‘未找到!‘)
- else
- begin
- Memo1.Lines.Add(‘找到!‘);
- Memo1.Lines.Add(‘父控制項名稱:‘+c.Parent.Name);
- end;
- end;
測試結果:
(1)尋找Button1(繼承自TWinControl)
(2)尋找Label1(繼承自TGraphicControl)
(3)尋找Button11(父容器為Panel1)
2、Panel1.FindChildControl
測試代碼:
[delphi] view plain copy print?
- //FindChildControl尋找——父控制項調用
- procedure TForm1.btn4Click(Sender: TObject);
- var
- c:TControl;
- begin
- memo1.Clear;
- Memo1.Lines.Add(‘FindChildControl尋找‘+Edit1.Text+‘...‘);
- c:=panel1.FindChildControl(Edit1.Text); //panel1調用
- if(c=nil)then
- Memo1.Lines.Add(‘未找到!‘)
- else
- begin
- Memo1.Lines.Add(‘找到!‘);
- Memo1.Lines.Add(‘父控制項名稱:‘+c.Parent.Name);
- end;
- end;
測試結果:尋找Button11(父容器為Panel1)
3、Self.FindComponent
測試代碼:
[delphi] view plain copy print?
- //FindComponent尋找
- procedure TForm1.btn2Click(Sender: TObject);
- var
- c:TComponent;
- begin
- memo1.Clear;
- Memo1.Lines.Add(‘FindComponent尋找‘+Edit1.Text+‘...‘);
- c:=self.FindComponent(Edit1.Text);//表單調用
- if(c=nil)then
- Memo1.Lines.Add(‘未找到!‘)
- else
- begin
- Memo1.Lines.Add(‘找到!‘);
- Memo1.Lines.Add(‘擁有者名稱:‘+c.Owner.Name);
- end;
- end;
測試結果
(1)尋找Button1(父容器為Form1)、Button11(父容器為Panel1)
(2)尋找Label1(繼承TCustomLabel→TGraphicControl)、SpeedButton1(繼承TGraphicControl)、Timer1(繼承TComponent)
4、Panel1.FindComponent
測試代碼:
[delphi] view plain copy print?
- procedure TForm1.Button6Click(Sender: TObject);
- var
- lbl:TLabel;
- c:TComponent;
- begin
- lbl:=TLabel.Create(Panel2);//動態建立並指定擁有者
- lbl.Name:=‘Label6‘;
- memo1.Clear;
- Memo1.Lines.Add(‘FindComponent尋找Label6...‘);
- c:=panel2.FindComponent(‘Label6‘);//擁有者調用
- if(c=nil)then
- Memo1.Lines.Add(‘未找到!‘)
- else
- begin
- Memo1.Lines.Add(‘找到!‘);
- Memo1.Lines.Add(‘擁有者名稱:‘+c.Owner.Name);
- end;
- {在表單上顯示還需加上以下代碼}
- lbl.Parent:=Panel2;//Parent預設為nil,所以“無顯示”
- lbl.Left:=50; //指定相對Parent的位置
- lbl.Top:=50;
- end;
測試結果:
注1:糾結倒不是因為這個方法本身,而是一開始我就寫了這個demo來測試這個方法的使用及其結果,當時也沒注意TLabel不是繼承自TWinControl(呵呵,平時都不怎麼關注這些,自然以為這些普通控制項都繼承自TWinControl),結果估計是編譯器出問題了,用Self.FindChildControl可以查詢到Label1,用Panel1.FindChildControl也可以查詢到Label(之前都是測試Label的),但就是在TabSheet.FindChildControl裡不能查到相應Label,而且編譯器也不能在FindChildControl裡設斷點,後來在網上看到說要將編譯器的一個開關開啟,但執行的結果還是一樣。第二天,無意中看到TLabel不是繼承自TWinControl,這就令人鬱悶了,怎麼之前能查詢到呢?馬上開啟demo從新運行了一次,結果就這樣突然都查不到了,真是令人蛋疼。好在最後驗證了這個方法的原理及其實現過程。
http://blog.csdn.net/tht2009/article/details/6954880
FindChildControl與FindComponent