Is win32-gdi system-driven WM_PAINT flicker free?

42 views
Skip to first unread message

Elemich

unread,
Mar 10, 2021, 6:29:50 AMMar 10
to
running this code leads to the title question:

if you resize the window you will not see any flicker (repaint sended by the system)
if you move mouse inside the window, severe flicker will occurr (repaint sended by me)

how to reproduce the system-driven WM_PAINT?

#include <windows.h>
#include <wingdi.h>

LRESULT CALLBACK proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch(msg)
{
case WM_ERASEBKGND: return true;break;
case WM_MOUSEMOVE: InvalidateRect(hwnd, 0, 0); break;
case WM_PAINT:
{
InvalidateRect(hwnd,0,0);
HBRUSH b= CreateSolidBrush(0x000000ff);
HBRUSH c= CreateSolidBrush(0x0000ff00);
HBRUSH d= CreateSolidBrush(0x00ff0000);
RECT r;
GetClientRect(hwnd,&r);
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
FillRect(hdc,&r, b);
Sleep(10);
FillRect(hdc,&r, c);
` Sleep(10);
FillRect(hdc,&r,d);
EndPaint(hwnd,&ps);
DeleteObject(b);
DeleteObject(c);
DeleteObject(d);
}
break;
default:
return DefWindowProc(hwnd, msg, wparam, lparam);
}
return 0;
}
int main()
{
HWND hwnd=CreateWindow(WC_DIALOG,0,WS_OVERLAPPEDWINDOW|WS_VISIBLE,0,0,500,500,0,0,0,0);
SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)proc);

MSG msg;

while (true)
{
if (GetMessage(&msg, 0, 0, 0) != WM_CLOSE)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return 1;
}

Elemich

unread,
Mar 10, 2021, 6:36:52 AMMar 10
to
is not possible to pretty-formatting the code?

R.Wieser

unread,
Mar 10, 2021, 7:06:53 AMMar 10
to
Elemich,

> if you move mouse inside the window, severe flicker will
> occurr (repaint sended by me)

Question: why do you think you should force a repaint on any kind of mouse
movement ?
Suggestion: don't.

Question: why are you (trying to) invalidate the rectangle *inside* the very
event that is called as a response to it ? I think you're lucky that the
re-validation step happens at the end, otherwise you would have had a
blinkfest ...
Suggestion: remove it.

And I hope you realize that putting a Sleep() in that (or any) event is a
big no-no. User timers (that fire events and do your stuff in there).

Furthermore, its rather informative to us when you mention what the
codesample is supposed to be doing.

> is not possible to pretty-formatting the code?

This is a newsgroup, not some HTML RTF forum. :-) Besides, whats wrong
with the formatting you used ? It looks pretty readable to me. For
everything else just use code comments.

Regards,
Rudy Wieser


Elemich

unread,
Mar 10, 2021, 7:33:08 AMMar 10
to
dear Wieser, this code is to show that the WM_PAINT after the WM_SIZE is a particular type of WM_PAINT, handed differently from other WM_PAINTs,
for this reason the Sleep serves to show the flickering and the invalidateRect inside the paint routine serves to forcing to repaint the entire area as you can see checking the ps.rcPaint rectangle.
have you tried to compile and running this snippet?
thank you for your time

R.Wieser

unread,
Mar 10, 2021, 12:02:52 PMMar 10
to
Elemich,

> this code is to show that the WM_PAINT after the WM_SIZE is a particular
> type of WM_PAINT, handed differently from other WM_PAINTs

I can see you have taken the normal paint event and filled it with your own
code (ignoring the default). I do not see how its a "particular type of"
paint though.

> for this reason the Sleep serves to show the flickering and the
> invalidateRect
> inside the paint routine serves to forcing to repaint the entire area as
> you can
> see checking the ps.rcPaint rectangle.

What I see is that *you* are purposely creating a (color) flickering.

> have you tried to compile and running this snippet?

Why would I do that ? I allready know that it will flicker.

I *think* you want to point out some kind of problem, but you still have to
describe what that problem actually is (what I should be looking for/at).
And no, pointing to that (color) flicker you yourself introduced doesn't
help in the slightest I'm afraid.

All I can currently tell you is *not* to put time-consuming (drawing)
actions in the paint event.

Regards,
Rudy Wieser


Elemich

unread,
Mar 10, 2021, 12:41:53 PMMar 10
to
Rudy

i think you have not grasped the question:

the paint routine in WM_PAINT handler shows that if it happens from a WM_SIZE , that is, a system-driven event at least in this case, the result will not flicker;
if the WM_PAINT happens from the WM_MOUSEMOVE event, that is, a user-driven event at least in this case, the result will flicker abundantly.

now the question is: is system-driven WM_PAINT acts differently from a user-driven WM_PAINT?

i hope you understand now.

thank you

Elemich

unread,
Mar 10, 2021, 12:44:20 PMMar 10
to

> Why would I do that ? I allready know that it will flicker.

if you'll try you discover resizing the windows will not flickers

R.Wieser

unread,
Mar 10, 2021, 2:23:31 PMMar 10
to
Elemich,

> the paint routine in WM_PAINT handler shows that if it happens
> from a WM_SIZE , that is, a system-driven event at least in this
> case, the result will not flicker;
> if the WM_PAINT happens from the WM_MOUSEMOVE event,
> that is, a user-driven event at least in this case, the result will
> flicker
> abundantly.

Yeah, funny how that can happen when you call 'InvalidateRect' in the
'mousemove', but *not* in the 'size' event. In other words, you are
cheating. :-)

Regards,
Rudy Wieser


R.Wieser

unread,
Mar 10, 2021, 3:24:56 PMMar 10
to
Elemich,

To show you what the effect of that 'InvalidateRect' is would like you to
make a few changes to your code.

Create a 'global' variable, initialize it with 0xFF0000 and use it as the
color for brush "d". After each "d" brush creation add something to that
color (I add 0x10 to the third byte, the FF / blue color)

On my puter I see the window change color when I move the mouse over it, or
when I enlarge the window. No color change when I shrink the window.

When I remove the 'InvalidateRect' inside the 'paint' event the whole window
still changes color when I move the mouse over it. But now take a look at
what happens when you enlarge the window ...

If you see the same as I do you see colored bands appear where you enlarged
the window, *but not where that window already existed*.

IOW, your code still *tries* to color the whole window, but due to only the
newly-added space being invalidated (by "the system") the drawing changes
only occur there. And likely you do not see any flickering (that you
programmed) *even though its still there* because there is too much change
going on - the border of the window moving and making place for some empty
window space.

Also notice that when you move the left border left or the top border up the
colored bands appear on the right or bottom. IOW : The moved part of the
window is /not/ redrawn at all. That is, as long as you do not invalidate
the whole window. Take a guess what happens when you also put an
'InvalidateRect' in the 'size' event. :-)

Also:
[quote]
if you resize the window you will not see any flicker (repaint sended by the
system)
if you move mouse inside the window, severe flicker will occurr (repaint
sended by me)
[/quote]
In neither case *you* are sending the repaint request. In the latter case
its send by "the system" as a result of it recognising that some visible
area has been marked as "changed" (that is what "invalidated" is supposed to
mean).

Suggestion : invalidate *a small part* of the window. Like a square of
10*10 pixels in the top-left corner.

Before you execute that, imagine what you think will happen. Also try to
reason why you think it would happen. And ? Does the result match your
imagination ?

Regards,
Rudy Wieser


JJ

unread,
Mar 11, 2021, 2:30:44 AMMar 11
to
On Wed, 10 Mar 2021 03:29:48 -0800 (PST), Elemich wrote:
> running this code leads to the title question:
>
> if you resize the window you will not see any flicker (repaint sended by the system)
> if you move mouse inside the window, severe flicker will occurr (repaint sended by me)
>
> how to reproduce the system-driven WM_PAINT?

Because the code directly draw on the application window, AND with added
delays, you'll see the progress as flickers.

Use a technique called double buffering. Make the code draw on a separate
(off screen) bitmap first, then draw the bitmap onto the application window.
It'll be a relatively slower process, but it'll minimize flickers. i.e. the
display will be updated less frequently, but it'll minimize flickers.

However, if the area which need to be redrawn is large enough, it will still
cause noticable flicker if the computer is not fast enough. IOTW, the whole
process still take too much time to complete for the computer. That's where
you'll notice the progress of the process. That's what flickers are when
those process are done repeatedly.

R.Wieser

unread,
Mar 11, 2021, 4:22:28 AMMar 11
to
JJ,

>> how to reproduce the system-driven WM_PAINT?
>
> Because the code directly draw on the application window,
> AND with added delays, you'll see the progress as flickers.
>
> Use a technique called double buffering.

The question is not how to minimize the flicker, but why "the system"s paint
doesn't, and his paint does flicker (even though he and "the system" execute
the same, his paint code). He simply doesn't yet know what effect
"invalidaterect" (the whole screen) has. Currently he just uses it to
force a paint event to happen, but forgets to recon with its "side effects".

Regards,
Rudy Wieser


JJ

unread,
Mar 12, 2021, 8:43:03 AMMar 12
to
That's exactly why.

R.Wieser

unread,
Mar 12, 2021, 9:13:08 AMMar 12
to
JJ,

> That's exactly why.

Nope. You're offering a solution to a problem he doesn't have.

The problem he has is that he doesn't understand why the very code he wrote
himself seems to act differently when its called "by himself" or "by the
OS".

He seems to assume that the OS either executes its own, different code, or
does something special to make sure that the flickering doesn't occur.
Neither is true. The cause/answer is way simpler. Which is what I tried to
explain

Regards,
Rudy Wieser


Reply all
Reply to author
Forward
0 new messages