⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 windows异形窗口 (2000年11月8日).txt

📁 delphi 编程技巧
💻 TXT
字号:
Windows异形窗口 (2000年11月8日) 

本站更新  分类:   作者:刘明华   推荐:   阅读次数:758  
(http://www.codesky.net)  

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

  WINDOWS图形界面应用程序都是基于窗口的。在Windows操作系统中,窗口是应用程序与用户之间的界
面。微软对窗口的定义是:窗口是屏幕上的一块方形部分,用来显示输出和接受用户的输入。编写基于
Windows 的GUI程序首先要做的事情之一便是创建一个或多个窗口。我们通常使用CreateWindow和
CreateWindowEx这两个API函数创建窗口,此外通过DialogBox,CreateDialog和MessageBox等函数还可以
创建特殊用途的窗口(如对话框、消息框等)。 

  不管是以上哪个函数,都将无一例外的得到矩形窗口。但是,有时为了实现特殊效果,有时希望使用不
规则形状的窗口。而本文就将探讨怎样实现这些异形窗口,如圆形、椭圆形、星形等窗口。 


  为了实现不规则形状的窗口,需要用到“区域”(Region)这一概念。在微软Windows操作系统中,区域
是指能对其进行填充、绘制、加边框、颜色翻转等操作的长方形、(椭)圆形、多边形,或者这些形状的叠
加。 

  区域的创建 

  通过以下API函数,我们可以创建区域,它们是:CreateRectRgn(长方形),CreateRoundRectRgn
(圆角长方形),CreateEllipticRgn(圆形和椭圆形),以及CreatePolygonRgn和
CreatePolyPolygonRgn。如果调用成功的话,它们都会返回一个指向新建区域的句柄。下面先简单地介绍
CreatePolygonRgn和CreateEllipticRgn的用法: 

  HRGN CreatePolygonRgn( //创建多边形区域 

   CONST POINT *lppt, //指向一个POINT类型的数组 

   int cPoints, //数组中元数的个数 

   int fnPolyFillMode //多边形填充模式 

   ); 

  HRGN CreateEllipticRgn( //创建圆形或者椭圆形区域 

  int nLeftRect, //(椭)圆外切长方形左上角的X坐标 

  int nTopRect, //(椭)圆外切长方形左上角的Y坐标 

   int nRightRect, //(椭)圆外切长方形右下角的X坐标 

   int nBottomRect //(椭)圆外切长方形右下角的Y坐标 

   ); 

  区域的一个非常重要的性质是:任意两个区域可以进行合成操作,进而生成一个新的区域。 

  区域的合成 

  利用已有的区域可以合成新的区域,这便是函数CombineRgn的作用。该函数的C语言原型声明如下: 

  int CombineRgn( 

   HRGN hrgnDest, // 指向目的区域 

   HRGN hrgnSrc1, // 指向源区域 

   HRGN hrgnSrc2, // 指向源区域 

   int fnCombineMode // 区域结合模式 

   ); 

  在上述函数中,第二、三个参数为源区域;第一个参数hrgnDest指向的是目的区域,这块区域将用来盛
放由hrgnSrc1和hrgnSrc2合成的新区域,所以必须保证hrgnDest所指向的区域在调用函数CombineRgn之前
已经存在。 

  第四个参数,即fnCombineMode,指明了合成方式,它的取值及含义如表1所示: 

  表1 

  合成方式  含 义 

  RNG_AND 新区域为两块源区域的相交部分。 

  RNG_COPY 新区域为第一块源区域的拷贝。 

  RNG_DIFF 新区域为第一块源区域减去与第二块源区域共有的部分。 

  RNG_OR 新区域为两块源区域的并集。 

  RNG_XOR 新区域为两块源区域的非公共部分的并集。 

  区域的使用 

  创建或者合成了一定形状的区域之后,并不能看到任何东西。区域要与具体的窗口结合才能起作用。把
区域同窗口挂起钩来,要用到名为SetWindowRgn的API函数。它的原型如下: 

  int SetWindowRgn( 

   HWND hWnd, // 指向窗口区域已被设定好的窗口 

   HRGN hRgn, // 指向区域 

   BOOL bRedraw // 窗口重画标志 

   ); 

  当成功地调用了此函数后,操作系统将拥有hRgn所指定的那块区域。区域的坐标是相对于窗口的左上角
(包括标题区在内)。窗口中只有在区域内的那部分是可见的,对位于区域之外的窗口部分,系统将不予显
示。也就是说,窗口表现出来的形状与区域的形状是一样的(当然这还有个条件,那就是窗口不得比区域
小)。为了调整窗口的大小,可先用API函数GetRgnBox获取区域的大小(即长与宽),再根据获得的数据
(在p2中)来相应地调整窗口的长和宽: 

  function GetRgnBox(RGN: HRGN; var p2: TRect): Integer; stdcall; 

  有了上面介绍的这些关于区域的知识,就足以实现这些异形窗口了。 

 异形窗口示例程序 

  笔者用Delphi编写了一个示例程序,它实现了5种形状的窗口(图1中列出了其中四种)。希望该示例程
序能有助于读者加深对区域的理解和运用。 

  以下是程序的主单元代码: 

  //Create windows in special shapes. 

  //Press CTRL+S to exit this program. 

  unit Shapes; 

  interface 

  uses 

   Windows, Messages, SysUtils, Classes, Graphics, 

   Controls, Forms, Dialogs, ExtCtrls, StdCtrls; 

   

  const HOTKEYID=1; 

   

  type 

   TShape = class(TForm) 

   Timer1: TTimer; 

   procedure FormCreate(Sender: TObject); 

   procedure FormDestroy(Sender: TObject); 

   procedure Timer1Timer(Sender: TObject); 

   private 

   procedure WMHOTKEY(var Msg:TWMHotKey);message WM_HOTKEY; 

   end; 

   

  var 

   Tick:Integer; 

   Shape: TShape; 

   Rgn, Rgn1:THandle; 

   XX,YY:Integer; 

   

   Triangle:array[0..2] of TPoint 

   =((x:30;y:0),(x:0;y:60),(x:60;y:60)); 

   

   Diamond:array[0..3] of TPoint 

   =((x:30;y:0),(x:60;y:50),(x:30;y:100),(x:0;y:50)); 

   

   Star:array[0..4]of TPoint=((x:34;y:0), (x:0;y:73), 

   (x:75;y:28),(x:3;y:28),(x:64;y:73)); 

   

  implementation 

  {$R *.DFM} 

  procedure TShape.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; 

   

  procedure TShape.FormDestroy(Sender: TObject); 

  begin 

  DeleteObject(Rgn); 

  UnregisterHotKey(Handle,HOTKEYID); 

  end; 

   

  procedure TShape.WMHOTKEY(var Msg:TWMHotKey); 

  begin 

  //检测到Ctrl+S 热键时退出程序 

  if (Msg.HotKey=HOTKEYID) then Close 

  else inherited; 

  end; 

   

  procedure TShape.Timer1Timer(Sender: TObject); 

  var Rect:TRect; 

   cl:Integer; 

  begin 

  Randomize; 

  cl:=Random($2FFFFFFF); 

   

  Tick:=Tick mod 300; 

  //每隔一定时间变换一次形状 

  case Tick of 

  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); 

   

  if Left>Screen.Width-Width then XX:=-Random(20) 

  else if Left   if Top>Screen.Height-Height then YY:=-Random(20) 

  else if Top   if (XX>-3)and(XX   if (YY>-3)and(YY   //移动窗口 

  SetWindowPos(Handle,HWND_TOPMOST,Left+XX,Top+YY,Width,Height,SWP_NOACTIVATE); 

  end; 

   

  end. 
 
 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -