トップへ(mam-mam.net/)

How to Control Clipping and Window Shapes in Delphi Using Regions Guide to CreateRectRgn and CreateEllipticRgn

Japanese

How to Control Clipping and Window Shapes in Delphi Using Regions Guide to CreateRectRgn and CreateEllipticRgn

When you want to clip part of an image or freely change the shape of a window in Delphi, the Windows API Region functions are extremely useful.
This article explains how to create rectangular, elliptical, and polygonal regions using functions such as CreateRectRgn, CreateEllipticRgn, CreatePolygonRgn, and CreateRoundRectRgn, and how to apply them for clipping and window‑shape control.
These techniques are especially helpful for tasks such as:

Sample code is included to walk you through the implementation in Delphi step by step.

API Functions for Creating Regions

The Windows API provides several functions for creating regions.

CreateEllipticRgn(x1,y1, x2,y2:Integer):HRGN;
Creates an elliptical region inscribed within the rectangle defined by the top‑left point (x1, y1) and the bottom‑right point (x2, y2).
var Rgn:HRGN;
begin
  Rgn:=CreateEllipticRgn(10,10,90,90);
  //Delete the region
  DeleteObject(Rgn);
end;
CreatePolygonRgn(Points:Array of TPoint, Count:Integer, FillMode:Integer):HRGN;
Creates a polygonal region using the vertices specified in Points.
Count specifies the number of points (vertices).
FillMode must be one of the following values:
Value Description
ALTERNATE Fills the polygon using the even‑odd rule.
A point is considered inside if a ray drawn from that point to infinity crosses the polygon edges an odd number of times.
WINDING Fills the polygon using the non‑zero winding rule.
A point is considered inside if the number of edge crossings is non‑zero.
var Rgn:HRGN;
    Points: array[0..4] of TPoint;
begin
  Points[0] := Point(90, 10);
  Points[1] := Point(10, 100);
  Points[2] := Point(120, 110);
  Points[3] := Point(10, 10);
  Points[4] := Point(60, 140);
  Rgn:=CreatePolygonRgn(Points,Length(Points),WINDING);
  //Delete the region
  DeleteObject(Rgn);
end;
CreateRectRgn(x1,y1, x2,y2:Integer):HRGN;
Creates a rectangular region defined by the top‑left point (x1, y1) and the bottom‑right point (x2, y2).
var Rgn:HRGN;
begin
  Rgn:=CreateRectRgn(10,10,90,90);
  //Delete the region
  DeleteObject(Rgn);
end;
CreateRoundRectRgn(x1,y1, x2,y2, w,h:Integer):HRGN;
Creates a rounded‑rectangle region defined by the top‑left point (x1, y1) and the bottom‑right point (x2, y2), with corner ellipse width w and height h.
var Rgn:HRGN;
begin
  Rgn:=CreateRoundRectRgn(10,10, 90,90, 10,6);
  //Delete the region
  DeleteObject(Rgn);
end;

Combining Regions

You can combine two existing regions to create a new one. To combine regions, use the CombineRgn function.

CombineRgn(RgnDest, RgnSrc1,RgnSrc2:HRGN, iMode:Integer);
Creates a new region RgnDest by combining RgnSrc1 and RgnSrc2 using the mode specified in iMode.
iMode can be one of the following values:
Value Description
RGN_AND Creates the intersection (logical AND) of the two regions.
RGN_COPY Copies RgnSrc1 (ignores RgnSrc2).
RGN_DIFF Creates the part of RgnSrc1 that is not overlapped by RgnSrc2.
RGN_OR Creates the union (logical OR) of the two regions.
RGN_XOR Creates the symmetric difference (logical XOR) of the two regions.
var Rgn1,Rgn2: HRGN;
begin
  Rgn1:=CreateRoundRectRgn(10,10, 90,90, 10,6);
  Rgn2:=CreateEllipticRgn(50,50,140,140);
  //Combine Rgn1 and Rgn2 using OR, storing the result in Rgn1
  CombineRgn(Rgn1,Rgn1,Rgn2,RGN_OR);
  //Delete regions
  DeleteObject(Rgn1);
  DeleteObject(Rgn2);
end;

Creating a Test Application

Creating the Test Project and Designing the Form

Create a new project by selecting File → New → VCL Forms Application – Delphi.

From the Tool Palette in the lower‑right pane, drag and drop two TImage components and two TButton components onto the form (Form1).

Copying an image using a clipping region created with Regions

Creating an Elliptical Region and Clipping the Image

Copy and paste the following source code into your project.
Set the OnClick event of Button1 to Button1Click,
and set the OnCreate event of Form1 to FormCreate.

Copying an image using an elliptical clipping region
Copying an image using an elliptical clipping region
unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  Bmp1,Bmp2:TBitmap;
  Rgn1: HRGN;
begin
  Bmp1:=Image1.Picture.Bitmap;
  Bmp2:=Image2.Picture.Bitmap;

  //Create an elliptical region (x1, y1, x2, y2)
  Rgn1:=CreateEllipticRgn(30, 50, 170, 150);

  //Set the region as the clipping area
  SelectClipRgn(Bmp2.Canvas.Handle, Rgn1);

  //Draw Image1.Picture.Bitmap onto Image2.Picture.Bitmap
  Bmp2.Canvas.Draw(0,0,Bmp1);

  //Delete the region
  DeleteObject(Rgn1);

  //Clear the clipping region
  SelectClipRgn(Bmp2.Canvas.Handle, 0);
end;

procedure TForm1.FormCreate(Sender: TObject);
var Bmp1,Bmp2:TBitmap;
begin
  Image1.Width:=200;
  Image1.Height:=200;
  Bmp1:=Image1.Picture.Bitmap;
  Bmp1.SetSize(Image1.Width,Image1.Height);

  Image2.Width  := Image1.Width;
  Image2.Height := Image1.Height;
  Bmp2:=Image2.Picture.Bitmap;
  Bmp2.Width:=Image1.Width;
  Bmp2.Height:=Image1.Height;

  //Draw something on Image1.Picture.Bitmap
  Bmp1.Canvas.Brush.Color:=clWhite;
  Bmp1.Canvas.FillRect(bmp1.Canvas.ClipRect);
  Bmp1.Canvas.Brush.Color:=clGreen;
  Bmp1.Canvas.FillRect(Rect(50,50,150,150));
  Bmp1.Canvas.Pen.Width:=4;
  Bmp1.Canvas.Pen.Color:=clBlue;
  Bmp1.Canvas.MoveTo(0,0);
  Bmp1.Canvas.LineTo(Bmp1.Width,Bmp2.Height);
  Bmp1.Canvas.Pen.Color:=clYellow;
  Bmp1.Canvas.MoveTo(Bmp1.Width,0);
  Bmp1.Canvas.LineTo(0,Bmp2.Height);

  //Fill Image2.Picture.Bitmap with red
  Bmp2.Canvas.Brush.Color:=clRed;
  Bmp2.Canvas.FillRect(bmp2.Canvas.ClipRect);
end;

Click Run → Run to execute the application.
When you click Button1, you will see that only the elliptical area (30, 50, 170, 150) of Image1 has been copied into Image2.

Copying an image using a clipping region created with Regions
Copying an image using a clipping region created with Regions

Setting the Window Shape to Match a Region

To change the shape of a window (its window region) to match a region, use the SetWindowRgn API function.

SetWindowRgn(hWnd:HWND; hRgn:HRGN; bRedraw:LongBool):HRGN;
Sets the window region of the window whose handle is hWnd to hRgn.
If bRedraw is True, the window is redrawn.
var Rgn:HRGN;
begin
  Rgn:=CreateRoundRectRgn(10,10, 900,900, 20,30);
  //Set the window shape to match the region
  SetWindowRgn(Self.Handle, Rgn1, True);
  //Delete the region
  DeleteObject(Rgn);
end;

Double‑click Button2 and enter the following source code.

procedure TForm1.Button2Click(Sender: TObject);
var
  Points: array[0..3] of TPoint;
  Rgn1,Rgn2: HRGN;
begin
  //Polygon points
  Points[0] := Point(0, 0);
  Points[1] := Point(Self.Width, 0);
  Points[2] := Point(Self.Width, Self.Height div 3 * 2);
  Points[3] := Point(0, Self.Height div 2);

  //Create a polygon region
  Rgn1:=CreatePolygonRgn(Points,Length(Points),WINDING);
  //Create a rectangular region (example)
  //Rgn2:=CreateRectRgn(100, 100, 180, 180);
  //Create an elliptical region
  Rgn2:=CreateEllipticRgn(0, Self.Height div 2, Self.Width div 2, Self.Height);

  //Combine Rgn1 and Rgn2 using OR, storing the result in Rgn1
  CombineRgn(Rgn1,Rgn1,Rgn2,RGN_OR);

  //Set the window shape to match the region
  SetWindowRgn(Self.Handle, Rgn1, True);

  //Delete regions
  DeleteObject(Rgn1);
  DeleteObject(Rgn2);
end;

Click Run → Run to execute the application.
When you click Button2, the window shape will change.

Changing the window shape using a region

To reset the window region, use the following:

  SetWindowRgn(Self.Handle, 0, True);

Animating the Window Shape at Application Startup Using a Region

To animate the window when the application starts, add the following source code to the OnActivate event of TForm1.

procedure TForm1.FormActivate(Sender: TObject);
var RectRgn: HRGN;
    i:Integer;
begin
  for i := 0 to 50 do
  begin
    //Create a rectangular region within the specified range
    RectRgn := CreateRectRgn(
      Width  div 2 - Width  * i div 100,
      Height div 2 - Height * i div 100,
      Width  div 2 + Width  * i div 100,
      Height div 2 + Height * i div 100
    );
    //Apply the region to the form's window
    SetWindowRgn(Handle, RectRgn, True);
    //Release the created region object
    DeleteObject(RectRgn);
    //Wait 10 ms to smooth the animation
    Sleep(10);
    //Process pending UI messages
    Application.ProcessMessages;
  end;
  //Reset the region and restore the original window shape
  SetWindowRgn(Handle, 0, True);
end;