1. Technology

Holiday Greetings With Windows Regions and Stars

Regional Government - or Stars in Their Eyes

By

Article submitted by Alan Lloyd

Windows regions are specifiers of regular or irregular areas, and are used when sensing mouse activity or display limits.

Having defined a region one can use PtInRgn() to test whether a point (X, Y) is in the region. Or allocate the region to a window to limit the display and mouse influence to that region. Regular shaped regions can be specified by simple region creating functions (CreateEllipticRgn, CreateRectRgn), more complex regions can be specified by CreatePolygonRgn, CreatePolyPolygonRgn or a number of other region manipulating APIs.

Regions can also be specified by drawing a path, and using PathToRegion to convert the path to a region. As an example of paths & regions here is an example of drawing a pentacle - a five-pointed star.

A pentacle or a pentagon consists of points at (moving anti-clockwise) centre-top, left-mid, left-bottom, right-bottom and right-mid. If the points are specified in this order one draws a pentagon, to draw a pentacle one must draw alternately, specifying consecutively drawn points at centre-top, left-bottom, right-mid, left-mid, right-bottom, centre-top.

To specify the points one must indulge in some geometry, as follows, to obtain the points as offsets relative to the centre-top point.

var
  Size, // direct distance between adjacent pentacle points
  DX1, DY1, DX2, DY2 : integer; // position increments from centre-top point
const  
// some trigonometric values, or use Maths unit
  Cos54 = 0.588;
  Sin54 = 0.809;
  Tan72 = 3.078;
begin
  Size := 250;  
  {calculate the increments of points from centre-top}
  {left-mid & right-mid increments}
  DX1 := trunc(Size * Sin54);
  DY1 := trunc(Size * Cos54);
  {left-bottom & right-bottom increments}
  DX2 := Size div 2;
  DY2 := trunc(Size * Tan72 / 2);
...
The above are offsets from the centre-top point, but we will need them from the top-left of a rectangle enclosing the pentacle, ie -DX1, 0 from the centre-top. We could just calculate this directly, but so that we may position the pentacle anywhere relative to the top points, I use an additional
var {of form scope}
  HRgn : THandle;

var
  FPent : array[0..4] of TPoint;
  XOffset, YOffset : integer;
  BM : TBitMap;
begin
  XOffset := trunc(Size * Sin54 + 10);  // half width of star plus a bit ...
  YOffset := 10;                        // ... a bit down too
  {now specify the points of the pentagon (anti-clock order)}
  FPent[0] := point(XOffset, YOffset);              // centre-top
  FPent[1] := point(XOffset - DX1, YOffset + DY1);  // left-mid
  FPent[2] := point(XOffset - DX2, YOffset + DY2);  // left-bottom
  FPent[3] := point(XOffset + DX2, YOffset + DY2);  // right-bottom
  FPent[4] := point(XOffset + DX1, YOffset + DY1);  // right-mid
Now get a canvas, draw the pentacle on it as a path and convert it to a region
BM := TBitmap.Create;
BeginPath(BM.Canvas.Handle);
{...set the fill mode to fill in the central polygon}
SetPolyFillMode(BM.Canvas.Handle, WINDING);  
with BM.Canvas do 
begin
  MoveTo(FPent[0].X, FPent[0].Y);
  for j := 1 to 5 do
   with FPent[(j * 2) mod 5] do // go round alternate points joining them
     LineTo(X, Y);
end{with BM.Canvas}
EndPath(BM.Canvas.Handle);
{... turn the path into a region}
HRgn := PathToRegion(BM.Canvas.Handle);
BM.Free;
WINDING in SetPolyFillMode includes the central pentagon in the region. ALTERNATE would exclude the central pentagon, and our form would have a pentagonal hole in it. WINDING & ALTERNATE have a more complex description of exactly how they work. See MSDN for more details.

Now we can allocate the region to a window & get a pentacle- (star-) shaped window.

In procedure TForm1.FormCreate

SetWindowRgn(Self.Handle, hRgn, true);
The form must initially be big enough to contain the pentacle - ie at least FPent[0].X * 2 wide by FPent[4].Y height. The region is in window co-ordinates with 0, 0 at the window’s top-left. So you may see a little of the form’s title bar in the top point of the star.

... and in FormClose when you’ve finished ...

DeleteObject(HRgn);
There are many other region manipulations (combining, moving etc). see MSDN for more information.

I could, of course, have used CreatePolygonRgn to make the region, specifying the points as a polygon in alternating order, but now you know a bit more about paths as well as regions .

Download "Stars" Source Code

©2014 About.com. All rights reserved.