请问有谁做过非规则的窗体,能说说原理或者例子吗?

解决方案 »

  1.   

    简单的,在主窗体Create。
    // 一个椭圆形窗体 OnResize中放同样的代码
    procedure TForm1.FormCreate(Sender: TObject);
    var
      hRegion: THandle;
    begin
      hRegion := CreateEllipticRgn(0, -Height, Width, Height);
      SetWindowRgn(Handle, hRegion, True);
    end; // 一个圆角矩形窗体 
    procedure TForm1.FormCreate(Sender: TObject);
    var
      hRegion: THandle;
    begin
      hRegion := CreateEllipticRgn(0,0,width,height,20,20);
      SetWindowRgn(Handle, hRegion, True);
    end; 
      

  2.   

    主要就是两个API,举例procedure TForm1.Button1Click(Sender: TObject);
    var
      rgn: HRGN;
    begin
      rgn := CreateEllipticRgn(0, 0, 600, 300);
      SetWindowRgn(handle, rgn, true);
    end;
      

  3.   

    复杂的,你要进行Mask的编程,进行CombineRGN
      

  4.   

    透明和异形窗体  
    CoDelphi.com
    摘 要:创造透明的或非矩形的或同时有以上两种特性的窗体
    关键字:透明 形状 窗体
    类 别:用户界面
     
     
        实际上,程序并不一定非要用Delphi来编。虽然我将提供Delphi的源代码,并且在Delphi环境中讨论问题,但是透明窗体程序是严格用winAPI实现的。因此,它可以被很容易的翻译为其他编程环境的代码。我将一步一步的把它解释清楚。    用这种方法可以将窗体的任意部分剪去。这些剪去的部分就是透明的。窗体的“透明”部分实际上已不属于窗体,用鼠标单击将会到达窗体下面。有一个很简单的方法能实现透明窗体,但是该方法也有它的弱点。    建立一个新的Application。    将BorderStyle设为bsNone。    保存并运行程序。它可以运行,但修改一下更好。因为它没有边缘部分,你的程序只显示一个简单的灰色矩形,你必须使用Alt-F4去关闭它。    为你的窗体的OnCreate事件添加处理函数:procedure TForm1.FormCreate(Sender: TObject); 
      var 
        NewRgn : HRGN; 
      begin 
      NewRgn := CreateEllipticRgn(10,10,width-10,height-10); 
      SetWindowRgn(handle,NewRgn,false); 
      end;     确定你的Uses子句含有"Windows"。    运行程序。你的窗口现在变成了一个灰色的椭圆形。你还是必须敲Alt-F4去关闭它。我已经告诉过你我将一步一步的把它解释清楚。    这里究竟发生了什么?Windows有一个称作“区域”的概念。我实际上对区域也不懂,现在我也只能猜了。区域是以边界定义的窗口的一部分。Windows为处理区域提供了几个函数,它提供给程序员区域句柄作为处理区域的主要接口。其中最基本函数的是关于建立区域的。在这个例子中,我使用CreateEllipticRgn来创建由其外接矩形定义的椭圆区域。我选择了一个比窗口小一些的矩形,这是因为在这一阶段一堆几何数据并不与什么窗口相联系。    最关键的区域函数是SetWindowRgn,它输入窗口的句柄、要设置的区域、窗体是否重画。区域的坐标是关于整个窗体的局部(而不是整个屏幕)坐标系。    实际上就这么简单。你先创建一个区域,然后把它设置为窗口的区域。    现在是开始解释细节的时候了。添加一个处理OnPaint事件的函数:procedure TForm1.FormPaint(Sender: TObject); 
      begin 
      canvas.pen.width := 10; 
      canvas.Ellipse(10,10,width-10,height-10); 
      end;     运行。我的程序现在填充了一个漂亮的黑边。我想除非你设定了不同的默认窗口颜色,你将得到相同的结果。    回到Object Inspector,将主窗体的BorderStyle设为bsSingle。     运行程序。现在椭圆向下了一些,你可以在上面看到一点标题栏。为什么?当你使用SetWindowRgn时,区域是相对窗口的整个部分的。把BorderStyle设为bsSingle就使所有的非客户区,包括边缘、标题栏和按钮都显示。这就是开始时我要你将BorderStyle设为bsNone的原因。如果你喜欢不同的边界样式,你可以利用CustomeForm.ClientRect、TCustomForm.ClientWidth、TCustomForm.ClientHeight、TControl.left和TControl.right,通过数学计算将所有的东西组合在一起。    请将BorderStyle重新设为bsNone。    呀,怎么来移动窗体呢?你可以自己用一些野路子,或是让Windows为你处理。当用户在一个窗口点击时,Windows先问窗口是否点击一个非客户区部分,如果是,是哪一种。我们可以在被问的时候,告诉Windows用户点击了标题栏。Windows然后对自己说:“好,我们开始移动窗口吧。”这样它就做了。    在你的窗体中添加一个私有方法,象这样声明:procedure WMNCHitTest(var Msg:TMessage); message WM_NCHITTEST; 象这样实现它:procedure TForm1.WMNCHitTest(var Msg:TMessage); 
    begin 
      msg.result := HTCAPTION; 
    end;     运行程序。在窗口某处点击并拖拽窗体,窗体能够移动。    当用户点击时Windows发送wm_nchittest给程序。你可以回答说用户点击到了标题。Windows就想当然的认为要移动窗体了,就这么简单。我记不住非客户区测试的返回值,但是我记得它们在windows.pas中的某个地方。一般我找到了它们,或是查找"caption"。只要你找到那儿,你可以看到所有其他的玩意儿。
    更加复杂的区域    区域不一定非要是简单的矩形或椭圆形。他们可以是……    坦率的说,他们可以是任意形状,凹的、不相连的、斑点状的。察看一下CreateXRgn样的函数(如在CreateEllipticRgn点F1,然后在帮助中点Group按钮)。其中有矩形、圆角矩形,还有任意多边形。更重要的是,还可以组合这些区域。OK,下面是一个组合区域的程序。我们用两个,而不是一个椭圆。    在你和更多区域打交道之前,你还需要知道一点其他的东西。看一下SetWindowRgn的帮助,你可以在底部看到它说你不能删去传给窗体的区域,Windows需要它。但当你组合两个区域时,你传给Windows其中的一个,另一个丢在一边。我们必须把它清除。下面是代码:procedure TForm1.FormCreate(Sender: TObject); 
    var 
      LeftRgn : HRGN; 
      RightRgn : HRGN; 
      NewRgn : HRGN; 
    begin 
      LeftRgn  := CreateEllipticRgn(10,10,width div 2, height-10); 
      RightRgn := CreateEllipticRgn(width div 2, 10, width-10, height-10); 
      NewRgn := CreateRectRgn(0,0,0,0); 
      CombineRgn(NewRgn,LeftRgn,RightRgn,RGN_OR); 
      DeleteObject(LeftRgn); 
      DeleteObject(RightRgn); 
      SetWindowRgn(handle,NewRgn,false); 
    end;     因为我们有两个椭圆,我们必须改FormPaint中的代码。你可以从FormCreate使工作简单一些。procedure TForm1.FormPaint(Sender: TObject); 
    begin 
      canvas.pen.width := 10; 
      canvas.Ellipse(10,10,width div 2, height-10); 
      canvas.Ellipse(width div 2, 10, width-10, height-10); 
    end;     运行程序。将会出现两个椭圆。你可能看到过眼珠转动的程序,它也是用这样的方法。现在你明白了吧。    仔细看一下椭圆间的空间,有一个象素的间隔。注意在文档中,我想是在CreateRectRgn中,它指出建立的区域不包含右边缘和下边缘。这就解释了为什么有间隔。    但是我还有一点要解释。为什么要NewRegion := CreateRectRgn()? 非常简单。CombineRgn并不建立一新区域,目的区域必须存在。给它一个假的区域句柄,它会不高兴的,SetWindowRgn也会失败。你可以试一下,注释掉CreateRectRgn那一行,你可以看到会发生什么。我得到了一个没有变化的矩形窗口。这样我建立了一个任意区域,使Windows在CombineRgn时满意。注意,因为区域是(0,0,0,0),并且右边和下边被去除了,这将会产生一空的区域。    当然,看一下我在用完左右两个区域后将它们删除了。要记住除了你传给通过SetWindowRgn传给Windows的区域,你必须删除你创建的任何区域。    注意在CombineRgn中,组合方式是RGN_OR。它是关于位运算的,而不是英语概念的。如果用RGN_AND,结果区域是两个区域交叉部分。    如何建一个没有区域的窗口?很难发现一个没有作图部分的窗口。但是它能在工具条上显示,你可以在那里右击来关闭它。或者,如果你运行,你看不到它。但它是活动的,你可以用Alt-F4使它死亡。    现在是我能想到的最后一件事:太大的区域。潜入代码,把右边的椭圆改得比窗体还大:  RightRgn := CreateEllipticRgn(width div 2, 10, width+60, height+60);     你将注意到椭圆正常并很大,但是Windows只使区域中在实际大小内的部分有效。如果你想使窗体增长到窗体之外,你必须改变窗体的实际大小使窗体增大。    所有的就是这些了。你可以从这个简单工具中得到不少创造性。 
      

  5.   

    进行Mask的编程,进行CombineRGN,mask得编程有介绍吗?谢谢!