摘要载入中…    请稍等…












内容载入中…    请稍等…

如长时间看不到内容,请关闭浏览器,重新打开此页!

芯友首页 应用软件 编程开发 网络硬件 资源下载 动漫音乐 精美图库 芯友论坛 视频教程 电脑技术QQ群:72845454
 ★★photoshop学友-史上最强播放器★★
 位置:编程开发>Deiphi>Deiphi窗体文章
◎→ 本类最新
DELPHI动态生成控件
Delphi编程中创建一个启动闪现窗
在win95,win98下实现半透明的窗口
拖动无标题栏窗体的方法
用Delphi 控制窗体的大小
使MDI窗口有一个背景图象或使它平
软件启动画面中启动状态的显示
◎→相关资源
C语言入门视频教程
C#编程WinForm入门视频
Asp.net入门视频教程下载
VC++编程视频教程下载
VB窗体文章
HTML入门教程
Deiphi实例教程
Deiphi窗体文章
Deiphi数据库编程
Deiphi网络编程
Deiphi图形图象文章
Deiphi系统文件
◎→ 热门资源
Listview中实现点击栏目标题排序
Microsoft Agent技术在Delphi中的
MIDAS中动态强制约束编程
Chuck Jazdzewski的离开意味着De
COM程序编写入门(三)
OICQ中用户图标选择的实现
DELPHI中利用对象的常用属性制作

创建除三角形外的各种形状窗体


日期:2008-10-20 22:01:48    来源:
   
 ·Delphi中如何调用VC++创建的动态链接库 ·PS CS2新增形状模糊滤镜绘制画布图案
 ·Delphi下用Windows API创建窗体
创建除三角形外的各种形状窗体


Is it possible to create forms with shapes other than the standard rectangular shape in Windows?
Sometimes it's just not enough to write applications that have the same boring rectangular forms over and over again. Sometimes you need a change. How about an elliptical form? Or maybe even a triangular form? Sound intriguing? It's not that hard to do.

New in Win32 is something called a region. The Win32 API Programmer's Reference defines a region as follows:



...a rectangle, polygon or ellipse (or a combination of two or more of these shapes) that can be filled, painted, inverted, framed and used to perform hit testing (testing for the cursor location).


From the definition, the most notable thing about a region is that it can be manipulated in a variety of ways. For our purposes we want to define a region to create a specific shape.

I should point out that a region can be defined for just about any TWinControl descendant (not just forms), meaning you can apply a region to a TPanel or even a TEdit (though I strongly recommend against it). But to alter the shape of a TWinControl descendant, all you need to provide is a handle and employ some handy-dandy shape change functions.

To get a control to change its shape, follow this two-step process:

Define the boundaries of the region that represent a particular shape.
Apply the boundaries you've defined to a window.
This is pretty simple. However, it's very important to refer to the help file, and to have the source at hand. I wouldn't be able to accomplish many of my projects, let alone write many of the articles I write here, without those two resources at my disposal. Especially with the Windows API calls, having access to the Window.PAS file is essential so I know what to pass into the functions. Remember, the WinAPI calls are really wrapper calls into the appropriate Windows DLLs, and of course, the help file is essential to getting background information on the topic you're interested in.
With respect to this article, look up the SetWindowRgn topic in Win32 Developer's Help, and have it handy while you're putting together your program. Pay particular attention to the Group hyperlink because it will give you a run-down of all the procedures related to the region topic. Let's move on!

Defining a Region's Boundary
The first step to creating a form of a different shape is to define the shape itself. For our discussion, we'll use three WinAPI calls:

CreateEllipticRgn
This function will create an elliptically-shaped region.
CreateRoundRectRgn
This will create a rectangular region with rounded corners.
CreatePolygonRgn
This will create just about any multi-sided shape, as long as the lines form a closed solid.

These functions return a HRGN type, which will then be used by a function called SetWindowRgn whose sole purpose in life it is to set the parameters defined by a particular region variable. I've encapsulated these functions in methods that are part of a demonstration form. The functions are coded as follows:
{===========================================================================
  Notice that all the functions are used in an assignment
  operation to a variable called rgn. This is a
  private var that I declared for the form. The private var is
  accessible to all functions; I did this so that I could change the shape of
  the form or a control on the form, and use the same region.
===========================================================================}

procedure TForm1.DrawEllipticRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateEllipticRgn(rect.left, rect.top, rect.right, rect.bottom);
  SetWindowRgn(wnd, rgn, TRUE);
end;

procedure TForm1.DrawRndRectRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateRoundRectRgn(rect.left, rect.top, rect.right, rect.bottom, 30, 30);
  SetWindowRgn(wnd, rgn, TRUE);
end;

procedure TForm1.DrawPolygonRegion(wnd : HWND; rect : TRect; NumPoints : Integer; DoStarShape : Boolean);
const
  RadConvert = PI/180;
  Degrees    = 360;
  MaxLines   = 100;
var
  x, y,
  xCenter,
  yCenter,
  radius,
  pts,
  I       : Integer;
  angle,
  rotation: Extended;
  arPts   : Array[0..MaxLines] of TPoint;
begin

  xCenter := (rect.Right - rect.Left) div 2;
  yCenter := (rect.Bottom - rect.Top) div 2;
  if DoStarShape then
    begin
      rotation := Degrees/(2*NumPoints);
      pts := 2 * NumPoints;
    end
  else
    begin
      rotation := Degrees/NumPoints;             //get number of degrees to turn per point
      pts := NumPoints
    end;
  radius := yCenter;

{This loop defines the Cartesian points of the shape. Notice I've added 90 degrees to the rotation angle. This is so that shapes will stand up; otherwise they'll lie on their sides. I had to brush up on my trigonometry to accomplish this (forgot all those sin and cos thingies). Many thanks to Terry Smithwick and David Ullrich for their assistance on CompuServe!}
  for I := 0 to pts - 1 do begin
    if DoStarShape then
      if (I mod 2) = 0 then //which means that
        radius := Round(radius/2)
      else
        radius := yCenter;

    angle := ((I * rotation) + 90) * RadConvert;
    x := xCenter + Round(cos(angle) * radius);
    y := yCenter - Round(sin(angle) * radius);
    arPts[I].X := x;
    arPts[I].Y := y;
  end;

  rgn := CreatePolygonRgn(arPts, pts, WINDING);
  SetWindowRgn(wnd, rgn, TRUE);
end;

The first two functions are pretty simple, just two-liners. All that's needed to create the appropriate shapes is a handle and a TRect structure. For forms, that structure would be taken from the ClientRect property; for other controls, use the BoundsRect property.

The DrawPolygonRegion method, however, is much more complex. This is due in part to the fact that CreatePolygonRgn requires the vertices of the corners of the polygon to be passed as an array of TPoints, and partly because I wanted to draw equilateral polygons based off points rotated around a common center point. For that I had to use some trigonometry.

I wanted to not only draw polygon regions, but stars as well. Using rotational trig allowed me to do it. The way the function works if the DrawStarShape parameter is set to True is that for every even value of I in the loop, the radius of the circle is set to half its length, and to maintain the number of points of the polygon I want to draw, I double the number of points to accomodate the contraction of the radius.

At the very end of each function is a call to SetWindowRgn. This function takes as parameters a window handle, a rgn var, and a Boolean value that specifies whether the window should be re-drawn. In all cases, if you want to see the shape you've made, this must be always be set to True.

Below is the listing for the entire source code of my test form. On the form I've dropped four TButtons (one for each of the shapes: ellipse, round rectangle, polygon and star); a TPanel to demonstrate the ability to set regions for TWinControl descendants other than TForm; and a SpinEdit used in conjunction with the Polygon and Star region buttons to define the number of points that'll be defining the shape. Here's the code:
unit regmain;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ExtCtrls, StdCtrls, Spin;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Button3: TButton;
    SpinEdit1: TSpinEdit;
    Button4: TButton;
    Panel1: TPanel;
    Edit1: TEdit;
    procedure DrawRndRectRegion(wnd : HWND; rect : TRect);
    procedure DrawEllipticRegion(wnd : HWND; rect : TRect);
    procedure DrawPolygonRegion(wnd : HWND; rect : TRect; NumPoints : Integer; DoStarShape : Boolean);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
    procedure Button4Click(Sender: TObject);
  private
    { Private declarations }
    rgn : HRGN;
    rect : TRect;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.DrawRndRectRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateRoundRectRgn(rect.left, rect.top, rect.right, rect.bottom, 30, 30);
  SetWindowRgn(wnd, rgn, TRUE);
end;

procedure TForm1.DrawEllipticRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateEllipticRgn(rect.left, rect.top, rect.right, rect.bottom);
  SetWindowRgn(wnd, rgn, TRUE);
end;

procedure TForm1.DrawPolygonRegion(wnd : HWND; rect : TRect; NumPoints : Integer; DoStarShape : Boolean);
const
  RadConvert = PI/180;
  Degrees    = 360;
  MaxLines   = 100;
var
  x, y,
  xCenter,
  yCenter,
  radius,
  pts,
  I       : Integer;
  angle,
  rotation: Extended;
  arPts   : Array[0..MaxLines] of TPoint;
begin

  xCenter := (rect.Right - rect.Left) div 2;
  yCenter := (rect.Bottom - rect.Top) div 2;
  if DoStarShape then
    begin
      rotation := Degrees/(2*NumPoints);
      pts := 2 * NumPoints;
    end
else
    begin
      rotation := Degrees/NumPoints;             //get number of degrees to turn per point
      pts := NumPoints
    end;
  radius := yCenter;

{This loop defines the Cartesian points of the shape. Again, I've added 90 degrees to the rotation angle so the shapes will stand up rather than lie on their sides. Thanks again to Terry Smithwick and David Ullrich for their trig help on CompuServe.}
  for I := 0 to pts - 1 do begin
    if DoStarShape then
      if (I mod 2) = 0 then //which means that
        radius := Round(radius/2)
      else
        radius := yCenter;

    angle := ((I * rotation) + 90) * RadConvert;
    x := xCenter + Round(cos(angle) * radius);
    y := yCenter - Round(sin(angle) * radius);
    arPts[I].X := x;
    arPts[I].Y := y;
  end;

  rgn := CreatePolygonRgn(arPts, pts, WINDING);
  SetWindowRgn(wnd, rgn, TRUE);
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
  DrawEllipticRegion(Form1.Handle, Form1.ClientRect);
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  DrawPolygonRegion(Panel1.Handle, Panel1.BoundsRect, SpinEdit1.Value, False);
end;

procedure TForm1.Button3Click(Sender: TObject);
begin
  DrawRndRectRegion(Form1.Handle, Form1.ClientRect);
end;

procedure TForm1.Button4Click(Sender: TObject);
begin
  DrawPolygonRegion(Panel1.Handle, Panel1.BoundsRect, SpinEdit1.Value, True);
end;

end.

As you can see, defining and setting regions is pretty easy. Look in the help file for in-depth discussions. If you belong to the MS Developer's Network, the library CDs discuss this topic comprehensively.

 [1]

DLL文件在Delphi的创建及调用

Photoshop自定义形状工具制作个性照

Delphi下实现QQ窗体自动隐藏

--->Windows XP PowerPacker V1.0 RC9┊创建WindowsXP多启动光盘┊英文绿色免费版
--->Visual Subst V1.0.5┊从任何现有文件夹创建虚拟驱动器盘符┊汉化绿色特别版
--->Teleport Ultra(离线浏览网页、创建某个网站镜象) V1.47┊离线浏览网页、可以创建某个网站镜象┊汉化绿色特别版
--->Teleport Pro V1.48┊离线浏览某网页、创建某个网站网页镜象┊英文绿色特别版
--->ASCII Art Studio V2.1.1┊创建ASCII字符画、图片转换字符画┊汉化绿色特别版
Tags:  创建 形状 窗体

芯友网版权所有 1999-2006 | 著作权与商标声明 | 法律声明 | 服务条款 | 隐私声明 | 联系我们