How to make Invalidate only part of paintbox / bitmap to optimize its performance?

The question arises: Draw on paintwork - How to keep up with mouse movements without delay?

I was going to ask at some point the question of how to repaint only a portion of Paintbox without invalidating the entire paintbox, which is slow when there is a lot of painting going on or in my case when there are a lot of tiles drawn on the screen.

From the link above, Peter Kostov touched on the topic in one of his comments:

you can partially paint the bitmap with BitBlt (only in the regions where it was changed). This will greatly improve performance.

I have limited graphic skills and have never used it before BitBlt

, but I will read more about it after posting this question.

Having said that, I wanted to know how exactly could you determine if areas of a bitmap have changed? Does it have something to do with something simple, or is there even more magic, so to speak, in determining which regions have changed?

Right now I am still painting directly in paintbox, but once I paint into an offscreen buffer bitmap, my next step is to optimize the painting, and the comments above sound exactly like I needed, only the changed areas of change confused me a little.

Of course, if there are other ways to do this, feel free to comment.

Thank.

+3


source to share


2 answers


You don't need to use BitBlt()

directly, if you are drawing on the screen TBitmap

, you can use TCanvas.CopyRect()

instead (which uses StretchBlt()

internally). But in any case, when you only need to invalidate a part TPaintBox

(the part that is related to the section of the off-screen bitmap that you drew), you can use InvalidateRect()

to specify the appropriate rectangle TPaintBox

instead of calling TControl.Invalidate()

(which calls InvalidateRect()

with the parameter lpRect

set to NULL). Whenever the event fires TPaintBox.OnPaint

will InvalidateRect()

set a clipping rectangle inside the canvas, any drawing you make outside of that rectangle will be ignored. If you want to manually optimize your drawing, you can use the propertyTCanvas.ClipRect

to define the rectangle TPaintBox

to draw and simply copy that portion from your screen bitmap.



Only result: TPaintBox

is a child TGraphicControl

, so it doesn't have its own HWND to pass to InvalidateRect()

. You will have to use its Parent.Handle

HWND instead . This means that you would need to translate TPaintBox

-relative coordinates to Parent

-relation coordinates and vice versa when needed.

+4


source


To do this, you need to take responsibility for the painting:

  • Call InvalidateRect

    to invalidate parts of the window.
  • On processing, WM_PAINT

    you call BeginPaint

    which gives a paint structure containing a rectangle to paint.


It requires a window, and unfortunately TPaintBox

not over for you . This way you can use the window handle of the parent control, but frankly it would be cleaner to use the windowed control.

As a starting point, you can use my window paint control from this question: How can I go to / from a TImage? Use ClipRect

the canvas control while painting to identify the part of the canvas that needs re-painting.

+2


source







All Articles