使用DELPHI编写一个小的控件
生活随笔
收集整理的這篇文章主要介紹了
使用DELPHI编写一个小的控件
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
好久沒有來了,今天終于有時(shí)間了,可以來寫寫關(guān)于控件開發(fā)的文章了。
????????? 今天我以我4年前寫的一個(gè)小控件為例寫一下如何開發(fā)控件的方法。
????????? 這個(gè)控件實(shí)現(xiàn)后的效果可見附件1。
????????? 首先我們繼承自TCustomControl一個(gè)類TKindSpinEdit。因?yàn)轭怲CustomControl中有Canvas屬性,利用這個(gè)屬性我們可以來繪制我們需要的圖像。 TKindSpinEdit = class(TCustomControl)
? private
??? .....
? protected
??? { Protected declarations }
??? procedure Change; dynamic;
? public
??? { Public declarations }
??? procedure Paint;override;
??? constructor Create (AOwner: TComponent); override;
??? destructor Destroy; override;
? published
??? property MaxValue:Integer read FMaxValue write SetMaxValue;
??? property MinValue:Integer read FMinValue write SetMinValue;
??? property Value:Integer read FValue write SetValue;
??? property BorderColor:TCOlor read FBorderColor write SetBorderColor;
??? property DrawColor:TColor read FDrawColor write SetDrawColor;
??? property Color;
??? property Font:TFont read FFont write SetFont;
??? property ClickColor:TColor read FClickColor write SetClickColor;
??? property Step:Integer read FStep write SetStep;
??? property WayStyle:TWayStyle read FWayStyle write SetWayStyle;
??? property Width;
??? property Height;
??? property OnChange: TNotifyEvent read FOnChange write FOnChange;
??? property OnClick;
??? property OnContextPopup;
??? property OnDblClick;
??? property OnDragDrop;
??? property OnDockDrop;
??? property OnDockOver;
??? property OnDragOver;
??? property OnEndDock;
??? property OnEndDrag;
??? property OnEnter;
??? property OnExit;
??? property OnGetSiteInfo;
??? property OnMouseDown;
??? property OnMouseMove;
??? property OnMouseUp;
??? property OnStartDock;
??? property OnStartDrag;
??? property OnUnDock;
? end; 不要被published中的屬性給嚇住,其實(shí)里面很多都是繼承自TCustomControl類的。只有少量的屬性會(huì)對(duì)我們編寫這個(gè)控件產(chǎn)生影響,所以才自己定義,例如:
?? property MaxValue;
??? property MinValue;
這兩個(gè)屬性就是用來設(shè)置最大值和最小值的。
property Value;屬性是用來記錄當(dāng)前的值的。
property BorderColor;屬性是用來確定繪制邊框的時(shí)候使用的顏色的。
property DrawColor;屬性是用來確定填充“-”和“+”內(nèi)容是使用的顏色的。
property ClickColor:屬性是用來確定您點(diǎn)擊的時(shí)候繪制“-”和“+”的內(nèi)容顏色。 下來我們要截獲兩個(gè)消息,一個(gè)是鼠標(biāo)點(diǎn)擊消息一個(gè)是鼠標(biāo)離開消息,及CM_MOUSEENTER消息和CM_MOUSELEAVE消息。如果有這兩個(gè)消息的時(shí)候我們則對(duì)我們的控件
進(jìn)行重新繪制。因?yàn)門CustomControl類已經(jīng)實(shí)現(xiàn)了繪制函數(shù),所以我們需要重載一下procedure Paint;override;在重載的Paint函數(shù)中我們需要繪制這個(gè)控件
的邊框,左區(qū)域,右區(qū)域和中心區(qū)域。一下是Paint函數(shù)的內(nèi)容:
procedure TKindSpinEdit.Paint;
var
? R:TRect;
begin
? R:=ClientRect;
? Frame3D(Canvas,R,FBorderColor,FBorderColor,1);
? //繪制邊框
? DrawBorder;
? //繪制左框
? DrawLeft;
? //繪制右框
? DrawRight;
? //繪制中間
? DrawCenter;
? inherited;
end;
函數(shù)DrawBorder;是用來繪制邊框的,具體的實(shí)現(xiàn)是:
procedure TKindSpinEdit.DrawCenter;
var
?? TextW,TextH:Integer;
?? Cap:String;
?? R:TRect;
begin
??? with Canvas do
??? begin
?????????? //繪制橫向中間邊框
?????????? Brush.Style:=bsClear;
?????????? R:=ClientRect;?//設(shè)置繪制的區(qū)域
?????????? Brush.Color:=Color;?//設(shè)置繪制的顏色
?????????? FillRect(EditRect);?//向繪制區(qū)域中繪制顏色
?????????? Cap:=IntToStr(FValue);
??? //計(jì)算當(dāng)前值應(yīng)該書寫的位置
?????????? TextW:=((EditRect.Right-EditRect.Left-Canvas.TextWidth(Cap)) div 2)+EditRect.Left;
?????????? TextH:=((EditRect.Bottom-EditRect.Top-Canvas.TextHeight(Cap)) div 2)+EditRect.Top;
??? //將當(dāng)前值寫入相應(yīng)的位置
?????????? TextOut(TextW,TextH,Cap);
??? end; end;
函數(shù)DrawLeft是用來繪制左區(qū)域,具體的實(shí)現(xiàn)是:
procedure TKindSpinEdit.DrawLeft;
var
?? OldWidth:Integer;
?? X,Y,X1,Y1:Integer;
begin
?? {首先根據(jù)不同的顯示效果得到左區(qū)域,右區(qū)域和中心書寫當(dāng)前值的區(qū)域}
?? case FWayStyle of
?? twsHorizontal:
?? begin
?????? LeftR:=ClientRect;
?????? LeftR.Right:=LeftR.Left+17;
?????? RightR:=ClientRect;
?????? RightR.Left:=RightR.Right-17;
?????? EditRect.Top:=ClientRect.Top+1;
?????? EditRect.Bottom:=ClientRect.Bottom-1;
?????? EditRect.Left:=LeftR.Right+1;
?????? EditRect.Right:=RightR.Left-1;
?? end;
?? twsVertical:
?? begin
?????? RightR:=ClientRect;
?????? RightR.Bottom:=RightR.Top+17;
?????? LeftR:=ClientRect;
?????? LeftR.Top:=LeftR.Bottom-17;
?????? EditRect.Top:=RightR.Bottom+1;
?????? EditRect.Bottom:=LeftR.Top-1;
?????? EditRect.Left:=LeftR.Left+1;
?????? EditRect.Right:=LeftR.Right-1;
?? end;
?? end;
??
?? with Canvas do
?? begin
?????? {根據(jù)當(dāng)前狀態(tài)(是鼠標(biāo)點(diǎn)擊下去還是鼠標(biāo)放開)來繪制}
?????? if FFlag then
?????? begin
???????? //繪制點(diǎn)擊時(shí)的狀態(tài)
????????? Brush.Color:=FDrawColor;?//設(shè)置畫刷顏色
????????? FillRect(LeftR);??//填充左區(qū)域
????????? Pen.Color:=FClickColor;?//設(shè)置畫筆顏色
????????? Pen.Width:=1;???//設(shè)置畫筆寬度
????????? Rectangle(LeftR);??//用畫筆繪制邊框
????????? Pen.Color:=FClickColor;?//設(shè)置點(diǎn)擊后的畫筆顏色
????????? Pen.Width:=1;
????????? X:= LeftR.Left+4;
????????? X1:=LeftR.Right-4;
????????? Y:=((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top;
????????? Y1:=((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top;
?? {繪制減號(hào)}
????????? Moveto(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left ,((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top);
????????? LineTo(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left+8,((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top);
?????? end
?????? else
?????? begin
???????? //繪制非點(diǎn)擊時(shí)的狀態(tài)
?? Brush.Color:=FDrawColor;
????????? FillRect(LeftR);
????????? Pen.Color:=FBorderColor;
????????? Pen.Width:=1;
????????? Rectangle(LeftR);
????????? Pen.Color:=FBorderColor;
????????? Pen.Width:=1;
????????? Moveto(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left,((LeftR.Bottom-LeftR.Top) div 2)+LeftR.Top);
????????? LineTo(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left+8,((LeftR.Bottom-LeftR.Top) div 2)+LeftR.Top);
?????? end; end; end; 剩余的繪制右區(qū)域和繪制中間區(qū)域的仿佛類似。
?
在我的代碼中我定義了一個(gè)變量FFlag,這個(gè)變量是用來標(biāo)志鼠標(biāo)是否按下的。當(dāng)鼠標(biāo)按下和鼠標(biāo)放開的時(shí)候繪制的仿佛是不同的。 變量FWayStyle是用來定義這個(gè)控件的顯示方式。twsHorizontal是橫向顯示,twsVertical是縱向顯示。 現(xiàn)在這個(gè)控件已經(jīng)繪制成功了,可是當(dāng)點(diǎn)擊“-”或者“+”的時(shí)候怎么樣讓值變化呢?
這需要對(duì)鼠標(biāo)點(diǎn)擊時(shí)間和鼠標(biāo)放開事件進(jìn)行處理
procedure TKindSpinEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
? X, Y: Integer);
begin
? if Button=mbLeft then????//判斷是否是左鍵點(diǎn)擊
? begin
????? I:=0;
????? FFlag:=true;
????? FTimer.Enabled:=true;
????? if(x>=LeftR.Left) and (x<=LeftR.Right) and (y>=LeftR.Top) and (y<=LeftR.Bottom) then??//判斷是否點(diǎn)擊的是左區(qū)域
????? begin
????????? FClick:=1;
????????? MathValue;
????????? DrawCenter;
????????? DrawLeft;
????????? FTimer.OnTimer:=OnTimer;
????? end;
????? if(x>=RightR.Left) and (x<=RightR.Right) and (y>=RightR.Top) and (y<=RightR.Bottom) then?//判斷是否點(diǎn)擊的是右區(qū)域
????? begin
????????? FClick:=2;
????????? MathValue;
????????? DrawCenter;
????????? DrawRight;
????????? FTimer.OnTimer:=OnTimer;
????? end;
? end;
? inherited;
end; 同時(shí)我在這個(gè)控件中定義了一個(gè)始終FTimer。用來處理用戶一直點(diǎn)擊鼠標(biāo)的情況。 下面是我寫的完整代碼。如果還有不清楚的地方,可以給我留言!
? 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
????????? 今天我以我4年前寫的一個(gè)小控件為例寫一下如何開發(fā)控件的方法。
????????? 這個(gè)控件實(shí)現(xiàn)后的效果可見附件1。
????????? 首先我們繼承自TCustomControl一個(gè)類TKindSpinEdit。因?yàn)轭怲CustomControl中有Canvas屬性,利用這個(gè)屬性我們可以來繪制我們需要的圖像。 TKindSpinEdit = class(TCustomControl)
? private
??? .....
? protected
??? { Protected declarations }
??? procedure Change; dynamic;
? public
??? { Public declarations }
??? procedure Paint;override;
??? constructor Create (AOwner: TComponent); override;
??? destructor Destroy; override;
? published
??? property MaxValue:Integer read FMaxValue write SetMaxValue;
??? property MinValue:Integer read FMinValue write SetMinValue;
??? property Value:Integer read FValue write SetValue;
??? property BorderColor:TCOlor read FBorderColor write SetBorderColor;
??? property DrawColor:TColor read FDrawColor write SetDrawColor;
??? property Color;
??? property Font:TFont read FFont write SetFont;
??? property ClickColor:TColor read FClickColor write SetClickColor;
??? property Step:Integer read FStep write SetStep;
??? property WayStyle:TWayStyle read FWayStyle write SetWayStyle;
??? property Width;
??? property Height;
??? property OnChange: TNotifyEvent read FOnChange write FOnChange;
??? property OnClick;
??? property OnContextPopup;
??? property OnDblClick;
??? property OnDragDrop;
??? property OnDockDrop;
??? property OnDockOver;
??? property OnDragOver;
??? property OnEndDock;
??? property OnEndDrag;
??? property OnEnter;
??? property OnExit;
??? property OnGetSiteInfo;
??? property OnMouseDown;
??? property OnMouseMove;
??? property OnMouseUp;
??? property OnStartDock;
??? property OnStartDrag;
??? property OnUnDock;
? end; 不要被published中的屬性給嚇住,其實(shí)里面很多都是繼承自TCustomControl類的。只有少量的屬性會(huì)對(duì)我們編寫這個(gè)控件產(chǎn)生影響,所以才自己定義,例如:
?? property MaxValue;
??? property MinValue;
這兩個(gè)屬性就是用來設(shè)置最大值和最小值的。
property Value;屬性是用來記錄當(dāng)前的值的。
property BorderColor;屬性是用來確定繪制邊框的時(shí)候使用的顏色的。
property DrawColor;屬性是用來確定填充“-”和“+”內(nèi)容是使用的顏色的。
property ClickColor:屬性是用來確定您點(diǎn)擊的時(shí)候繪制“-”和“+”的內(nèi)容顏色。 下來我們要截獲兩個(gè)消息,一個(gè)是鼠標(biāo)點(diǎn)擊消息一個(gè)是鼠標(biāo)離開消息,及CM_MOUSEENTER消息和CM_MOUSELEAVE消息。如果有這兩個(gè)消息的時(shí)候我們則對(duì)我們的控件
進(jìn)行重新繪制。因?yàn)門CustomControl類已經(jīng)實(shí)現(xiàn)了繪制函數(shù),所以我們需要重載一下procedure Paint;override;在重載的Paint函數(shù)中我們需要繪制這個(gè)控件
的邊框,左區(qū)域,右區(qū)域和中心區(qū)域。一下是Paint函數(shù)的內(nèi)容:
procedure TKindSpinEdit.Paint;
var
? R:TRect;
begin
? R:=ClientRect;
? Frame3D(Canvas,R,FBorderColor,FBorderColor,1);
? //繪制邊框
? DrawBorder;
? //繪制左框
? DrawLeft;
? //繪制右框
? DrawRight;
? //繪制中間
? DrawCenter;
? inherited;
end;
函數(shù)DrawBorder;是用來繪制邊框的,具體的實(shí)現(xiàn)是:
procedure TKindSpinEdit.DrawCenter;
var
?? TextW,TextH:Integer;
?? Cap:String;
?? R:TRect;
begin
??? with Canvas do
??? begin
?????????? //繪制橫向中間邊框
?????????? Brush.Style:=bsClear;
?????????? R:=ClientRect;?//設(shè)置繪制的區(qū)域
?????????? Brush.Color:=Color;?//設(shè)置繪制的顏色
?????????? FillRect(EditRect);?//向繪制區(qū)域中繪制顏色
?????????? Cap:=IntToStr(FValue);
??? //計(jì)算當(dāng)前值應(yīng)該書寫的位置
?????????? TextW:=((EditRect.Right-EditRect.Left-Canvas.TextWidth(Cap)) div 2)+EditRect.Left;
?????????? TextH:=((EditRect.Bottom-EditRect.Top-Canvas.TextHeight(Cap)) div 2)+EditRect.Top;
??? //將當(dāng)前值寫入相應(yīng)的位置
?????????? TextOut(TextW,TextH,Cap);
??? end; end;
函數(shù)DrawLeft是用來繪制左區(qū)域,具體的實(shí)現(xiàn)是:
procedure TKindSpinEdit.DrawLeft;
var
?? OldWidth:Integer;
?? X,Y,X1,Y1:Integer;
begin
?? {首先根據(jù)不同的顯示效果得到左區(qū)域,右區(qū)域和中心書寫當(dāng)前值的區(qū)域}
?? case FWayStyle of
?? twsHorizontal:
?? begin
?????? LeftR:=ClientRect;
?????? LeftR.Right:=LeftR.Left+17;
?????? RightR:=ClientRect;
?????? RightR.Left:=RightR.Right-17;
?????? EditRect.Top:=ClientRect.Top+1;
?????? EditRect.Bottom:=ClientRect.Bottom-1;
?????? EditRect.Left:=LeftR.Right+1;
?????? EditRect.Right:=RightR.Left-1;
?? end;
?? twsVertical:
?? begin
?????? RightR:=ClientRect;
?????? RightR.Bottom:=RightR.Top+17;
?????? LeftR:=ClientRect;
?????? LeftR.Top:=LeftR.Bottom-17;
?????? EditRect.Top:=RightR.Bottom+1;
?????? EditRect.Bottom:=LeftR.Top-1;
?????? EditRect.Left:=LeftR.Left+1;
?????? EditRect.Right:=LeftR.Right-1;
?? end;
?? end;
??
?? with Canvas do
?? begin
?????? {根據(jù)當(dāng)前狀態(tài)(是鼠標(biāo)點(diǎn)擊下去還是鼠標(biāo)放開)來繪制}
?????? if FFlag then
?????? begin
???????? //繪制點(diǎn)擊時(shí)的狀態(tài)
????????? Brush.Color:=FDrawColor;?//設(shè)置畫刷顏色
????????? FillRect(LeftR);??//填充左區(qū)域
????????? Pen.Color:=FClickColor;?//設(shè)置畫筆顏色
????????? Pen.Width:=1;???//設(shè)置畫筆寬度
????????? Rectangle(LeftR);??//用畫筆繪制邊框
????????? Pen.Color:=FClickColor;?//設(shè)置點(diǎn)擊后的畫筆顏色
????????? Pen.Width:=1;
????????? X:= LeftR.Left+4;
????????? X1:=LeftR.Right-4;
????????? Y:=((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top;
????????? Y1:=((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top;
?? {繪制減號(hào)}
????????? Moveto(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left ,((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top);
????????? LineTo(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left+8,((LeftR.Bottom-LeftR.Top) div 2)+1+LeftR.Top);
?????? end
?????? else
?????? begin
???????? //繪制非點(diǎn)擊時(shí)的狀態(tài)
?? Brush.Color:=FDrawColor;
????????? FillRect(LeftR);
????????? Pen.Color:=FBorderColor;
????????? Pen.Width:=1;
????????? Rectangle(LeftR);
????????? Pen.Color:=FBorderColor;
????????? Pen.Width:=1;
????????? Moveto(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left,((LeftR.Bottom-LeftR.Top) div 2)+LeftR.Top);
????????? LineTo(((LeftR.Right-LeftR.Left-8) div 2)+LeftR.Left+8,((LeftR.Bottom-LeftR.Top) div 2)+LeftR.Top);
?????? end; end; end; 剩余的繪制右區(qū)域和繪制中間區(qū)域的仿佛類似。
?
在我的代碼中我定義了一個(gè)變量FFlag,這個(gè)變量是用來標(biāo)志鼠標(biāo)是否按下的。當(dāng)鼠標(biāo)按下和鼠標(biāo)放開的時(shí)候繪制的仿佛是不同的。 變量FWayStyle是用來定義這個(gè)控件的顯示方式。twsHorizontal是橫向顯示,twsVertical是縱向顯示。 現(xiàn)在這個(gè)控件已經(jīng)繪制成功了,可是當(dāng)點(diǎn)擊“-”或者“+”的時(shí)候怎么樣讓值變化呢?
這需要對(duì)鼠標(biāo)點(diǎn)擊時(shí)間和鼠標(biāo)放開事件進(jìn)行處理
procedure TKindSpinEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
? X, Y: Integer);
begin
? if Button=mbLeft then????//判斷是否是左鍵點(diǎn)擊
? begin
????? I:=0;
????? FFlag:=true;
????? FTimer.Enabled:=true;
????? if(x>=LeftR.Left) and (x<=LeftR.Right) and (y>=LeftR.Top) and (y<=LeftR.Bottom) then??//判斷是否點(diǎn)擊的是左區(qū)域
????? begin
????????? FClick:=1;
????????? MathValue;
????????? DrawCenter;
????????? DrawLeft;
????????? FTimer.OnTimer:=OnTimer;
????? end;
????? if(x>=RightR.Left) and (x<=RightR.Right) and (y>=RightR.Top) and (y<=RightR.Bottom) then?//判斷是否點(diǎn)擊的是右區(qū)域
????? begin
????????? FClick:=2;
????????? MathValue;
????????? DrawCenter;
????????? DrawRight;
????????? FTimer.OnTimer:=OnTimer;
????? end;
? end;
? inherited;
end; 同時(shí)我在這個(gè)控件中定義了一個(gè)始終FTimer。用來處理用戶一直點(diǎn)擊鼠標(biāo)的情況。 下面是我寫的完整代碼。如果還有不清楚的地方,可以給我留言!
? 《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀
總結(jié)
以上是生活随笔為你收集整理的使用DELPHI编写一个小的控件的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 终于可以回家了!
- 下一篇: 在ASP.NET AJAX 1.0框架中