回 帖 发 新 帖 刷新版面

主题:[delphi]制作桌面宠物

--------------------------------------------------------------------------------


一、引言

相信大家都见过一些桌面上的小宠物,如Office中的小助手等,小宠物们活泼可爱,还可帮助主人完成一定的事件,为应用程序添色不少,那我们自己也能否制作出这样的小宠物窗体呢?答案是肯定的。说到底其实就是对窗体显示区域的操作,使得窗体具有多种多样的外形,然后在窗体上绘制相应的图案。


二、支持区域操作的编程接口

在Windows的API函数中有一组用于区域操作的函数,可以用来生成区域、合并区域、获取区域数据、根据数据生成区域、把区域和窗体联系等,其中常用的几个函数有:生成矩形区域的CreateRectRgn函数,生成椭圆区域的CreateEllipticRgn函数,合并两个区域的CombinetRgn函数,从内存区域数据生成区域的ExCreateRegion函数,获得区域数据的GetRegionData函数,把区域和窗体联系的SetWindowRgn函数。

在Delphi中,这些常用的区域函数都被封装到了Windows单元中,在实际应用中,只须在单元文件中引用Windows单元(默认),即可直接使用这些函数。


三、多态窗体的生成原理

1、不规则窗体的生成

在实际操作过程中,可以直接利用CreateEllipticRgn函数直接生成圆形窗体,也可以利用CreatePolygonRgn函数生成任意非矩形窗体。如果目标区域过于复杂,可以把目标划分成规则的多个小区域分别建立,再把各区域合并,即可得到目标区域。

对于要生成基于位图图案的窗体,可以首先将位图背景色设为单一色,再按位图图案上的色彩进行行扫描,每扫描到非背景色,则产生一个像素宽的矩形区域,并入已形成的区域。这样当整个图案扫描完毕,以位图轮廓构成的区域形成,然后把位图图案绘入窗体,可以得到一个图形窗体。

2、动画的生成

在窗体创建时,建立起相对于每个位图图案的区域数据,在程序运行时,通过线程轮换调用数据产生区域,并在窗体上显示相应的位图图案,以达到动画效果。


四、位图图案窗体的创建

1、位图图案区域数据的生成函数GetRgnData

procedure GetRgnData (Bmp: TBitmap; var nCount: Cardinal; var lpRgnData: PRgnData);

var

h, w, i, j: Integer;

tc: TColor;

hrgn1, hrgn2: HRGN;

begin

h := Bmp.Height;

w := Bmp.Width;

//获取位图第一象素点的颜色值,背景颜色

tc := Bmp.Canvas.Pixels[0, 0];

//生成矩形区域

hrgn1 := CreateRectRgn (0, 0, w, h);


try

for i := 0 to h-1 do

begin

for j := 0 to w-1 do

begin

//判断当前象素点的颜色值是否与背景色相同

if Bmp.Canvas.Pixels[j, i] = tc then 

begin

hrgn2 := CreateRectRgn (j, i, j+1, i+1);

if hrgn2 <> 0 then

//抠去hrgn2数据区域

CombineRgn (hrgn1, hrgn1, hrgn2, RGN_DIFF); 


DeleteObject (hrgn2);

end;

end;

end;


//获取hrgn1数据区域大小

nCount := GetRegionData (hrgn1, 0, nil); 

//分配内存空间给临时区域指针lpRgnData

GetMem (lpRgnData, nCount * sizeof(TRgnData));

//获取数据

GetRegionData (hrgn1, nCount, lpRgnData);

except

ShowMessage ('区域数据生成出错');

end;

DeleteObject (hrgn1);

end;


2、动画线程的实现

⑴ 线程的定义

TAnimThread = class (TThread)

private

FIndex: Integer;

OwnerForm: TForm;

procedure DrawAnimPic;

protected

procedure Execute; override;

public

constructor Create (Form: TForm); {override;}

end;


说明:①FIndex所要显示的位图索引值,OwnerForm指定当前窗体;

②DrawAnimPic线程中动画绘制窗体过程。


⑵ 线程的实现

constructor TAnimThread.Create (Form: TForm);

begin

OwnerForm := Form;

FIndex := 0;

inherited Create (False);

end;


procedure TAnimThread.DrawAnimPic;

var

Bmp: TBitmap;

w, h: Integer;

rgn: HRGN;

begin

Bmp := AnimBmp[FIndex];

w := Bmp.Width;

h := Bmp.Height;

//重新设置窗体的尺寸

OwnerForm.Width := w; 

OwnerForm.Height := h;

//从内存区域数据生成区域

rgn := ExtCreateRegion (nil, nCount[FIndex], TRData[FIndex]^); 

//把区域和窗体联系起来

SetWindowRgn (OwnerForm.Handle, rgn, True); 

DeleteObject (rgn);

//在窗体画布上绘制位图图案

BitBlt (OwnerForm.Canvas.Handle, 0, 0, w, h, Bmp.Canvas.Handle, 0, 0, SRCCOPY);

end;

procedure TAnimThread.Execute;

begin

inherited;

//反复执行,直至线程终止

repeat

FIndex := FIndex mod 6;

//同步绘制过程DrawAnimPic

Synchronize (DrawAnimPic);

Sleep (300);

Inc (FIndex);

until Terminated;

end; 


说明:① 在绘制过程DrawAnimPic所使用到的变量定义在单元文件内,其定义:

AnimBmp: array[0..5] of TBitmap;

nCount: array[0..5] of Cardinal;

TRData: array[0..5] of PRgnData;

以上变量均在窗体创建过程中赋值,在窗体销毁前释放。

②在线程的执行(Execute)过程中,不能直接调用DrawAnimPic过程,以免产生VCL组件读写冲突,所以必须使用同步函数Synchronize进行协调。


五、结束语

通过本次学习,让读者初步了解Delphi编程中线程的创建及使用,同时掌握如何在Delphi编程过程中调用Windows 的API函数,来建立个性化的应用程序。本文简述了一个动画窗体的实现过程,当然要真正作为一个宠物,它必须有自己的“思想”,会随机地做出一些动作,这就需要在程序中可以随机地调取一些动作序列,其程序过程读者可根据自己的 兴趣进一步完善。

回复列表 (共5个回复)

沙发

希望大家去尝试!!

板凳

顶上去,自顶!

3 楼

顶一下

4 楼

是楼主原创不?呵呵

5 楼

我自己顶一下!

我来回复

您尚未登录,请登录后再回复。点此登录或注册