Discussion:
How to use InvalidateRect
(too old to reply)
Mkennedy1102
2007-05-21 01:45:00 UTC
Permalink
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
InvalidateRect? According to MSDN :

"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."

How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
Mkennedy1102
2007-05-21 01:59:01 UTC
Permalink
Post by Mkennedy1102
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."
How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
Update:
After some testing, I realize that whats happening is this;

OnPaint draws text into the CRect;
text changes;
InvalidateRect is called;
text is redrawn into rect, however the old text is not erased entirely, only
what is covered by the new text, mind you, its not being drawn on top of the
old text its more like it's repacing it. I need some way to completely erase
what was there before I redraw.
Scott McPhillips [MVP]
2007-05-21 04:33:33 UTC
Permalink
Post by Mkennedy1102
Post by Mkennedy1102
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."
How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
After some testing, I realize that whats happening is this;
OnPaint draws text into the CRect;
text changes;
InvalidateRect is called;
text is redrawn into rect, however the old text is not erased entirely, only
what is covered by the new text, mind you, its not being drawn on top of the
old text its more like it's repacing it. I need some way to completely erase
what was there before I redraw.
The default OnEraseBkgnd should erase the invalid area. If you have
overridden it then you have to erase things yourself (by drawing a
rectangle of the desired background color before painting the content).

When you use InvalidateRect to optimize painting, the trick you seem to
be missing is that your OnDraw function can call pDC->GetClipBox to find
out what needs repainting. Then paint only what is required by the
GetClipBox rect.

Absolutely, positively, do not call OnDraw, OnPaint or post WM_PAINT
yourself. Calling Invalidate or InvalidateRect is the only correct way
to initiate a repaint.
--
Scott McPhillips [MVP VC++]
Mkennedy1102
2007-05-22 00:14:01 UTC
Permalink
Indeed I have overridden OnEraseBkgnd to make the backgorund green, after
reading your post, I went back and looked at it again. It turns out that the
handler was the culprit. with a little tweaking (including implementing
GetClipRect, thanks for that tip!) Everything is working great, thanks for
your assistance!
Post by Scott McPhillips [MVP]
Post by Mkennedy1102
Post by Mkennedy1102
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."
How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
After some testing, I realize that whats happening is this;
OnPaint draws text into the CRect;
text changes;
InvalidateRect is called;
text is redrawn into rect, however the old text is not erased entirely, only
what is covered by the new text, mind you, its not being drawn on top of the
old text its more like it's repacing it. I need some way to completely erase
what was there before I redraw.
The default OnEraseBkgnd should erase the invalid area. If you have
overridden it then you have to erase things yourself (by drawing a
rectangle of the desired background color before painting the content).
When you use InvalidateRect to optimize painting, the trick you seem to
be missing is that your OnDraw function can call pDC->GetClipBox to find
out what needs repainting. Then paint only what is required by the
GetClipBox rect.
Absolutely, positively, do not call OnDraw, OnPaint or post WM_PAINT
yourself. Calling Invalidate or InvalidateRect is the only correct way
to initiate a repaint.
--
Scott McPhillips [MVP VC++]
Joseph M. Newcomer
2007-05-21 11:41:44 UTC
Permalink
See below...
Post by Mkennedy1102
Post by Mkennedy1102
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."
How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
After some testing, I realize that whats happening is this;
OnPaint draws text into the CRect;
text changes;
InvalidateRect is called;
text is redrawn into rect, however the old text is not erased entirely, only
what is covered by the new text, mind you, its not being drawn on top of the
old text its more like it's repacing it. I need some way to completely erase
what was there before I redraw.
*****
Yes, that is the correct and expected behavior. You need to redraw everything
(EVERYTHING) in the rectangle; failure to redraw everything means that the old material
remains.

Do you have an OnEraseBkgnd handler? What does it do? What is the nature of what you are
painting on top of? How is it redrawn? Looking only at a small piece of the program does
not enable us to deduce what kind of program you have, or anything about the images.
joe
*****
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Mkennedy1102
2007-05-22 00:24:01 UTC
Permalink
Post by Joseph M. Newcomer
See below...
Post by Mkennedy1102
Post by Mkennedy1102
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."
How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
After some testing, I realize that whats happening is this;
OnPaint draws text into the CRect;
text changes;
InvalidateRect is called;
text is redrawn into rect, however the old text is not erased entirely, only
what is covered by the new text, mind you, its not being drawn on top of the
old text its more like it's repacing it. I need some way to completely erase
what was there before I redraw.
*****
Yes, that is the correct and expected behavior. You need to redraw everything
(EVERYTHING) in the rectangle; failure to redraw everything means that the old material
remains.
Do you have an OnEraseBkgnd handler? What does it do? What is the nature of what you are
painting on top of? How is it redrawn? Looking only at a small piece of the program does
not enable us to deduce what kind of program you have, or anything about the images.
joe
*****
Joseph M. Newcomer [MVP]
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Joe-
As I mentioned in my reply to Scott, it was in fact the OnEraseBkgnd handler
that was causing the problem, which I couldn't understand yesterday, since
all it does is paint the view green. The text in question is simply drawn
over the green background, so I thought that the handler should be taking
care of it. In any case, both you and Scott steered me in the right
direction in spite of my sketchy description of the problem, so thanks! I
really appreciate that you guys are willing to spend the time helping guys
like me.

Joseph M. Newcomer
2007-05-21 11:39:18 UTC
Permalink
What is the value in rect.?
Post by Mkennedy1102
I want to redraw only a portion of my View, for example I have a CRect in the
lower right corner where my app draws some text, I want to redraw that rect
when the info changes, so if that CRect is named rect, I call
InvalidateRect(&rect) (the berase parameter is moot in this case). However
this does nothing. If I call Invalidate() to repaint the screen, it works
fine, but I want to reduce my drawing overhead. Where am I going wrong with
"The invalidated areas accumulate in the update region until the region is
processed when the next WM_PAINT message occurs or until the region is
validated by using the ValidateRect or ValidateRgn function."
How do I make that happen? I have tried PostMessage(WM_PAINT), I have tried
calling OnPaint from within my code. I must be missing something here. Much
thanks for any help.
*****
Both of the above would be wrong. In fact, erroneous. You must never do either, at any
time, for any reason whatsoever.

Presumably, after having done the InvalidateRect, you will return to the message pump so
the OnPaint request can be dispatched. If you do not, your window will not repaint.

If you are in such a situation, you can call UpdateWindow, which will force the window to
repaint.
joe
*****
Joseph M. Newcomer [MVP]
email: ***@flounder.com
Web: http://www.flounder.com
MVP Tips: http://www.flounder.com/mvp_tips.htm
Continue reading on narkive:
Loading...