Discussion:
Is win32-gdi system-driven WM_PAINT flicker free?
(too old to reply)
Elemich
2021-03-10 11:29:48 UTC
Permalink
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
2021-03-10 11:36:50 UTC
Permalink
is not possible to pretty-formatting the code?
R.Wieser
2021-03-10 12:06:40 UTC
Permalink
Elemich,
Post by 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.
Post by Elemich
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
2021-03-10 12:33:07 UTC
Permalink
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
2021-03-10 17:02:35 UTC
Permalink
Elemich,
Post by 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.
Post by Elemich
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.
Post by Elemich
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
2021-03-10 17:41:51 UTC
Permalink
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
2021-03-10 17:44:18 UTC
Permalink
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
2021-03-10 19:23:14 UTC
Permalink
Elemich,
Post by 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
2021-03-10 20:24:39 UTC
Permalink
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
2021-03-11 07:30:19 UTC
Permalink
Post by Elemich
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
2021-03-11 09:22:08 UTC
Permalink
JJ,
Post by JJ
Post by Elemich
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
2021-03-12 13:42:29 UTC
Permalink
Post by R.Wieser
JJ,
Post by JJ
Post by Elemich
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".
That's exactly why.
R.Wieser
2021-03-12 14:12:49 UTC
Permalink
JJ,
Post by 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

Loading...