好久没有来了,今天终于有时间了,可以来写写关于控件开发的文章了。
          今天我以我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;
不要被published中的属性给吓住,其实里面很多都是继承自TCustomControl类的。只有少量的属性会对我们编写这个控件产生影响,所以才自己定义,例如:
   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;

函数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,这个变量是用来标志鼠标是否按下的。当鼠标按下和鼠标放开的时候绘制的仿佛是不同的。
变量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;
同时我在这个控件中定义了一个始终FTimer。用来处理用户一直点击鼠标的情况。
下面是我写的完整代码。如果还有不清楚的地方,可以给我留言!