WM_PAINT confuses me

WM_PAINT confuses me

I'm having a lot of trouble with WM_PAINT. In the following, I have stripped the code to the essential parts that demonstrate my problem. Subroutine AnaStart creates a toolbar and some on-screen tool buttons, while AnaRefresh displays a geographical map.

NewAnaScreen = .true.
call AnaStart(hWnd,themes,hWndAnaTB,hWndAnaPB)
NewAnaScreen = .false.
end if
call AnaRefresh(hWnd,rect)
iret = SetFocus(ghWndMain)
iret = EndPaint(hWnd,ps)
MainWndProc = 0

I would like to see the tool bar displayed first (more or less instantly), then the map being painted (this may take several seconds for a detailed map). What I always see is the map first, then the toolbar. In fact it's worse than that because the map gets painted twice before the toolbar appears. I have proved by debugging that AnaStart is called first every time, but AnaRefresh always runs twice before the product of AnaStart appears.

I'm very confused and would be very grateful for some insight.

With many thanks in advance,


5 posts / 0 new
Last post
For more complete information about compiler optimizations, see our Optimization Notice.

Huh... -- don't do that -- only BeginPaint->GDI calls->EndPaint should be in WM_PAINT block. Purpose of WM_PAINT is that Windows tell you that (a part of) your window has became visible (unobscured by other windows) and that you should draw on that part; that's all you're supposed to do.

What happens here is that, when AnaStart creates a toolbar, it (supposedly) moves or obscures the part of hWnd. Something of the following happens:

- Some of API functions you didn't show us somehow generate another WM_PAINT so in effect you get a recursive call to your WindowProc -- check it with "call stack" debug window.

- Another scenario is that, after the toolbar is created, WM_PAINT is sent to the parent first, before the toolbar is to be initially drawn.

Whatever the case is, do not create anything on WM_PAINT. Create your toolbar when "NewAnaScreen" event occurs (i.e. instead of setting it to .TRUE., just create the toolbar). If I have to guess, perhaps the code you showed came out as a consequence that you couldn't have gotten toolbar to redraw properly, butyour cure is wrong; instead, take a look at WS_CLIPCHILDREN style for the parent. Best, create a borderless "view window" child between the toolbar and the progress bar which will serve only for drawing purposes (leaving the frame window's client area 100% obscured by these three). Point Spy++ to e.g. Internet Explorer window to see the layout of its children, and/or take a look at XGraph sample at my home page (it's XFT, but it's rather clear -- take a look at OnSize handler).



Thankyou Jugoslav once again, I'm beginning to understand at last.

I have made changes as you suggested and it nearly works perfectly now. The only thing that puzzles me is the fact that the toolbar appears before the map is drawn (as it should) but the buttons on it don't appear until after the map is drawn.

I'm adding the buttons in my routine AnaStart with:

iret = SendMessage(hWndAnaTB,TB_ADDBUTTONSA,23,LOC(TBbutton))

I guess there's something I don't understand about the processing of messages. Do you have any suggestions?

With many thanks


Are you saying that your map drawing is so slow that you can see the order in which the windows are drawn? (Since you're working on a GIS, that doesn't surprise me too much as I can imagine that the drawing can be very complex).

Further, which parts of my suggestion did you implement? In this short time, I assume you only moved toolbar creation elsewhere and added WS_CLIPCHILDREN. If that's the case, I can only guess that the order of WM_PAINT and WM_NCPAINT is such that the order is:

- WM_NCPAINT for the parent
- WM_NCPAINT for the child (toolbar)
- WM_PAINT for the parent (long map drawing)
- WM_PAINT for the child (toolbar) -- you have to wait until the previous one is completed to see the buttons.

I've just verified that using Spy++.
So, you will probably have to go for "view window" architecture as well. (This requires some code changes, so that you'll have to split FrameWindowProc into two, and move WM_PAINT block into ViewWindowProc).

Then, I'm affraid, you will have to pay attention to optimization of drawing as well. Several suggestions:

- If you always draw entire picture in WM_PAINT, ensure that WNDCLASS.hbrBackground is NULL -- that will partly eliminate the flicker
- Implement double-buffering (see XDblBuffer2 sample on my home page, under XFT Downloads)
- Minimize the number of GDI operations. That means, if you implement zooming, on high zoom levels you should not render entire picture, but just the visible part; OTOH, on low zoom levels, you should probably skip drawing of tiny details.

Such optimizations can range from simple ones to really mind-boggling (a guy from my company implemented some really flashing but complicated stuff). A relatively simple schema I implemented once is:

- Divide themap into a NxN matrix. For each square, create a list of objects that belong/intersect it in advance.
- When a part is zoomed or the scrollbar is moved, calculate which squares of the matrix intersect the visible screen.
- Draw only the objects belonging to visible squares.



Hi Jugoslav,

I've been trying not to burden you with actual details of my application, but you seem to be able to guess much of it anyway. Yes, it's a GIS which potentially can be called upon to display mega amounts of data in one screen - topographical and cadastral details over 100000 sq Km or more.

You also guessed correctly that I have only so far implemented the first parts of your suggestion - move the toolbar creation, and add WS_CLIPCHILDREN. And this works very well nearly all the time.

Your explanation of the order of painting was what I most needed - thankyou, I understand now, but before I had not even heard of WM_NCPAINT. As for optimizations, about half of what you suggest is already operational, for example, when zoomed in, only those parts of the dataset that are relevant are processed, so in this case there is no flicker at all.

It's only when the user opts for a satellite's eye view that a problem emerges. I will live with it for now, but your suggestions are filed away and when I get time I will set about implementing them.

With many thanks once again,


Leave a Comment

Please sign in to add a comment. Not a member? Join today