创建除三角形外的各种形状窗体
点击次数:70 次 发布日期:2008-11-09 08:41:39 作者:源代码网
|
源代码网推荐 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; 软件开发网 www.mscto.com 源代码网推荐 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; 软件开发网 www.mscto.com 源代码网推荐 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; 软件开发网 www.mscto.com 源代码网推荐 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. 源代码网推荐 源代码网供稿. |
