熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Delphi編程 >> 正文

創建除三角形外的各種形狀窗體

2013-11-23 17:46:47  來源: Delphi編程 

  Is it possible to create forms with shapes other than the standard rectangular shape in Windows?

  Sometimes its 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? Its not that hard to do

  New in Win is something called a region The Win API Programmers 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 handydandy shape change functions

  To get a control to change its shape follow this twostep process:

  * Define the boundaries of the region that represent a particular shape

  * Apply the boundaries youve defined to a window

  This is pretty simple However its very important to refer to the help file and to have the source at hand I wouldnt 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 WindowPAS 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 youre interested in

  With respect to this article look up the SetWindowRgn topic in Win Developers Help and have it handy while youre putting together your program Pay particular attention to the Group hyperlink because it will give you a rundown of all the procedures related to the region topic Lets move on!

  Defining a Regions Boundary

  The first step to creating a form of a different shape is to define the shape itself For our discussion well use three WinAPI calls:

  * CreateEllipticRgn

  This function will create an ellipticallyshaped region

  * CreateRoundRectRgn

  This will create a rectangular region with rounded corners

  * CreatePolygonRgn

  This will create just about any multisided 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 Ive 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 TFormDrawEllipticRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateEllipticRgn(rectleft recttop rectright rectbottom);
  SetWindowRgn(wnd rgn TRUE);
end;

procedure TFormDrawRndRectRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateRoundRectRgn(rectleft recttop rectright rectbottom );
  SetWindowRgn(wnd rgn TRUE);
end;

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

  xCenter := (rectRight rectLeft) div ;
  yCenter := (rectBottom rectTop) div ;
  if DoStarShape then
    begin
      rotation := Degrees/(*NumPoints);
      pts := * 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 Ive added degrees to the rotation angle This is so that shapes will stand up; otherwise theyll 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 := to pts do begin
    if DoStarShape then
      if (I mod ) = then //which means that
        radius := Round(radius/)
      else
        radius := yCenter;

    angle := ((I * rotation) + ) * 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 twoliners All thats 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 redrawn In all cases if you want to see the shape youve 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 Ive 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 thatll be defining the shape Heres the code:

unit regmain;

interface

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

type
  TForm = class(TForm)
    Button: TButton;
    Button: TButton;
    Button: TButton;
    SpinEdit: TSpinEdit;
    Button: TButton;
    Panel: TPanel;
    Edit: TEdit;
    procedure DrawRndRectRegion(wnd : HWND; rect : TRect);
    procedure DrawEllipticRegion(wnd : HWND; rect : TRect);
    procedure DrawPolygonRegion(wnd : HWND; rect : TRect; NumPoints : Integer; DoStarShape : Boolean);
    procedure ButtonClick(Sender: TObject);
    procedure ButtonClick(Sender: TObject);
    procedure ButtonClick(Sender: TObject);
    procedure ButtonClick(Sender: TObject);
  private
    { Private declarations }
    rgn : HRGN;
    rect : TRect;
  public
    { Public declarations }
  end;

var
  Form: TForm;

implementation

{$R *DFM}

procedure TFormDrawRndRectRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateRoundRectRgn(rectleft recttop rectright rectbottom );
  SetWindowRgn(wnd rgn TRUE);
end;

procedure TFormDrawEllipticRegion(wnd : HWND; rect : TRect);
begin
  rgn := CreateEllipticRgn(rectleft recttop rectright rectbottom);
  SetWindowRgn(wnd rgn TRUE);
end;

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

  xCenter := (rectRight rectLeft) div ;
  yCenter := (rectBottom rectTop) div ;
  if DoStarShape then
    begin
      rotation := Degrees/(*NumPoints);
      pts := * 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 Ive added 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 := to pts do begin
    if DoStarShape then
      if (I mod ) = then //which means that
        radius := Round(radius/)
      else
        radius := yCenter;

    angle := ((I * rotation) + ) * 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 TFormButtonClick(Sender: TObject);
begin
  DrawEllipticRegion(FormHandle FormClientRect);
end;

procedure TFormButtonClick(Sender: TObject);
begin
  DrawPolygonRegion(PanelHandle PanelBoundsRect SpinEditValue False);
end;

procedure TFormButtonClick(Sender: TObject);
begin
  DrawRndRectRegion(FormHandle FormClientRect);
end;

procedure TFormButtonClick(Sender: TObject);
begin
  DrawPolygonRegion(PanelHandle PanelBoundsRect SpinEditValue True);
end;

end

  As you can see defining and setting regions is pretty easy Look in the help file for indepth discussions If you belong to the MS Developers Network the library CDs discuss this topic comprehensively


From:http://tw.wingwit.com/Article/program/Delphi/201311/25060.html
    推薦文章
    Copyright © 2005-2013 電腦知識網 Computer Knowledge   All rights reserved.