` Printed Icetips Article

Icetips Article



Windows API: Double Buffering image draws
2002-09-16 -- Andy Ireland
 
Newsgroups: TopSpeed.Topic.Third_Party


Hi Ville,

> Yes, this message is sent to a window when it's background needs to
> be erased . This happens because windows are usually painted using
> a 2-stage process:
>
> - WM_ERASEBKGND: clear the background
> - WM_PAINT: draw the contents on top

It is quicker to draw everything on WM_ERASEBKGND. As for memory overhead
and speed for double buffering, it's not really noticeable. Most
applications use double buffering and it's not a problem. Likewise so does
the OS. IMO double buffering is absolutely a requirement for skinning. You
do not necessarily have to do the whole image everytime either, you could
just do the invalidated portion using the extents sent to you.

> This makes it easy to draw a windows contents, every time you receive
> a WM_PAINT message, you know that you have a nice fresh canvas to
> draw on.
> However, drawing a window twice (once with WM_ERASEBKGND and
> once again with WM_PAINT) will cause the window to flicker.
> Open up notepad, type something and then resize the window and see
> how Microsoft is demonstrating the flickering ;-)

Do the same on a professional product. Double buffering is worth it.

> Dunno what is the fundamental purpose for this property... Andy?

Double buffering probably I think it causes the image to be persisted to
a DC and all other operations drawn to same, then flushed but only SV would
know for sure. I suppose I could check this out in Boundschecker and see
what it calls.

IMO, not buffering looks worse every time. The speed hit is negligable in
the grand scheme of things and if it's not noticeable but not doing it is, I
know what I'd choose and do choose.

Here's a clarion example....

AppClient.OnPaint procedure(PWDevice DC, <*_RECT_ UpdateRect>)

Bmp             PWBitmap
sizeBmp         like(SIZE),auto
rcClient        like(_RECT_),auto
rcImage         like(_RECT_),auto
hdcMem          long,auto
hCompatBmp      long,auto
hBmpOld         long,auto
DCM             PWDevice
AppWin          &AppWindow

  code
    AppWin &= address(self.AppWin)
    if GetClientRect(self.GetHandle(), rcClient)
      hdcMem = CreateCompatibleDC(DC.GetHandle())
      if hdcMem
        hCompatBmp = CreateCompatibleBitmap(DC.GetHandle(), rcClient.right -
rcClient.left, |
          rcClient.bottom - rcClient.top)
        if hCompatBmp
          hBmpOld = SelectObject(hdcMem, hCompatBmp)
          if DCM.Init(hdcMem, false)
            if AppWin.fActive
              if Bmp.LoadBitmap(IDB_IM1)
                if Bmp.GetBitmapDimensions(sizeBmp, DCM.GetHandle())
                  GetClientRect(self.GetHandle(), rcClient)
                  rcImage.left = ((rcClient.right - rcClient.left) / 2) -
(sizeBmp.cx / 2)
                  rcImage.top = ((rcClient.bottom - rcClient.top) / 2) -
(sizeBmp.cy / 2)
                  rcImage.right = rcImage.left + sizeBmp.cx
                  rcImage.bottom = rcImage.top + sizeBmp.cy
                  assert(DCM.DrawImageAt(, rcImage.left, rcImage.top,
IDB_IM1, rcImage, 000ffffffh))
                end
                Bmp.Destruct()
              end
            end
          end
          BitBlt(DC.GetHandle(), rcClient.left, rcClient.top,
rcClient.right, rcClient.bottom, DCM.GetHandle(), 0, 0, SRCCOPY)
          SelectObject(hdcMem, hBmpOld)
          DeleteObject(hCompatBmp)
        end
        DeleteDC(hdcMem)
      end
    end
    AppWin.PaintCnt += 1
    if AppWin.PaintCnt = 2
      AppWin.fActive = true.
    return true

It draws to the memory DC first DCM, the to the DC for the window.

Regards

Andy
Plugware Solutions.com Ltd,  taking the puzzle out of I.T
Tel : +44 1249 813335
Fax : +44 1249 813462



Printed November 23, 2024, 8:21 pm
This article has been viewed/printed 35210 times.
Google search has resulted in 154 hits on this article since January 25, 2004.