How to implement your own double buffering (Views: 100)


In order to give a control the appearance of being "transparent", in the WM_EraseBkgnd message processing section I'm invalidating the rectangle the control covers in the parent control's context and then having the parent control repaint itself in the rectangle that's hidden behind the control. However, this doesn't work when the control's DoubleBuffer property is set to true. Does anyone know how to get this working with double buffered controls?


VCL double-buffering is ineffective and limited. If you need double-buffering, you will need to implement it yourself. To do this process the WM_PAINT message and do something like this:

1) Do your own effective double-buffering:

procedure TCustomElPanel.WMPaint(var Msg: TWMPaint);
  DC, MemDC: HDC;
  MemBitmap, OldBitmap: HBITMAP;
  PS: TPaintStruct;
  R: TRect;
  ARgn: HRGN;
  if (Msg.DC <> 0) then
    DC := GetDC(0);
    MemBitmap := CreateCompatibleBitmap(DC, ClientRect.Right, ClientRect.Bottom);
    ReleaseDC(0, DC);
    MemDC := CreateCompatibleDC(0);
    OldBitmap := SelectObject(MemDC, MemBitmap);
      DC := BeginPaint(Handle, PS);
      GetClipBox(DC, R);
      if IsRectEmpty(R) then
        R := ClientRect
        InflateRect(R, 1, 1);
      with R do
        ARgn := CreateRectRgn(Left, Top, right, Bottom);
      SelectClipRgn(MemDC, ARgn);
      Perform(WM_ERASEBKGND, MemDC, MemDC);
      Msg.DC := MemDC;
      SelectClipRgn(MemDC, 0);
      Msg.DC := 0;
      with R do
        BitBlt(DC, Left, Top, Right, Bottom, MemDC, Left, Top, SRCCOPY);
      EndPaint(Handle, PS);
      SelectObject(MemDC, OldBitmap);

2) When painting, ask your parent to draw on your canvas or do the following:

{ ... }
if Transparent then
  GetClipBox(Canvas.Handle, Rect);
  OffsetRect(Rect, Left, Top);
  RedrawWindow(Parent.Handle, @Rect, 0, RDW_ERASE or RDW_INVALIDATE or
    OffsetRect(Rect, -Left, -Top);
    DC := GetDC(Handle);
    bitblt(Canvas.Handle, 0, 0, Rect.Right - Rect.Left, Rect.Bottom - Rect.Top,
      DC, Rect.Left, Rect.Top, SRCCOPY);
    ReleaseDC(Handle, DC);
{ ... }

<< Back to main page