windows异性窗体.docx
《windows异性窗体.docx》由会员分享,可在线阅读,更多相关《windows异性窗体.docx(9页珍藏版)》请在冰豆网上搜索。
windows异性窗体
windows异性窗体
WINDOWS图形界面应用程序都是基于窗口的。
在Windows操作系统中,窗口是应用程序与用户之间的界
面。
微软对窗口的定义是:
窗口是屏幕上的一块方形部分,用来显示输出和接受用户的输入。
编写基于
Windows的GUI程序首先要做的事情之一便是创建一个或多个窗口。
我们通常使用CreateWindow和
CreateWindowEx这两个API函数创建窗口,此外通过DialogBox,CreateDialog和MessageBox等函数还可以
创建特殊用途的窗口(如对话框、消息框等)。
不管是以上哪个函数,都将无一例外的得到矩形窗口。
但是,有时为了实现特殊效果,有时希望使用不
规则形状的窗口。
而本文就将探讨怎样实现这些异形窗口,如圆形、椭圆形、星形等窗口。
为了实现不规则形状的窗口,需要用到“区域”(Region)这一概念。
在微软Windows操作系统中,区域
是指能对其进行填充、绘制、加边框、颜色翻转等操作的长方形、(椭)圆形、多边形,或者这些形状的叠
加。
区域的创建
通过以下API函数,我们可以创建区域,它们是:
CreateRectRgn(长方形),CreateRoundRectRgn
(圆角长方形),CreateEllipticRgn(圆形和椭圆形),以及CreatePolygonRgn和
CreatePolyPolygonRgn。
如果调用成功的话,它们都会返回一个指向新建区域的句柄。
下面先简单地介绍
CreatePolygonRgn和CreateEllipticRgn的用法:
HRGNCreatePolygonRgn(//创建多边形区域
CONSTPOINT*lppt,//指向一个POINT类型的数组
intcPoints,//数组中元数的个数
intfnPolyFillMode//多边形填充模式
);
HRGNCreateEllipticRgn(//创建圆形或者椭圆形区域
intnLeftRect,//(椭)圆外切长方形左上角的X坐标
intnTopRect,//(椭)圆外切长方形左上角的Y坐标
intnRightRect,//(椭)圆外切长方形右下角的X坐标
intnBottomRect//(椭)圆外切长方形右下角的Y坐标
);
区域的一个非常重要的性质是:
任意两个区域可以进行合成操作,进而生成一个新的区域。
区域的合成
利用已有的区域可以合成新的区域,这便是函数CombineRgn的作用。
该函数的C语言原型声明如下:
intCombineRgn(
HRGNhrgnDest,//指向目的区域
HRGNhrgnSrc1,//指向源区域
HRGNhrgnSrc2,//指向源区域
intfnCombineMode//区域结合模式
);
在上述函数中,第二、三个参数为源区域;第一个参数hrgnDest指向的是目的区域,这块区域将用来盛
放由hrgnSrc1和hrgnSrc2合成的新区域,所以必须保证hrgnDest所指向的区域在调用函数CombineRgn之前
已经存在。
第四个参数,即fnCombineMode,指明了合成方式,它的取值及含义如表1所示:
表1
合成方式 含义
RNG_AND新区域为两块源区域的相交部分。
RNG_COPY新区域为第一块源区域的拷贝。
RNG_DIFF新区域为第一块源区域减去与第二块源区域共有的部分。
RNG_OR新区域为两块源区域的并集。
RNG_XOR新区域为两块源区域的非公共部分的并集。
区域的使用
创建或者合成了一定形状的区域之后,并不能看到任何东西。
区域要与具体的窗口结合才能起作用。
把
区域同窗口挂起钩来,要用到名为SetWindowRgn的API函数。
它的原型如下:
intSetWindowRgn(
HWNDhWnd,//指向窗口区域已被设定好的窗口
HRGNhRgn,//指向区域
BOOLbRedraw//窗口重画标志
);
当成功地调用了此函数后,操作系统将拥有hRgn所指定的那块区域。
区域的坐标是相对于窗口的左上角
(包括标题区在内)。
窗口中只有在区域内的那部分是可见的,对位于区域之外的窗口部分,系统将不予显
示。
也就是说,窗口表现出来的形状与区域的形状是一样的(当然这还有个条件,那就是窗口不得比区域
小)。
为了调整窗口的大小,可先用API函数GetRgnBox获取区域的大小(即长与宽),再根据获得的数据
(在p2中)来相应地调整窗口的长和宽:
functionGetRgnBox(RGN:
HRGN;varp2:
TRect):
Integer;stdcall;
有了上面介绍的这些关于区域的知识,就足以实现这些异形窗口了。
异形窗口示例程序
笔者用Delphi编写了一个示例程序,它实现了5种形状的窗口(图1中列出了其中四种)。
希望该示例程
序能有助于读者加深对区域的理解和运用。
以下是程序的主单元代码:
//Createwindowsinspecialshapes.
//PressCTRL+Stoexitthisprogram.
unitShapes;
interface
uses
Windows,Messages,SysUtils,Classes,Graphics,
Controls,Forms,Dialogs,ExtCtrls,StdCtrls;
constHOTKEYID=1;
type
TShape=class(TForm)
Timer1:
TTimer;
procedureFormCreate(Sender:
TObject);
procedureFormDestroy(Sender:
TObject);
procedureTimer1Timer(Sender:
TObject);
private
procedureWMHOTKEY(varMsg:
TWMHotKey);messageWM_HOTKEY;
end;
var
Tick:
Integer;
Shape:
TShape;
Rgn,Rgn1:
THandle;
XX,YY:
Integer;
Triangle:
array[0..2]ofTPoint
=((x:
30;y:
0),(x:
0;y:
60),(x:
60;y:
60));
Diamond:
array[0..3]ofTPoint
=((x:
30;y:
0),(x:
60;y:
50),(x:
30;y:
100),(x:
0;y:
50));
Star:
array[0..4]ofTPoint=((x:
34;y:
0),(x:
0;y:
73),
(x:
75;y:
28),(x:
3;y:
28),(x:
64;y:
73));
implementation
{$R*.DFM}
procedureTShape.FormCreate(Sender:
TObject);
begin
Timer1.Interval:
=99;
BorderStyle:
=bsNone;
{
下条语句将Application窗口的扩展风格重新设
为WS_EX_TOOLWINDOW,这样程序运行时就不会在
任务栏上出现一个小图标。
}
Timer1Timer(self);
SetWindowLong(Application.Handle,GWL_ExStyle,WS_EX_ToolWindow);
//为窗口注册Ctr+S热键
RegisterHotKey(Handle,HOTKEYID,MOD_CONTROL,ord('S'));
end;
procedureTShape.FormDestroy(Sender:
TObject);
begin
DeleteObject(Rgn);
UnregisterHotKey(Handle,HOTKEYID);
end;
procedureTShape.WMHOTKEY(varMsg:
TWMHotKey);
begin
//检测到Ctrl+S热键时退出程序
if(Msg.HotKey=HOTKEYID)thenClose
elseinherited;
end;
procedureTShape.Timer1Timer(Sender:
TObject);
varRect:
TRect;
cl:
Integer;
begin
Randomize;
cl:
=Random($2FFFFFFF);
Tick:
=Tickmod300;
//每隔一定时间变换一次形状
caseTickof
0:
//五星形
begin
Rgn:
=CreatePolygonRgn(Star,5,0);
SetWindowRgn(Handle,Rgn,TRUE);
GetRgnBox(Rgn,Rect);
Width:
=Rect.Right-Rect.Left;
Height:
=Rect.Bottom-Rect.Top;
Color:
=cl;
end;
60:
//圆形
begin
Rgn:
=CreateEllipticRgn(0,0,60,60);
SetWindowRgn(Handle,Rgn,TRUE);
GetRgnBox(Rgn,Rect);
Width:
=Rect.Right-Rect.Left;
Height:
=Rect.Bottom-Rect.Top;
Color:
=cl;
end;
120:
//圆环形
begin
Rgn:
=CreateEllipticRgn(0,0,60,60);
Rgn1:
=CreateEllipticRgn(15,15,45,45);
CombineRgn(Rgn,Rgn,Rgn1,RGN_XOR);
DeleteObject(Rgn1);
SetWindowRgn(Handle,Rgn,TRUE);
GetRgnBox(Rgn,Rect);
Width:
=Rect.Right-Rect.Left;
Height:
=Rect.Bottom-Rect.Top;
Color:
=cl;
end;
180:
//棱形
begin
Rgn:
=CreatePolygonRgn(Diamond,4,0);
SetWindowRgn(Handle,Rgn,TRUE);
GetRgnBox(Rgn,Rect);
Width:
=Rect.Right-Rect.Left;
Height:
=Rect.Bottom-Rect.Top;
Color:
=cl;
end;
240:
//三角形
begin
Rgn:
=CreatePolygonRgn(Triangle,3,0);
SetWindowRgn(Handle,Rgn,TRUE);
GetRgnBox(Rgn,Rect);
Width:
=Rect.Right-Rect.Left;
Height:
=Rect.Bottom-Rect.Top;
Color:
=cl;
end;
end;//case
inc(Tick);
ifLeft>Screen.Width-WidththenXX:
=-Random(20)
elseifLeft ifTop>Screen.Height-HeightthenYY:
=-Random(20)
elseifTop if(XX>-3)and(XX if(YY>-3)and(YY //移动窗口
SetWindowPos(Handle,HWND_TOPMOST,Left+XX,Top+YY,Width,Height,SWP_NOACTIVATE);
end;
end.