二、支持区域操作的编程接口
在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函数,来建立个性化的应用程序。本文简述了一个动画窗体的实现过程,当然要真正作为一个宠物,它必须有自己的“思想”,会随机地做出一些动作,这就需要在程序中可以随机地调取一些动作序列,其程序过程读者可根据自己的 兴趣进一步完善。

最新文章

  1. LCX端口转发实现内网突破
  2. c#跨线程访问控件帮助类
  3. 自定义列表dl的使用原因和场合
  4. c/c++面试题(3)strcat/strcmp/strlen/strcpy的实现
  5. 惠普M1005打印机无法自动进纸的问题
  6. Block、委托、回调函数原理剖析(在Object C语境)——这样讲还不懂,根本不可能!
  7. PHP的MySQL扩展:PHP访问MySQL的常用扩展函数
  8. Ruby多字节字符的设计
  9. vi的撤销命令
  10. Android应用开发学习笔记之播放视频
  11. Excel相关问题
  12. js判断奇偶数实现隐藏显示功能 与css立体按钮
  13. 程序员的自我修养-----Java开发的必须知道的几个注意点
  14. PHP中使用CURL实现GET和POST请求(转载)
  15. 使用deb 打包开发的postgres extension
  16. PHP数组(数组正则表达式、数组、预定义数组)
  17. shell模拟ctrl c停止
  18. java并发编程:线程安全管理类--原子操作类--AtomicReferenceArray&lt;E&gt;
  19. C++字符串类型和数字之间的转换
  20. python console

热门文章

  1. rest_framework框架实现之(认证)
  2. C判断语句
  3. css创建
  4. 线段树区间合并优化dp——cf1197E(好)
  5. DNS域名服务器的搭建
  6. thinkphp 表单令牌
  7. mongo分组查询(转)
  8. CSS:CSS 属性 选择器
  9. hibernate使用手写sql以及对结果list的处理
  10. mvn eclipse:eclipse