• Delphi 组件开发教程指南(7)继续模拟动画显示控件


       上一次,我讲解了如何实现一个模拟显示动画效果的控件,但是我没有给出所有代码,只是给了一些关键代码,不晓得,有没有人将代码完全补全的,同时也留下了一个问题说,如何通过另一种方式来实现这个动画的现实效果!不晓得有人实现出来了没!现在,我就来揭露留下的问题。揭露之前,先回复有人提出的问题,说我说要讲组件卸载的,咋没讲到!还真是忘记了!因为这个卸载很简单!打开Component菜单下的Install Packages那个菜单会出现一个Delphi的安装了的所有的包列表,在里面找到我们之前建立的那个安装包,然后点击Remove删除,就完事了!具体操作如下:

    这个图中,我删除了我们安装的控件,然后再看组件列表,安装的控件就没有了!这就是卸载控件的完整操作了!很简单吧!

        现在,正式进入主题!在上回,我给出了一种实现方式,同时,我也说还有另外一种实现方式。今天讲的就是通过另一种方式来实现这个动画显示效果!其实这个方式也就是个大同小异,思路一样,只是中间的某些过程不同,上次,我是用了一个ImageList来获取的每一帧图片,那个比较简单,而这回,我所说的方式,就是给定一整张图片,然后将图片切片,根据指定的帧数来获得不同图片区域的现实信息,然后再绘制到界面上呈现给用户。那么和前次的比较,唯一的不同,也就是那个每一帧图片的那个来源不同,以前是来源于ImageList,而现在我是要来源于一张图片!那么,先来分析一下,首先要来源一张图片,所以,肯定需要向外面分发一个属性,比如我设置为FrameSource,表示帧源

    Property FrameSource: TBitmap read FFrameSource write SetFrameSource;

    然后再想一想,当这个图片改变的时候,界面肯定要变化的,所以我们需要在设置图片的时候,通知界面刷新,这个容易在

    FrameSource.OnChange事件中调用一下刷新Invalidate就好了。然后再思考一下,指定了帧源,那么如何来区分这个帧源呢(也就是怎么对这个图片进行切片,以获得每一帧图片!)所以,还需要一个属性FrameCount,用来指定帧数,然后通过这个帧数对每一帧图的区域进行标记。同时,这个FrameCount改变的时候也是需要更新的!指定了这个之后,我们就能顺利的取得每一帧的图片了,这个是很容易的,Delphi为我们提供了一个Canvas的画布属性,我们可以通过这个画布来获得画布上的某一个区域的显示信息,所以我们获取图片就可以使用Canvas.CopyRect来获取某一块区域了。之后的操作就和上一次讲的一样,绘制到前台显示给用户就好了。这个分析就完全完成了,现在给出完整代码!

    代码
    unit DxAnimateControl;

    interface
    uses
    Windows,SysUtils, Classes, Controls,Graphics,ImgList,ExtCtrls;

    type
    TDxAnimateControl
    = class(TGraphicControl)
    private
    FImageList: TImageList;
    Timer: TTimer;
    PicIndex: Integer;
    FActive: Boolean;
    bmp: TBitmap;
    FFrameSource: TBitmap;
    FFrameCount: Integer;
    procedure SetImageList(const Value: TImageList);
    procedure SetActive(const Value: Boolean);
    function GetInterVal: Integer;
    procedure SetInterVal(const Value: Integer);
    procedure SetFrameSource(const Value: TBitmap);
    procedure SetFrameCount(const Value: Integer);
    protected
    procedure DoTimer(Sender: TObject);
    procedure DoPicChange(Sender: TObject);
    procedure Paint;override;
    public
    constructor Create(AOwner: TComponent);override;
    destructor Destroy;override;
    published
    property FrameSource: TBitmap read FFrameSource write SetFrameSource;
    property FrameCount: Integer read FFrameCount write SetFrameCount default 1;
    property ImageList: TImageList read FImageList write SetImageList;
    property Interval: Integer read GetInterVal write SetInterVal;
    property Active: Boolean read FActive write SetActive;
    end;

    procedure Register;
    implementation

    procedure Register;
    begin
    RegisterComponents(
    'Standard', [TDxAnimateControl]);
    end;
    { TDxAnimateControl }

    constructor TDxAnimateControl.Create(AOwner: TComponent);
    begin
    inherited;
    FFrameCount :
    = 1;
    FFrameSource :
    = TBitmap.Create;
    FFrameSource.OnChange :
    = DoPicChange;
    bmp :
    = TBitmap.Create;
    PicIndex :
    = -1;
    Timer :
    = TTimer.Create(self);
    FActive :
    = False;
    Timer.Enabled :
    = False;
    Timer.OnTimer :
    = DoTimer;
    Width :
    = 20;
    Height :
    = 20;
    end;

    destructor TDxAnimateControl.Destroy;
    begin
    bmp.Free;
    FFrameSource.Free;
    inherited;
    end;

    procedure TDxAnimateControl.DoPicChange(Sender: TObject);
    begin
    if not FFrameSource.Empty then
    Height :
    = FFrameSource.Height;
    DoTimer(
    nil);
    end;

    procedure TDxAnimateControl.DoTimer(Sender: TObject);
    var
    r: TRect;
    tmpw: Integer;
    begin
    if not FFrameSource.Empty then
    begin
    tmpw :
    = FFrameSource.Width div FFrameCount;
    bmp.Width :
    = tmpw;
    bmp.Height :
    = FFrameSource.Height;
    inc(PicIndex);
    if PicIndex > FFrameCount - 1 then
    PicIndex :
    = 0;
    if PicIndex = FFrameCount - 1 then
    r :
    = Rect(FFrameSource.Width - tmpw * (PicIndex - 1),0,FFrameSource.Width,FFrameSource.Height)
    else
    r :
    = Rect(PicIndex*tmpw,0,(PicIndex+1)*tmpw,FFrameSource.Height);
    bmp.Canvas.CopyRect(bmp.Canvas.ClipRect,FFrameSource.Canvas,r);
    end
    else
    begin
    bmp.Canvas.Brush.Color :
    = Color;
    bmp.Canvas.FillRect(ClientRect);
    if (FImageList <> nil) and (FImageList.Count <> 0) then
    begin
    inc(PicIndex);
    if PicIndex > FImageList.Count - 1 then
    PicIndex :
    = 0;
    FImageList.GetBitmap(PicIndex,Bmp);
    end;
    end;
    Invalidate;
    end;

    function TDxAnimateControl.GetInterVal: Integer;
    begin
    Result :
    = Timer.Interval;
    end;

    procedure TDxAnimateControl.Paint;
    begin
    if not bmp.Empty then
    Canvas.CopyRect(ClientRect,bmp.Canvas,bmp.Canvas.ClipRect)
    else inherited;
    end;

    procedure TDxAnimateControl.SetActive(const Value: Boolean);
    begin
    if FActive <> Value then
    begin
    FActive :
    = Value;
    if not (csDesigning in ComponentState) then
    Timer.Enabled :
    = FActive;
    if FActive or (csDesigning in ComponentState) then
    DoTimer(
    nil);
    end;
    end;

    procedure TDxAnimateControl.SetFrameCount(const Value: Integer);
    begin
    if (FFrameCount <> value) and (Value > 0) then
    begin
    FFrameCount :
    = Value;
    if not FFrameSource.Empty then
    begin
    Width :
    = FFrameSource.Width div FFrameCount;
    Invalidate;
    end;
    end;
    end;

    procedure TDxAnimateControl.SetFrameSource(const Value: TBitmap);
    begin
    FFrameSource.Assign(Value);
    end;

    procedure TDxAnimateControl.SetImageList(const Value: TImageList);
    begin
    if FImageList <> Value then
    begin
    FImageList :
    = Value;
    if FImageList <> nil then
    begin
    Width :
    = FImageList.Width;
    Height :
    = FImageList.Height;
    end;
    DoTimer(
    nil);
    end;
    end;

    procedure TDxAnimateControl.SetInterVal(const Value: Integer);
    begin
    Timer.Interval :
    = Value;
    end;

    end.
    这次我在代码中,有几个新玩意在里面,一个是我声明FrameCount属性的时候写法为

    property FrameCount: Integer read FFrameCount write SetFrameCount default 1;

    后面跟了一个default 1,这个default表示为在IDE属性编辑器中默认会显示的内容为1,也就是说一开始不会用粗体显示的,然后还有一个新玩意是

    procedure TDxAnimateControl.SetActive(const Value: Boolean);

    这个设置中,我用了一个if not (csDesigning in ComponentState) then

    ComponentState专门用来表示属性的状态!csdesigning就表示是设计器状态,我这里表示的是在设计器状态的时候就不打开时钟了,不然会在设计的时候也看到界面的动画效果了!好了,到目前为止,这个简单的动画模拟显示效果的控件就基本完成了!当然,还是有很多情况没考虑到的,比如说图片帧源的方向问题,取图是横向还是纵向,都没做考虑,这个扩充就留给大家自己来完成吧!所有代码下载

    组件开发教程指南目录

  • 相关阅读:
    pku3734Blocks
    STLmultiset
    zoj 2744
    EXCEL vba 插入图片的大小裁剪尺寸移动和旋转的设置和指定
    C# WinForm下Excel导入导出
    日期格式校验
    vb获取目录下所有文件夹名称的方法
    批量 生成 word 多线程
    Java中验证日期时间格式
    递归绑定树形菜单
  • 原文地址:https://www.cnblogs.com/DxSoft/p/1736905.html
Copyright © 2020-2023  润新知