




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認(rèn)領(lǐng)
文檔簡介
1、Delphi控件開發(fā)淺入深出(一) 有人說過“不會開發(fā)控件的Delphi程序員不是真正的程序員”。Delphi正是由于高度的可擴展性和大量的第三方控件的支持才能吸引無數(shù)程序員挑剔的目光。即使是由于工作需要使用其他開發(fā)工具的開發(fā)者也常常懷念和Delphi度過的日日夜夜。接觸Delphi已經(jīng)一年多了,從當(dāng)初對著Delphi組件面板上上百個控件不知所措,到現(xiàn)在已經(jīng)可以根據(jù)需要開發(fā)一些有一定難度的控件,其中走過的路是十分艱辛的,所以特此寫下這篇文章,將自己的經(jīng)驗留給后來者,也算是獻給“同門師弟”的一份厚禮吧! 需要說明的一點是:在寫這篇文章之前我假設(shè)讀者已經(jīng)對面向?qū)ο蟮幕局R有一定的了解,所以對于文
2、章中面向?qū)ο笙嚓P(guān)的概念將不再展開講述。一、牛刀小試TURLLabel控件我們從一個能夠添加超鏈接的標(biāo)簽控件開始我們的控件開發(fā)之旅吧!既然是Label我們就從Tlabel派生這個控件吧(其實從TcustomLabel派生最好,不過出于簡單的目的我們這里先從Tlabel派生)!1、選擇“File”“New”“Component”,將彈出如下的對話框:在Ancestor type中選擇Tlabel,ClassName中填入TURLLabel(名字可以任意取,但是要以T開頭,否則的話會出現(xiàn)注冊控件時候的問題)。這里Ancestor type代表控件的基類,TURLLabel代表控件的名稱。2、超鏈接的
3、視覺效果是帶下劃線的文字,所以我們覆蓋父類的構(gòu)造函數(shù),在構(gòu)造函數(shù)里修改控件的字體屬性。constructor TUrlLabel.Create(AOwner:TComponent);begin inherited Create(AOwner); Cursor:=crHandPoint; Font.Style:= fsUnderline; end;代碼解釋:(1) inherited Create(AOwner);這句的意思是執(zhí)行父類的構(gòu)造函數(shù)。我們制作控件的時候,如果覆蓋了父類的構(gòu)造函數(shù),那么在新的構(gòu)造函數(shù)中一定要首先調(diào)用父類的構(gòu)造函數(shù),否則會引起錯誤。這是很多初學(xué)控件開發(fā)的人常常遇到的問題。
4、當(dāng)您把自己開發(fā)的控件從面板上拖放到窗體時,如果跳出一個“Access Violent”的錯誤對話框的話,那么十有八九是因為您忘了調(diào)用父類的構(gòu)造函數(shù)。 (2) Cursor:=crHandPoint;Font.Style:= fsUnderline; 這三句的意思是修改標(biāo)簽的視覺效果。Cursor:=crHandPoint;是設(shè)定當(dāng)鼠標(biāo)移動到控件上時鼠標(biāo)的形狀為“手型”;Font.Style:= fsUnderline; 是設(shè)定文字的下劃線效果。3、既然是超鏈接控件,那么我們肯定要能使用戶在使用控件的時候能在“Object Inspector”中對超鏈接的URL進行修改,所以我們應(yīng)該為控件增加一
5、個Url屬性。 屬性是訪問控件字段的接口。通過屬性,控件使用者可以間接讀或者寫控件的內(nèi)部字段改變控件的狀態(tài)。組件屬性的聲明需要以下幾部分:屬性名、屬性類型、讀方法(或讀字段)、寫方法(或?qū)懽侄?。如果沒有寫方法或?qū)懽侄?,則該屬性為只讀屬性)。屬性在控件類聲明的Published部分聲明。在Published中聲明的屬性可以在設(shè)計期通過“Object Inspector”對屬性值進行修改。如果聲明在Public部分則不可以在設(shè)計期通過“Object Inspector”對屬性值進行修改,但是可以在運行時通過代碼進行讀寫。 在類聲明的Private訪問區(qū)域中添加如下字段聲明: FUrl: Strin
6、g; 在類聲明中添加Published訪問區(qū)域,并添加如下代碼property Url: String read FUrl write FUrl;這段聲明的意思是為控件添加一個Url屬性,屬性的類型是string,在讀Url屬性時返回Furl的值,在寫 Url屬性時設(shè)定Furl的值。4、超鏈接的視覺效果有了,下面使它點擊時調(diào)用瀏覽器打開Url指定的網(wǎng)址。在Delphi控件的事件處理中很多事件都有對應(yīng)的一個調(diào)度方法(這是設(shè)計模式中模板模式的典型應(yīng)用)。比如在鼠標(biāo)點擊控件時,控件會首先調(diào)用Click方法,由Click方法進行相應(yīng)的處理,而絕大多數(shù)調(diào)度方法都會引發(fā)一個事件句柄(關(guān)于事件句柄我們后邊有
7、深入的介紹)。比如Tlabel控件中在用戶用點擊Label時會首先調(diào)用控件的Click方法(被聲明為Protected級別),Click方法再觸發(fā)OnClick事件。所以我們只要覆蓋Tlabel的Click方法進行我們自己的處理就可以了。在Protected部分添加如下的聲明:procedure Click;override; 在實現(xiàn)部分為Click方法寫如下的代碼:procedure TUrlLabel.Click;begin ShellExecute(Application.Handle, nil, PChar(Url), nil, nil,SW_NORMAL); inherited;en
8、d;代碼解釋:(1) ShellExecute的作用是用默認(rèn)的程序打開第三個參數(shù)指定的文件。所以當(dāng)?shù)谌齻€參數(shù)為一個URL時,則用瀏覽器打開這個網(wǎng)址。關(guān)于ShellExecute其他參數(shù)的使用方法可以查閱MSDN或其他相關(guān)資料。(2) Inherited;的作用是調(diào)用父類的Click方法來由父類來對鼠標(biāo)單擊事件做其他的處理。5、源代碼。下面給出這個控件的全部源代碼:unit UrlLabel;interfaceuses Windows, Messages, SysUtils, Classes, Controls, StdCtrls,Shellapi, Graphics, Forms;type T
9、UrlLabel = class(TLabel) private FUrl:AnsiString; protected procedure Click;override; public constructor Create(AOwner:TComponent);override; published property Url:AnsiString read FUrl write FUrl; end;procedure Register;implementationconstructor TUrlLabel.Create(AOwner:TComponent);begin inherited Cr
10、eate(AOwner); Cursor:=crHandPoint; Font.Style:=fsUnderline;end;procedure TUrlLabel.Click;begin ShellExecute(Application.Handle, nil, PChar(Url), nil, nil,SW_NORMAL); inherited;end;procedure Register;begin RegisterComponents(Linco, TUrlLabel);/控件生成向?qū)傻淖钥丶么aend;end.6、為控件添加圖標(biāo)。如果沒有給自定義的控件定義圖標(biāo),出現(xiàn)在控件面板
11、上的自定義圖標(biāo)的圖標(biāo)是默認(rèn)的圖標(biāo),很沒有“個性”,也不容易被用戶與其他控件區(qū)別開來,所以我們需要給組件指定一個圖標(biāo)。首先利用Delphi的Image Editor創(chuàng)建一個24*24的位圖,并把它保存到一個DCR文件中。創(chuàng)建了一個位圖后,就需要給位圖命名了。位圖的名稱必須和控件的類名相同,且為大寫,而DCR文件的名字則必須與控件所在單元的單元名相同。如我們上邊定義的控件,位圖的名字應(yīng)該為TURLLABEL,DCR文件的名字應(yīng)該是UrlLabel.dcr,此DCR文件應(yīng)該與組件的單元文件放在同一個目錄下。打開Image Editor,選擇”File”“New” “Component Resourc
12、e File(.dcr)”,如下圖:在“Contents”上單擊鼠標(biāo)右鍵,選擇“New”“BitMap”:在Width,Height中都填入24,點“OK”即可??梢栽贐itmap1上點右鍵選擇“Rename”為位圖重命名為TURLLABEL,然后雙擊TURLLABEL,就可以像使用“畫圖”一樣為您的控件設(shè)計圖標(biāo)了。7、注冊組件。點擊ComponetInstall Componet進行自定義組件安裝,此時將出現(xiàn)組件安裝對話框。在Unit FilName 中輸入控件單元文件的文件名(包括路徑),點擊“OK”,在彈出的Package Editor 中按下Install按鈕。如果安裝成功系統(tǒng)就會提示
13、安裝成功。關(guān)閉Package Editor時,會提示您是否保存修改,點擊Yes即可。安裝成功,建立一個測試程序。將URLLabel控件放到窗體上,設(shè)定Url屬性為 運行程序,點擊此Label,就會彈出瀏覽器打開這個網(wǎng)址。思考題:1、如何為控件添加一個圖標(biāo)?2、Delphi中的控件的共同基類是哪個類?3、請做一個編輯框控件,當(dāng)控件中輸入的字符串是網(wǎng)址(以http:/開頭)且用戶在編輯框上按回車時,用瀏覽器打開此網(wǎng)址。Delphi控件開發(fā)淺入深出(二) 二、控件開發(fā)縱覽 通過開發(fā)上邊這個控件,我們已經(jīng)對Delphi控件開發(fā)有了基本的認(rèn)識。下面我們將系統(tǒng)的講述一下控件開發(fā)的知識。制作控件第一件事就是
14、選擇適當(dāng)?shù)?Delphi對象類型作為父對象,以派生新的對象。子對象可以繼承父對象的全部非 private部件,但不能擺脫不需要的部件。因此,所選父對象應(yīng)盡可能多地包含子對象所需的屬性、事件和方法,但不應(yīng)包含子對象不需要的東西。Delphi必須從Tcomponent或Tcomponent的子類派生。TComponent是所有 Delphi控件的基點,但若直接從 TComponent 派生新控件,很多東西就需要自己從頭做起。一般只有非可視控件才直接從 TComponent派生。 Delphi提供了若干專門用于制作控件(可視控件)的對象類型,都是從 TControl和 TWinControl派生而來
15、。TControl的子類型用于非窗口式控件, TWinControl的子類型則用于窗口式控件。除非特殊需要,一般不直接從 TControl和TWinControl派生新控件,而是從其子類型派生。這樣可以充分利用原有的屬性、事件和方法,減少很多工作量。在這些控件類型中,非通用的屬性、事件和方法都聲明為 protected。這樣可以禁止控件用戶訪問,又能被子類型繼承和修改。在新控件中,可以簡單地把繼承來的屬性和事件重新聲明為 published,使控件用戶能在設(shè)計期通過對象編輯窗口訪問,也可以進而修改屬性的默認(rèn)值和讀寫方式,或是重載( override)事件處理子過程和其他控件方法,以修改其中的程
16、序代碼。重聲明可以放寬訪問權(quán)限,但不能相反,例如,不可能把 published屬性重聲明為 private或 protected。 Delphi控件也是Delphi的類,所有的控件都有特定的結(jié)構(gòu)。一般控件包括三大組成部分:屬性、方法和事件,下面先介紹初學(xué)控件開發(fā)的最難懂的屬性部分,其他部分我們將在以后章節(jié)為大家介紹。屬性主要部分就是屬性的讀寫方法(或讀寫字段)。前面的例子用的是讀寫字段,也就是對屬性的讀寫都通過對字段的讀寫來完成。下面為大家講解一下讀寫方法的使用方法:TmyComponent = class(TComponent)Private Fcount: Integer; Procedu
17、re SetCount(Avalue: Integer);Pulbished Property Count: Integer read Fcount write SetCount;End;這個例子中當(dāng)執(zhí)行MyComponent1.Count := 1;這樣的代碼時,將會導(dǎo)致SetCount方法執(zhí)行,并且參數(shù)Avalue被指定為1;當(dāng)執(zhí)行 I := MyComponent1.Count;方法時,會將 Fcount的值返回給I。屬性的聲明語法允許屬性聲明的Read和Write部分用訪問方法取代對象私有數(shù)據(jù)域。屬性的讀方法是不帶參數(shù)的函數(shù),返回同屬性相同類型的值。通常讀方法以Get開頭。屬性的寫方法
18、總是帶一個參數(shù)的過程。寫方法常常以Set開頭。思考題:1、 如何為控件添加屬性?2、 從TwinControl類派生的控件的特點是什么?Delphi控件開發(fā)淺入深出(三)三、開關(guān)控件TlincoSwitch用過Delphi1(好古老的東東呀?。┑娜讼嘈哦加浀眠@個開關(guān)控件,不知道當(dāng)初Borland為什么把這么一個在開發(fā)普通應(yīng)用程序中應(yīng)用不到的工控控件放到Delphi中,而且在Delphi2及其以后的版本中再也沒有見過它的身影。讓我們懷著懷舊的心情把這位“開國元老”請出來吧!1、建立位圖資源文件:用Image Editor建立一個Res文件,并在文件中分別建立下面兩個位圖,并分別命名為SWITCH
19、ON、SWITCHOFF。保存此Res到控件單元所在目錄下。2、寫控件代碼。unit LincoSwitch;interfaceuses SysUtils, Classes, Controls, Graphics, Windows;type TLincoSwitch = class(TCustomControl) private FIsOn: Boolean; FPicOn: Graphics.TBitmap; FPicOff: Graphics.TBitmap; procedure FSetIsOn(AValue: Boolean); protected procedure Click;ov
20、erride; procedure Paint;override; public constructor Create(AOwner: TComponent);override; destructor Destroy;override; published property IsOn: Boolean read FIsOn write FSetIsOn; property OnClick; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnCanResize; property OnDblClick; p
21、roperty OnMouseDown; property OnMouseMove; property OnMouseUp; property OnMouseWheel; property OnResize; end;procedure Register;implementation$R *.resprocedure LoadBitmapFromRes(ABitmapId: string; ABitmap: Graphics.TBitmap);begin ABitmap.LoadFromResourceName(hInstance, ABitmapId);/從資源文件中讀取位圖end;cons
22、tructor TLincoSwitch.Create(AOwner: TComponent);begin inherited Create(AOwner); FPicOn := Graphics.TBitmap.Create; FPicOff := Graphics.TBitmap.Create; LoadBitmapFromRes(SWITCHON, FPicOn); LoadBitmapFromRes(SWITCHOFF, FPicOff); Invalidate;end;destructor TLincoSwitch.Destroy;begin FPicOn.Free; FPicOff
23、.Free; inherited;end;procedure TLincoSwitch.Click;begin IsOn := not IsOn;/改變按鈕的狀態(tài) Invalidate; inherited;end;procedure TLincoSwitch.Paint;begin/畫開關(guān)圖案 if IsOn then StretchBlt(Canvas.Handle, 0, 0, self.Width, self.Height, FPicOn.Canvas.Handle, 0, 0, FPicOn.Width, FPicOn.Height,SRCCOPY) elsele, 0, 0, FP
24、icOff.Width, FPicOff.Height,SRCCOPY);end;procedure TLincoSwitch.FSetIsOn(AValue: Boolean);begin FIson := AValue; Invalidate;end;procedure Register;begin RegisterComponents(Linco, TLincoSwitch);end;end.3、代碼分析 (1)、因為我們要在控件表面上將按鈕的圖案畫出來,所以我們選擇TcustomControl做為父類控件,因為它有個Canvas屬性,我們可以利用Canvas在控件表面作圖。不選用Tco
25、ntrol的原因是因為它有很多我們不需要的屬性。(2)、ABitmap.LoadFromResourceName(hInstance, ABitmapId);是從資源文件中讀取Id為AbitmapId的位圖,關(guān)于資源文件的使用請參考其他相關(guān)資料。注意代碼中的“$R *.res”,它的作用是將資源文件編譯到程序文件中,如果沒有這個預(yù)編譯條件,程序?qū)霈F(xiàn)錯誤。(3)、StretchBlt是將位圖畫到畫板上,使用方法請參考MSDN。(4)、我們?yōu)榭丶黾恿薎sOn屬性。這個布爾屬性用來表示開關(guān)的狀態(tài)(開/關(guān))。從property IsOn: Boolean read FIsOn write FSe
26、tIsOn;我們可以看出這個屬性是個可讀可寫的屬性。當(dāng)讀這個屬性時會將FisOn的值返回給調(diào)用者,而寫屬性時則會調(diào)用FsetIsOn方法,并將賦給屬性的值做為參數(shù)傳遞給FsetIsOn。在FsetIsOn方法中,有如下實現(xiàn)代碼: FIson := AValue; Invalidate;首先將Fison設(shè)置為參數(shù)傳遞來的值,然后調(diào)用 Invalidate;要求重畫控件,以告訴用戶控件的狀態(tài)已經(jīng)改變,這一點是使用寫字段無法做到的。(5) FPicOn: Graphics.TBitmap;FPicOff: Graphics.TBitmap;是聲明兩個.Tbitmap類型變量以保存控件的開關(guān)兩種狀態(tài)的
27、圖案。(6) procedure Click;override;procedure Paint;override;分別是覆蓋父類中相應(yīng)的調(diào)度方法。當(dāng)控件被鼠標(biāo)單擊時,Click方法會被調(diào)用,我們將在Click中改變控件的開關(guān)狀態(tài);Paint方法則在用戶調(diào)用 Invalidate方法或控件發(fā)生重畫時調(diào)用,我們一般在這個方法繪制控件的圖案。(7)、TcustomControl中又很多事件處理句柄。比如OnClick、OnKeyDown等,但是它把他們聲明成了Protected保護級別,所以我們在Object Inspector中看不到他們,如果我們要他們可以在Object Inspector中被用
28、戶編輯的話,只要在Published中重新聲明他們即可,不用寫他們的讀寫方法,只要使用:Property 屬性名;這樣的方法就可以。比如這個例子中的:Property Onclick;思考題:1、 做一個有特效的按鈕控件,當(dāng)鼠標(biāo)按下時按鈕是一個紅色邊框的空心圓,當(dāng)鼠標(biāo)松開時按鈕是一個淡綠色邊框的空心圓。2、 對于父類控件中為protected的屬性,如果想將它在子類控件中公布,應(yīng)該怎么做?請思考Delphi為什么要將一些屬性設(shè)為protected級別?Delphi控件開發(fā)淺入深出(四)四、對特定字符串敏感的Edit控件 我們這個控件將演示控件的自定義事件的書寫。這個控件有一個類型為string
29、的SensitiveText屬性,當(dāng)用戶在輸入框中輸入的文字為InvalidText時就會觸發(fā)OnSensitiveText事件。按照慣例,我先把源碼展示給大家:unit TextSenseEdit;interfaceuses SysUtils, Classes, Controls, StdCtrls;type TSensitiveTextEvent = procedure(AText: string) of object;/方法指針 TTextSenseEdit = class(TEdit) private FSensitiveText: string; FOnSensitiveText:
30、TSensitiveTextEvent; procedure SetSensitiveText(AValue: string); protected procedure Change;override; public published property SensitiveText: string read FSensitiveText write SetSensitiveText; property OnSensitiveText: TSensitiveTextEvent read FOnSensitiveText write FOnSensitiveText; end;procedure
31、Register;implementationprocedure Register;begin RegisterComponents(Linco, TTextSenseEdit);end;procedure TTextSenseEdit.Change;begin inherited; if Text = SensitiveText then if Assigned(OnSensitiveText) then OnSensitiveText(Text);end;procedure TTextSenseEdit.SetSensitiveText(AValue: string);begin FSen
32、sitiveText := AValue;end;end.代碼解釋:(1)、SensitiveText屬性的添加方法大家已經(jīng)熟悉了,這里不多解釋。(2)、正如大家猜測的,Change方法正是編輯框文字發(fā)生變化時的調(diào)度方法,它將引起OnChange事件。我們可以在這個方法中監(jiān)控編輯框文字發(fā)生的變化,當(dāng)文字等于SensitiveText就觸發(fā)OnSensitiveText事件(具體的實現(xiàn)方法在后邊解釋)。(3)、Delphi中的控件的事件機制是通過方法指針來實現(xiàn)的。聲明方法指針的格式為:方法指針名稱 = procedure(參數(shù)列表) of object;聲明事件屬性的方法與聲明普通屬性的方法相同
33、。在我們這個例子中,我們首先聲明一個FOnSensitiveText: TSensitiveTextEvent;私有變量,然后property OnSensitiveText: TSensitiveTextEvent read FOnSensitiveText write FOnSensitiveText; 聲明事件屬性。這樣注冊控件后,當(dāng)用戶把控件放到窗體中后,就會在Object Inspector中Evnets頁中出現(xiàn)OnSensitiveText事件,我們就可以像使用其他事件一樣使用這個事件了。 但是我們現(xiàn)在只是聲明了一個事件屬性,并沒有書寫任何代碼來激發(fā)這個事件。我們應(yīng)該在合適的時候激
34、發(fā)此事件,顯而易見我們應(yīng)該在Change方法中激發(fā)此事件:procedure TTextSenseEdit.Change;begin inherited; if Text = SensitiveText then if Assigned(OnSensitiveText) then OnSensitiveText(Text);end;當(dāng)if Text = SensitiveText時就判斷控件使用者是否為OnSetSensitiveText寫代碼了(準(zhǔn)確的說是是否為OnSetSensitiveText事件句柄賦值了),如果寫代碼了則調(diào)用OnSetSensitiveText(Text);來激發(fā)On
35、SetSensitiveText事件,并把控件的Text傳遞給方法的Avalue參數(shù)。正如“方法指針”這個名字一樣,被聲明為方法指針類型的變量可以當(dāng)作方法使用,用來激發(fā)事件。VCL已經(jīng)為我們預(yù)定義了一些常用的事件句柄,我們直接拿來使用:TnotifyEvent,TmouseEvent,TmouseMoveEvent,TkeyPressEvent等,具體可以參考VCL源碼。思考題:1、做一個支持累加運算的文本編輯框控件,用戶可以在編輯框中輸入正整數(shù)。當(dāng)用戶按回車時,如果編輯框中輸入的不是正整數(shù)(為負數(shù)、小數(shù)或一般字符串)則觸發(fā)控件的OnError事件;如果輸入的是正整數(shù),則開始計算從1到用戶輸入
36、的那個正整數(shù)中所有整數(shù)的和(用123+這種累加的辦法實現(xiàn),不要用(1+n)*n/2這種直接計算的方法),并且在計算工程中如果發(fā)現(xiàn)計算的中間結(jié)果位數(shù)是5,則觸發(fā)OnTailFive事件。Delphi控件開發(fā)淺入深出(五)五、復(fù)合控件復(fù)合控件是Delphi控件中非常重要的一種控件,復(fù)合控件就是將兩個或兩個以上的控件重新組合成一個新的控件。例如TspinEdit、TlabeledEdit、TDBNavigator等就是復(fù)合控件,TDBNavigator其實就是在一個Panel放上若干個Button而已。制作一個復(fù)合控件時,我們一般從TwinControl派生控件。我們這次做的控件是擁有一個Edit編
37、輯框和一個Button按鈕的復(fù)合控件,在用戶在編輯框中輸入文字的過程中,Button將隨時顯示編輯框中文字的長度。我們把控件的源碼先展示給大家。unit EditButton;interfaceuses SysUtils, Classes, Controls, StdCtrls, Messages;type TEditButton = class(TWinControl) private FEdit: TEdit; FButton: TButton; FText: string; procedure FSetText(AValue: string); procedure OnEditChang
38、e(Sender: TObject); protected procedure WMSize(var Msg: TMessage);message WM_SIZE; public constructor Create(AOwner: TComponent);override; destructor Destroy;override; published property Text: string read FText write FSetText; end;procedure Register;implementationprocedure Register;begin RegisterCom
39、ponents(Linco, TEditButton);end;constructor TEditButton.Create(AOwner: TComponent);begin inherited; FEdit := TEdit.Create(nil); FEdit.Parent := self; FEdit.Top := 0; FEdit.Left := 0; FEdit.Height := Height; FEdit.Width := Width div 2; FEdit.OnChange := OnEditChange; FButton := TButton.Create(nil); F
40、Button.Parent := self; FButton.Top := 0; FButton.Left := Width div 2; FButton.Height := Height; FButton.Width := Width div 2;end;destructor TEditButton.Destroy;begin FEdit.Free; FButton.Free; inherited;end;procedure TEditButton.FSetText(AValue: string);begin FEdit.Text := AValue;end;procedure TEditB
41、utton.OnEditChange(Sender: TObject);begin FButton.Caption := IntToStr(Length(FEdit.Text);end;procedure TEditButton.WMSize(var Msg: TMessage);begin FEdit.Height := Height; FEdit.Width := Width div 2; FButton.Left := Width div 2; FButton.Height := Height; FButton.Width := Width div 2;end;end.代碼解釋:(1)、
42、我們首先定義了兩個變量 FEdit: TEdit; FButton: TButton; 分別代表復(fù)合控件中的文字編輯框和按鈕。(2)所謂復(fù)合控件說簡單一點就是在一個共同的基板上將組成復(fù)合控件的各個控件(可以叫做子控件)畫出來。所以我們在構(gòu)造函數(shù)中建立各個子控件,然后分別設(shè)定它們的位置等屬性。以文字編輯框為例:FEdit := TEdit.Create(nil);的作用是建立編輯框控件。如果Create的參數(shù)指定為nil,則子控件在設(shè)計狀態(tài)是可以響應(yīng)用戶的操作的;而如果設(shè)定為self(即設(shè)定子控件的父控件為基板),則子控件在設(shè)計時時不可響應(yīng)用戶操作的,如果設(shè)定為self則析構(gòu)函數(shù)中就不用Fedi
43、t.Free來銷毀對象了,對象會自動銷毀。 FEdit.Parent := self;的作用是設(shè)定子控件的父控件,如果沒有這一句則控件是無法顯示的。 FEdit.Top := 0; FEdit.Left := 0; FEdit.Height := Height; FEdit.Width := Width div 2;這四句是設(shè)定控件在基板上的相對位置的,這里的Top,Left不是相對于窗體的,而是相對于基板的。 FEdit.OnChange := OnEditChange;則是設(shè)定編輯框控件的OnChange(文字改變事件)的處理句柄為OnEditChange;(1) 用戶有可能在設(shè)計時或運行
44、時通過代碼改變控件的大小,這時控件中子控件的順序就會變得亂七八糟,所以需要相應(yīng)控件的WM_SIZE事件(控件大小發(fā)生變化的事件)重新設(shè)定子控件的位置,大小等。函數(shù)WMSize的作用就是這樣的。安裝控件后發(fā)現(xiàn)控件已經(jīng)可以正確運行了,但是還有一個問題,就是這個控件沒有了Onclick,Onchange等必須的屬性。我們只要為控件增加事件處理句柄屬性,然后把事件處理句柄屬性的讀寫方法都指向子控件的事件處理句柄屬性即可。例如我們?yōu)榭丶黾覱nClick事件,這個事件發(fā)生在用戶單擊按鈕時,我么只要在Pulished部分增加如下代碼:property OnClick: TnotifyEvent read
45、GetOnClick write SetOnClick在Private中增加如下方法聲明:function GetOnclick: TnotifyEvent;procedure SetOnclick(AValue: TnotifyEvent); 這兩個方法的實現(xiàn)分別為:function TeditButton. GetOnclick: TnotifyEvent;begin result := Fbutton.Onclick;end;procedure TeditButton. SetOnclick(AValue: TnotifyEvent); begin Fbutton.OnClick :=
46、Avalue;end;思考題:1、做一個模仿播放器中的操作按鈕的復(fù)合控件,控件由三個按鈕組成,分別是“播放”、“暫?!?、“停止”,請按照正常的邏輯關(guān)系,處理這三個按鈕的可用/不可用關(guān)系。(提示:可以參考TDBNavigator的源代碼)Delphi控件開發(fā)淺入深出(六)六、控件手拉手控件關(guān)聯(lián)的實現(xiàn)控件的關(guān)聯(lián)在Delphi中也是很常見的,我們可以設(shè)定一個控件的某個屬性指向另一個控件。比如我們在窗體上放上Tedit,TpopupMenu兩個控件,然后設(shè)定Tedit的PopupMenu屬性為TpopupMenu控件,運行后在Tedit點擊右鍵就會彈出剛才設(shè)定的那個TpopupMenu菜單,也就是說T
47、edit,TpopupMenu聯(lián)手完成了任務(wù)。再比如TDBEdit控件的DataSource屬性就可以指向一個TdataSource控件,這樣就可以在TDBEdit控件中顯示TdataSource輸出的某個字段的值了。 下面我們將寫一個簡單的實現(xiàn)控件關(guān)聯(lián)的控件。這個控件派生于Tedit,它可以與一個Tlabel控件關(guān)聯(lián),在控件的編輯框中輸入文字時,與它關(guān)聯(lián)的Tlabel控件的文字將隨著它而變化。代碼如下:unit MyEdit;interfaceuses SysUtils, Classes, Controls, StdCtrls;type TMyEdit = class(TEdit) priv
48、ate FLinkLabel: TLabel; procedure FSetLinkLabel(AValue: TLabel); protected procedure Notification(AComponent: TComponent;Operation: TOperation); override; procedure Change;override; public published property LinkLabel: TLabel read FLinkLabel write FSetLinkLabel; end;procedure Register;implementation
49、procedure Register;begin RegisterComponents(Linco, TMyEdit);end;procedure TMyEdit.Change;begin inherited; if LinkLabel nil then LinkLabel.Caption := Text;end;procedure TMyEdit.FSetLinkLabel(AValue: TLabel);begin FLinkLabel := AValue; if AValue nil then FLinkLabel.FreeNotification(self);end;procedure
50、 TMyEdit.Notification(AComponent: TComponent; Operation: TOperation);begin inherited; if (Operation = opRemove) and (AComponent = LinkLabel) then LinkLabel := nil;end;end.代碼解釋:(1)、我們只要將控件的任意一個屬性的類型設(shè)定為另外一個控件的類名稱,那么我們就可以在控件的Object Inspector中將這個屬性指向那個控件(或那個控件的派生控件)的一個實例。比如本例中我們增加了LinkLabel屬性,它的類型為 Tlab
51、el,所以我們就可以把LinkLabel屬性指向一個標(biāo)簽控件。(2)、請注意FsetLinkLabel中的這段代碼: if AValue nil thenFLinkLabel.FreeNotification(self);如果我們將控件關(guān)聯(lián)屬性指向了一個控件,可是后來又將被指向的控件刪除了,那么我們的控件關(guān)聯(lián)屬性是不會自動刪除的,這樣就會造成控件關(guān)聯(lián)屬性指向的控件不存在的現(xiàn)象。我們必須自動感知被關(guān)聯(lián)控件的刪除并重新設(shè)定控件關(guān)聯(lián)屬性為不指向任何控件,這樣就避免了錯誤的發(fā)生。FLinkLabel.FreeNotification(self);的作用就是這樣的。它調(diào)用控件的FreeNotificat
52、ion方法(在Tcomponent中定義)向被指向的控件注冊一個“消息”,當(dāng)被指向控件被刪除時,會向所有向他注冊的控件發(fā)送一個它被刪除的消息,此時向他注冊的控件就會觸發(fā)Notification方法,這樣我們就可以自動感知被指向控件的狀態(tài)了。這是設(shè)計模式中Observer(觀察者)模式的典型應(yīng)用。既然向他注冊的控件就會觸發(fā)Notification方法,我們就覆蓋父類的Notification方法,寫出如下的代碼: if (Operation = opRemove) and (AComponent = LinkLabel) then LinkLabel := nil;這句話的意思是:如果控件被刪除
53、并且被刪除的控件(因為我們的控件可能向多個控件注冊了消息)是LinkLabel,那么我們就設(shè)定LinkLabel屬性不指向任何控件。(3)覆蓋父類的Change調(diào)度方法。在此方法里為連接的LinkLabel的Caption賦值就達到我們的目的了。思考題:1、做一個Label控件,給它增加一個DataSource屬性,該屬性可以指向一個TdataSource類型的控件,它有一個GetRecordCount方法。當(dāng)調(diào)用此方法時,就在Label控件中顯示這個DataSource對應(yīng)的數(shù)據(jù)集中的記錄的條數(shù)。Delphi控件開發(fā)淺入深出(七)對話框控件的制作Delphi中有很多對話框組件,例如Topen
54、Dialog、TfontDialog等。這些控件的特點就是雖然是不可視控件,但是在運行時都有一個可視化的效果,比如TopenDialog的可視化效果就是一個打開對話框。我們這次將開發(fā)一個日期對話框控件,當(dāng)我們調(diào)用控件的Execute方法(不一定非要使用Execute方法,不過大部分對話框控件都是使用這個方法,我們也就按照慣例來了)時,就會彈出一個可以選擇日期的對話框,我們選擇一個日期后,點擊“確定”則Execute返回True,點擊“取消”則Execute返回False。我們可以讀取Date屬性來得到用戶選擇的日期,也可以修改此屬性來改變對話框的初始日期。1、新建一個對話框。在對話框窗體上放置一個TmonthCalendar組件,命名為Cal,窗體名稱改為FormDate。在窗體上放置兩個按鈕,一個按鈕的Caption為“確定(&O)”,ModalResult為mrOk,一個按鈕的Caption為“取消(&C)”,M
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二手車銷售質(zhì)量保證合同書
- 政府項目招標(biāo)與投標(biāo)操作手冊
- 分季度財務(wù)預(yù)算明細表
- 農(nóng)村農(nóng)業(yè)項目資金使用協(xié)議
- 基礎(chǔ)工作流程簡明教程與指南
- 員工辦公電腦使用說明書
- 理發(fā)師學(xué)徒專用合同
- 《數(shù)學(xué)函數(shù)圖像理解與問題解決》
- 企業(yè)戰(zhàn)略聯(lián)盟合作能力提升效果評估預(yù)案
- 汽車股份轉(zhuǎn)讓合同
- 2025山東青島市屬事業(yè)單位公開招聘筆試和高頻重點提升(共500題)附帶答案詳解
- 臨床護理死亡病例討論
- 《奢香夫人》歌詞(男女聲歌詞標(biāo)注)
- 2025年廣東韶關(guān)城投集團招聘筆試參考題庫含答案解析
- iso28000-2022供應(yīng)鏈安全管理手冊程序文件表單一整套
- 養(yǎng)老院敬老院福利醫(yī)養(yǎng)機構(gòu)消防知識培訓(xùn)科普講座教學(xué)課件
- 商業(yè)辦公樓網(wǎng)絡(luò)改造施工方案
- 子癇診斷及治療
- 2025屆海南省??谑忻8呖加⒄Z二模試卷含解析
- 《中醫(yī)美容》課件
- 2023年高考真題-歷史(遼寧卷) 含解析
評論
0/150
提交評論