三、開關(guān)控件TlincoSwitch
用過Delphi1(好古老的東東呀?。┑娜讼嘈哦加浀眠@個開關(guān)控件
1、建立位圖資源文件:
用Image Editor建立一個Res文件,并在文件中分別建立下面兩個位圖,并分別命名為SWITCHON、SWITCHOFF。保存此Res到控件單元所在目錄下。
2、寫控件代碼。
unit LincoSwitch;
interface
uses
? 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;override;
??? 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;
??? property OnMouseDown;
??? property OnMouseMove;
??? property OnMouseUp;
??? property OnMouseWheel;
??? property OnResize;
? end;
?
procedure Register;
implementation
{$R *.res}
procedure LoadBitmapFromRes(ABitmapId: string; ABitmap: Graphics.TBitmap);
begin
? ABitmap.LoadFromResourceName(hInstance, ABitmapId);//從資源文件中讀取位圖
end;
?
constructor 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.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)
? else
????? StretchBlt(Canvas.Handle, 0, 0, self.Width, self.Height, FPicOff.Canvas.Handle,
???????????? 0, 0, FPicOff.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在控件表面作圖。不選用Tcontrol的原因是因為它有很多我們不需要的屬性。
(2)、ABitmap.LoadFromResourceName(hInstance, ABitmapId);是從資源文件中讀取Id為AbitmapId的位圖,關(guān)于資源文件的使用請參考其他相關(guān)資料。注意代碼中的“{$R *.res}”,它的作用是將資源文件編譯到程序文件中,如果沒有這個預(yù)編譯條件,程序?qū)霈F(xiàn)錯誤。
(3)、StretchBlt是將位圖畫到畫板上,使用方法請參考MSDN。
(4)、我們?yōu)榭丶黾恿?/SPAN>IsOn屬性。這個布爾屬性用來表示開關(guān)的狀態(tài)(開/關(guān))。
從property IsOn: Boolean read FIsOn write FSetIsOn;我們可以看出這個屬性是個可讀可寫的屬性。當(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)的圖案。
(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保護(hù)級別,所以我們在Object Inspector中看不到他們,如果我們要他們可以在Object Inspector中被用戶編輯的話,只要在Published中重新聲明他們即可,不用寫他們的讀寫方法,只要使用:Property? 屬性名;
這樣的方法就可以。比如這個例子中的:Property Onclick;
思考題:
1、??????? 做一個有特效的按鈕控件,當(dāng)鼠標(biāo)按下時按鈕是一個紅色邊框的空心圓,當(dāng)鼠標(biāo)松開時按鈕是一個淡綠色邊框的空心圓。
2、??????? 對于父類控件中為protected的屬性,如果想將它在子類控件中公布,應(yīng)該怎么做?請思考Delphi為什么要將一些屬性設(shè)為protected級別?