好久没有来了,今天终于有时间了,可以来写写关于控件开发的文章了。
今天我以我4年前写的一个小控件为例写一下如何开发控件的方法。
这个控件实现后的效果可见附件1。
首先我们继承自TCustomControl一个类TKindSpinEdit。因为类TCustomControl中有Canvas属性,利用这个属性我们可以来绘制我们需要的图像。
今天我以我4年前写的一个小控件为例写一下如何开发控件的方法。
这个控件实现后的效果可见附件1。
首先我们继承自TCustomControl一个类TKindSpinEdit。因为类TCustomControl中有Canvas属性,利用这个属性我们可以来绘制我们需要的图像。
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;
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中的属性给吓住,其实里面很多都是继承自TCustomControl类的。只有少量的属性会对我们编写这个控件产生影响,所以才自己定义,例如:
property MaxValue;
property MinValue;
这两个属性就是用来设置最大值和最小值的。
property Value;属性是用来记录当前的值的。
property BorderColor;属性是用来确定绘制边框的时候使用的颜色的。
property DrawColor;属性是用来确定填充“-”和“+”内容是使用的颜色的。
property ClickColor:属性是用来确定您点击的时候绘制“-”和“+”的内容颜色。
property MaxValue;
property MinValue;
这两个属性就是用来设置最大值和最小值的。
property Value;属性是用来记录当前的值的。
property BorderColor;属性是用来确定绘制边框的时候使用的颜色的。
property DrawColor;属性是用来确定填充“-”和“+”内容是使用的颜色的。
property ClickColor:属性是用来确定您点击的时候绘制“-”和“+”的内容颜色。
下来我们要截获两个消息,一个是鼠标点击消息一个是鼠标离开消息,及CM_MOUSEENTER消息和CM_MOUSELEAVE消息。如果有这两个消息的时候我们则对我们的控件
进行重新绘制。因为TCustomControl类已经实现了绘制函数,所以我们需要重载一下procedure Paint;override;在重载的Paint函数中我们需要绘制这个控件
的边框,左区域,右区域和中心区域。一下是Paint函数的内容:
procedure TKindSpinEdit.Paint;
var
R:TRect;
begin
R:=ClientRect;
Frame3D(Canvas,R,FBorderColor,FBorderColor,1);
//绘制边框
DrawBorder;
//绘制左框
DrawLeft;
//绘制右框
DrawRight;
//绘制中间
DrawCenter;
inherited;
end;
进行重新绘制。因为TCustomControl类已经实现了绘制函数,所以我们需要重载一下procedure Paint;override;在重载的Paint函数中我们需要绘制这个控件
的边框,左区域,右区域和中心区域。一下是Paint函数的内容:
procedure TKindSpinEdit.Paint;
var
R:TRect;
begin
R:=ClientRect;
Frame3D(Canvas,R,FBorderColor,FBorderColor,1);
//绘制边框
DrawBorder;
//绘制左框
DrawLeft;
//绘制右框
DrawRight;
//绘制中间
DrawCenter;
inherited;
end;
函数DrawBorder;是用来绘制边框的,具体的实现是:
procedure TKindSpinEdit.DrawCenter;
var
TextW,TextH:Integer;
Cap:String;
R:TRect;
begin
with Canvas do
begin
//绘制横向中间边框
Brush.Style:=bsClear;
R:=ClientRect; //设置绘制的区域
Brush.Color:=Color; //设置绘制的颜色
FillRect(EditRect); //向绘制区域中绘制颜色
Cap:=IntToStr(FValue);
//计算当前值应该书写的位置
TextW:=((EditRect.Right-EditRect.Left-Canvas.TextWidth(Cap)) div 2)+EditRect.Left;
TextH:=((EditRect.Bottom-EditRect.Top-Canvas.TextHeight(Cap)) div 2)+EditRect.Top;
//将当前值写入相应的位置
TextOut(TextW,TextH,Cap);
end;
end;
函数DrawLeft是用来绘制左区域,具体的实现是:
procedure TKindSpinEdit.DrawLeft;
var
OldWidth:Integer;
X,Y,X1,Y1:Integer;
begin
{首先根据不同的显示效果得到左区域,右区域和中心书写当前值的区域}
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
{根据当前状态(是鼠标点击下去还是鼠标放开)来绘制}
if FFlag then
begin
//绘制点击时的状态
Brush.Color:=FDrawColor; //设置画刷颜色
FillRect(LeftR); //填充左区域
Pen.Color:=FClickColor; //设置画笔颜色
Pen.Width:=1; //设置画笔宽度
Rectangle(LeftR); //用画笔绘制边框
Pen.Color:=FClickColor; //设置点击后的画笔颜色
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;
{绘制减号}
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
//绘制非点击时的状态
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;
剩余的绘制右区域和绘制中间区域的仿佛类似。
在我的代码中我定义了一个变量FFlag,这个变量是用来标志鼠标是否按下的。当鼠标按下和鼠标放开的时候绘制的仿佛是不同的。
在我的代码中我定义了一个变量FFlag,这个变量是用来标志鼠标是否按下的。当鼠标按下和鼠标放开的时候绘制的仿佛是不同的。
变量FWayStyle是用来定义这个控件的显示方式。twsHorizontal是横向显示,twsVertical是纵向显示。
现在这个控件已经绘制成功了,可是当点击“-”或者“+”的时候怎么样让值变化呢?
这需要对鼠标点击时间和鼠标放开事件进行处理
procedure TKindSpinEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if Button=mbLeft then //判断是否是左键点击
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 //判断是否点击的是左区域
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 //判断是否点击的是右区域
begin
FClick:=2;
MathValue;
DrawCenter;
DrawRight;
FTimer.OnTimer:=OnTimer;
end;
end;
inherited;
end;
这需要对鼠标点击时间和鼠标放开事件进行处理
procedure TKindSpinEdit.MouseDown(Button: TMouseButton; Shift: TShiftState;
X, Y: Integer);
begin
if Button=mbLeft then //判断是否是左键点击
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 //判断是否点击的是左区域
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 //判断是否点击的是右区域
begin
FClick:=2;
MathValue;
DrawCenter;
DrawRight;
FTimer.OnTimer:=OnTimer;
end;
end;
inherited;
end;
同时我在这个控件中定义了一个始终FTimer。用来处理用户一直点击鼠标的情况。
下面是我写的完整代码。如果还有不清楚的地方,可以给我留言!
附件:http://down.51cto.com/data/2347758
本文转自狗窝博客51CTO博客,原文链接http://blog.51cto.com/fxh7622/20513如需转载请自行联系原作者
fxh7622