Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the exact regions that need to be draw in OnPaint() event?

In a WinForm application, when subscribing to OnPaint() event, PaintEventArgs provide a ClipRectangle property that define the region to be drawn.

When the form is resized vertically or horizontally, it gives the minimum rectangle to be draw.

enter image description here

But when window is resized in both directions, there several regions that need to be draw (one on right, one at bottom) and OnPaint event merge them. It results in a rectangle having same size as Form (thus everything is redraw). What i'd like to have is individual regions separately (the two rectangles on the picture)

enter image description here

I know that GDI+ automatically clips what doesn't need to be draw (things are outside the two rectangles, not just ClipRectangle) but i'd like to minimize GDI+ calls at maximum (i already have performance issues when drawing in OnPaint event because of many GDI+ calls, this is not premature optimisation)

like image 263
tigrou Avatar asked Oct 21 '22 19:10

tigrou


1 Answers

Painting in Windows is initiated by the WM_PAINT message handler. It must call BeginPaint() to get info about what needs to be painted. Which returns a struct of type PAINTSTRUCT, it looks like this:

typedef struct tagPAINTSTRUCT {
  HDC  hdc;
  BOOL fErase;
  RECT rcPaint;              // <=== here
  BOOL fRestore;
  BOOL fIncUpdate;
  BYTE rgbReserved[32];
} PAINTSTRUCT, *PPAINTSTRUCT;

The rcPaint member is the one that you get from Graphics.ClipRectangle. The Graphics.Clip and Graphics.ClipBounds properties are not relevant, they only work if you intentionally clip yourself by assigning the Clip property.

Clearly Windows itself does not let you find out what you are asking for. rcPaint is a RECT, a simple rectangle. Windows only keeps track of a dirty rectangle, not a region. New rectangles added by InvalidateRect() are merged with the existing one and you'll indeed easily end up with the entire client area.

The only reasonable way to tackle this problem is to pay attention to the ResizeBegin and ResizeEnd events. When you get ResizeBegin then you know that the user is dragging a window edge or corner. Knowledge that you can use to optimize the painting, skipping expensive bits that make the modal resizing loop work poorly.

like image 108
Hans Passant Avatar answered Oct 24 '22 12:10

Hans Passant