Search code examples
delphibitmappaintclipping

Delphi SelectClipRGN Hides Drawn Bitmap


I am drawing a custom background (derived from TGraphicControl) with a border. After drawing the border in the DrawBorderRect function, I return the "client" area, and want to limit future painting to this new region. Everything works if I do not use a ClipRgn.

Working Code:

var
  R : TRect;

begin;
  R := GetClientRect;     //(R -> 0, 0, 300, 200)
  R := DrawBorderRect(R); //(R -> 20, 20, 280, 180)
  Canvas.StretchDraw(R, FBitmap); //FBitmap is a 3 pixel x 3 pixel square
end;

Above code gives me this:Output without ClipRGN

But, I want to use ClipRgn, and I have tried the following. The pattern is not shown this time (But, if I click the mouse button on the area then the pattern shows. So it is working kind of working, but then gets overwritten for some reason ?).

Problematic code:

var
  R : TRect;
  ClientRegion: HRGN;

begin;
  R := GetClientRect;     //(R -> 0, 0, 300, 200)
  R := DrawBorderRect(R); //(R -> 20, 20, 280, 180)

  ClientRegion := CreateRectRgn(R.Left, R.top, R.Right, R.Bottom);
  SelectClipRgn(Canvas.Handle, ClientRegion);
  try
    Canvas.StretchDraw(R, FBitmap); //FBitmap is a 3 pixel x 3 pixel square
  finally
    SelectClipRgn(Canvas.Handle, HRGN(nil));
    DeleteObject(ClientRegion);
  end;
end;

and I get this (unless I click the left mouse button in which case I see the above) Output with ClipRGN

Any insights as to what is going on, and what am I missing?


Solution

  • SelectClipRgn assumes device coordinates.

    TGraphicControl descendants have a device context retrieved for their parent window. The viewport origin is moved to be able to set the client origin to (0, 0), but they are logical coordinates.

    In short, you need to offset your region:

    ...
    ClientRegion := CreateRectRgn(R.Left, R.top, R.Right, R.Bottom);
    OffsetRgn(ClientRegion, Left, Top);           // <--
    SelectClipRgn(Canvas.Handle, ClientRegion);
    ...