组件制作之三(图形控件)

2016-02-19 12:50 9 1 收藏

关注图老师设计创意栏目可以让大家能更好的了解电脑,知道有关于电脑的更多有趣教程,今天给大家分享组件制作之三(图形控件)教程,希望对大家能有一点小小的帮助。

【 tulaoshi.com - 编程语言 】

VCL中的Shape是个很不错的控件,可以选择几种图形,以满足我们的需求,但有时候就是觉得它的可选图形少了一点,比如我们想要一个三角形,它却没有。于是就想到来扩展一下这个控件,名为ShapeEx。其实扩展的功能不多,只是增加了一些图形。而类也并不是继承自TShape,而是继承自TGraphicControl,这样可以让我们彻底看看图形控件的做法。Tshape也是继承自TGraphicControl。而我们的扩展控件功能是基于Shape的扩展,所以当然里面的代码几乎取之TShape,只是加了一些扩展图形的代码,但又有什么关系呢,VCL源码是最好的学习资源,我们何不取之用之。
  
   
  
  很多东西我们已经在上面说过了,这里不多说了,我要直入图形控件的重点。图形控件不是封装Windows的控件,而是Delphi自己画出来的,那么它肯定有一个画控件的函数。这个函数就是:
  
  Paint;
  
   看一下VCL源码,可以知道它定义在TGraphicControl。中:
  
   procedure Paint; virtual; 
  
  这是一个虚函数,那么它的实现是怎么样的呢,点击看它的实现如下:
  
  procedure TGraphicControl.Paint;
  
  begin
  
  end;
  
  里面什么码也没有,这个很容易理解,因为它不可能知道他的子类的图形是什么样子的。所以设为虚函数,由它的子类来覆盖它。
  
   
  
  那么是谁调用了这个函数来引起画控件呢。Windows有一个WM_PAINT;消息,当一切引起重画的条件发生,则会发送这条消息,再看看TGraphicControl,果然有截获这个消息:
  
  procedure WMPaint(var Message: TWMPaint); message WM_PAINT;
  
  在处理函数里面,调用了Paint方法,从而实现了画图形控件可能:
  
  procedure TGraphicControl.WMPaint(var Message: TWMPaint);
  
  begin
  
    if Message.DC  0 then
  
    begin
  
      Canvas.Lock;
  
      try
  
        Canvas.Handle := Message.DC;
  
        try
  
          Paint;   //调用了这个函数来画图形控件
  
        finally
  
          Canvas.Handle := 0;
  
        end;
  
      finally
  
        Canvas.Unlock;
  
      end;
  
    end;
  
  end;
  
  而它的子类覆盖了Paint函数,所以消息处理函数调用的实际上是某个子类的Paint方法,这个就是多态的应用了,这里不多说。
  
   
  
  既然Paint函数可以画图形控件,那么它是以什么来画的呢,VCL有一个Canvas类,它就是用这个来画的,在TGraphicControl果然也定义了这个成员:
  
  FCanvas: TCanvas;
  
  property Canvas: TCanvas read FCanvas;
  
  可以看出这是一个只读的成员,因为它不想外界来影响他。
  
   
  
  好了,一切已经具备了,现在就可以画上去了。源代码有详细解释,这里不多说。
  
   
  
  在ShapeEx中有两个对象属性,为Pen和Brush。对应于他的两个对象成员。设置了这两个属性之后,在对象察看器中就可以展开他们来设置他们的属性了。这个也是对象属性的一般用法。
  
   
  
  似乎没有什么可说的了,下面看源代码吧,其中也有很详细的说明:
  
  unit shapeExUnit;
  
   
  
  interface
  
  uses
  
    SysUtils,Classes,Graphics,Controls,ExtCtrls;
  
   
  
  type
  
  //定义了几种形状:矩形,正方形,圆角矩形,圆角正方形,椭圆形,圆形,
  
  //增加的图形:横线,坚线,上三角形,菱形
  
   TShapeType = (stRectangle, stSquare, stRoundRect, stRoundSquare,
  
      stEllipse, stCircle,stHLine,stVLine,stTriangle,stDiamond);
  
   
  
    TShapeEx = class(TGraphicControl)
  
    private
  
      FPen: TPen;
  
      FBrush: TBrush;
  
      FShape: TShapeType;
  
      procedure SetBrush(Value: TBrush);
  
      procedure SetPen(Value: TPen);
  
      procedure SetShape(Value: TShapeType);
  
    protected
  
    //最重要的函数,在父类TGraphicControl中定义的一个
  
    //虚函数,当得到WM_PAINT消息时,调用该函数引起重画
  
    //父类是一个空函数,以便TGraphicControl的子类复盖它。
  
      procedure Paint; override;
  
    public
  
      constructor Create(AOwner: TComponent); override;
  
      destructor Destroy; override;
  
    published
  
    //这个函数当图形中的画笔和画刷改变时引起重画,在设计器中最为明显
  
      procedure StyleChanged(Sender: TObject);
  
      property Align;
  
      property Anchors;
  
      property Brush: TBrush read FBrush write SetBrush;
  
      property DragCursor;
  
      property DragKind;
  
      property DragMode;
  
      property Enabled;
  
      property Constraints;
  
      property ParentShowHint;
  
      property Pen: TPen read FPen write SetPen;
  
      property Shape: TShapeType read FShape write SetShape default stRectangle;
  
      property ShowHint;
  
      property Visible;
  
      property OnContextPopup;
  
      property OnDragDrop;
  
      property OnDragOver;
  
      property OnEndDock;
  
      property OnEndDrag;
  
      property OnMouseDown;
  
      property OnMouseMove;
  
      property OnMouseUp;
  
      property OnStartDock;
  
      property OnStartDrag;
  
    end;
  
   
  
  implementation
  
   
  
  //构造函数,ControlStyle确定控件的特征,这里是加上csReplicatable
  
  //使该控件可以用PaintTo方法把它画到一个任意的画布中
  
  //另外还指定Pen和Brush对象的OnChange事件的方法指针给StyleChanged;
  
  constructor TShapeEx.Create(AOwner: TComponent);
  
  begin
  
    inherited Create(AOwner);
  
    ControlStyle := ControlStyle + [csReplicatable];
  
    Width := 65;
  
    Height := 65;
  
    FPen := TPen.Create;
  
    FPen.OnChange := StyleChanged;
  
    FBrush := TBrush.Create;
  
    FBrush.OnChange := StyleChanged;
  
  end;
  
   
  
  destructor TShapeEx.Destroy;
  
  begin
  
    FPen.Free;
  
    FBrush.Free;
  
    inherited Destroy;
  
  end;
  
  //最重要函数,控件就是以这个函数画出来的。
  
  procedure TShapeEx.Paint;
  
  var
  
  //X:左上角X, Y:左上角Y, W:宽, Y:高  S:宽高中大的值
  
    X, Y, W, H, S: Integer;
  
  begin
  
  //Canvas是父类TGraphicControl的属性,用于画控件
  
  //在画图之前,要进行一些坐标点的确定,
  
    with Canvas do
  
    begin
  
    //如果以控件的四个角来画图形,当Pen太大时,图形的边线
  
    //将比Pen的宽要小一些,所以要进行点的重定位。
  
      Pen := FPen;
  
      Brush := FBrush;
  
      X := Pen.Width div 2;
  
      Y := X;
  
      W := Width - Pen.Width + 1;
  
      H := Height - Pen.Width + 1;
  
      //Pen.width的值为0和为1时是一样的等于一个象素
  
      //如果上面Pen.width等于1,则图形的宽高刚好等于控件的宽高
  
      //如果为0,则图形宽高要大于控件宽高一个象素了,所以有了下面的语句
  
      if Pen.Width = 0 then
  
      begin
  
        Dec(W);
  
        Dec(H);
  
      end;
  
      if W  H then S := W else S := H;
  
      //当图形为正方类型的图形时,需要对图形的位置进行一些调整
  
      if FShape in [stSquare, stRoundSquare, stCircle] then
  
      begin
  
        Inc(X, (W - S) div 2);
  
        Inc(Y, (H - S) div 2);
  
        W := S;
  
        H := S;
  
      end;
  
      case FShape of
  
        stRectangle, stSquare:
  
          Rectangle(X, Y, X + W, Y + H);
  
        stRoundRect, stRoundSquare:
  
          RoundRect(X, Y, X + W, Y + H, S div 4, S div 4);
  
        stCircle, stEllipse:
  
          Ellipse(X, Y, X + W, Y + H);
  
        //以下是增加的部分。
  
        stHLine:
  
        begin
  
          MoveTo(X, Height div 2);
  
          LineTo(X+W,Height div 2);
  
        end;
  
        stVLine:
  
        begin
  
          MoveTo(Width div 2,Y);
  
          LineTo(Width div 2,Y+H);
  
        end;
  
        stTriangle:
  
          Polygon([Point(X,Y+H-1),Point(X+W-1,Y+H-1),Point(Width div 2,Y)]);
  
        stDiamond:
  
          Polygon([Point(Width div 2,Y),Point(X,Height div 2),
  
                   Point(Width div 2,Y+H-1),Point(X+W-1, Height div 2)]);
  
      end;
  
    end;
  
  end;
  
  //Invalidate这个函数将使系统发送WM_PAINT给TGraphicControl
  
  //TGraphicControl的处理函数将调用Paint,而它的子类覆盖了它
  
  //所以实际就调用了ShapeEx的Paint函数,从而达到了重画的效果
  
  procedure TShapeEx.StyleChanged(Sender: TObject);
  
  begin
  
    Invalidate;
  
  end;
  
   
  
  procedure TShapeEx.SetBrush(Value: TBrush);
  
  begin
  
    FBrush.Assign(Value);
  
  end;
  
   
  
  procedure TShapeEx.SetPen(Value: TPen);
  
  begin
  
    FPen.Assign(Value);
  
  end;
  
  //设置图形,同时引起重画,以达到图形变化,
  
  //最明显的效果是在设计器时改变Shape属性时看到的变化
  
  procedure TShapeEx.SetShape(Value: TShapeType);
  
  begin
  
    if FShape  Value then
  
    begin
  
      FShape := Value;
  
      Invalidate;
  
    end;
  
  end;
  
   
  
  end.
  
   
  
  安装等方法在上一章已经说过了,这里不多说。这一次知道了图形控件的大概做法,其实无非就是覆盖Paint来画自己的图形控件,而其他,则和我们上一章的说过的一样。其实也很简单。
  
  以上两个控件算是比较简单,但已经讲清了很多组件制作的概念和技巧,看不看得懂就由你了,我也没有办法。有一个有用的技巧就是多看看VCL的源码,你会学到更多的东西。
  
  接下来,应该要做一个难一点了吧。想知道是什么,且听下回分解。

来源:http://www.tulaoshi.com/n/20160219/1602111.html

延伸阅读
这将是最后一个组件了,目标定为非可视化,事实上非可视化组件要比可视化组件难做,因为是从TComponent继承而来,就没有了很多属性和事件。而这些都要我们从头来做过。 这个非可视化组件,我决定为托盘组件,其中用到的技术较多,我不如列一个表出来,然后再来讲解好一点。另外,可能篇幅会多一些,请耐心看。 用到的技术: ...
标签: Java JAVA基础
一、前言 对于初学者来说,要执行JSP和Servlet,Tomcat是一个很不错的选择。你也可以用Resin,这两个产品都是可以不花一分钱的。 Resin对Xml的支持是很好的。 二、下载,安装 下载地址为Resin官方站点:http://www.caucho.com/。 从这个地址可以下载:http://www.caucho.com/download/index.xtp,我下载的是Resin1.1.4版本。 下...
标签: ASP
  构造代理库 .NET 平台上的应用程序可以使用代理库来调用Web服务上的方法,这样使用Web服务就非常容易。生成代理库的第一步是从SDL中生成一个Web服务的代理类。.NET SDK提供了一个叫做WebServiceUtil.exe的工具,它能够帮助我们生成一个代理类。要生成Web服务的代理类,首先进入命令行环境,然后转到将要开发客户应用程序的那个目录...
标签: CorelDRAW
(镜框) 看到这个小节的小标题了吧?镜框!不是艺术镜框!我是一直不太喜欢提“艺术”这个词的,所以没有在镜框前面加上这两个字,因为我觉得是否“艺术”并不重要,它并不是这里讨论的主题,这里只告诉你这种东西怎么做,至于能否具有“艺术性”,我不能也不敢给你打包票,只能靠你自己的修为了。 按老规矩,这一小节有两种...
标签: PS PS教程
本文由中国专家hf-2048原创,转载须保留此信息 之前已经发过两篇,但之前的两篇主要讲的是偏色照片的调正及美化. 今天要讲的是对数码照片进行润色和对人物的细节进行调整. 调色练习教程之一: http://bbs.jcwcn.com/viewthread.php?tid=24483&extra=page%3D1 调色练习教程之二: http://bbs.jcwcn.com/viewthread.php?tid=24828&ext...

经验教程

178

收藏

23
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部