What are the differences between RedrawWindow and UpdateWindow in Win32?
Since they seem to have the same purpose to refresh a window, what are the differences?
RedrawWindow is typically used to force a redraw of the entire window (or some specified region within) right now.
UpdateWindow will force a redraw of only the update region of the window, i.e. that part of the window that has been invalidated (e.g. by calling InvalidateRect) since the last paint cycle.
Related
I have a window which is set to AlwaysOnTop using the WS_EX_TOPMOST flag. Now, it is possible that some other application might also have a window which has WS_EX_TOPMOST set and override the topmost flag for my window.
How should I check if my window is indeed the window that is the top most window and nothing is being painted over it (the nothing is being painted over my window is the important part). If something is painting over my window, I want to hide my window and show it again when I can make it the top most window (but that's probably the second step)
Call GetWindow passing your topmost window's handle and the GW_HWNDFIRST flag. The window returned will be the topmost window that is highest in the Z-order. You can then use the GW_HWNDNEXT flag to walk through the topmost windows in order of decreasing Z-order until you find yours. If any of the windows overlap your window, then your window is underneath.
The old standard way was to call WindowFromPoint for a point on your supposedly visible window and compare the returned handle against your own window handle. There is a better way using the clipping system. I discuss this here.
I'm working on a program that requires WM_ERASEBKGND to be disabled (to avoid flickering).
The problem comes in when my main window loses focus, and another window (another program) gains the focus.
The window that has the focus (not my program) invalidates MY program's window every time it passes over it! The result is, my window's screen turns white everywhere that another window has passed by it, leaving it almost totally blank afterward. Obviously, I cannot have a program where the screen turns white every time it loses focus.
Is there any way to continue my window's drawing operations, (continue calling wm_paint, for example) even after my window has lost focus (WM_KILLFOCUS)?
First of all, from the comments above, never send the WM_PAINT manually with SendMessage or PostMessage. Use InvalidateRect to instruct the window to be repainted.
About the WM_ERASEBKGND, the return value is used to indicate the WM_PAINT handler that the background has been erased, in case the paint procedure can be optimized. To actually prevent the background from being erased, simply do not call DefWndProc() for that message. Or even easier, set the hbrBackground to NULL in the window class.
As others mentioned the focus has nothing to do with repainting, and your window should paint normally even while in the background.
I have a main window with 3 child: hwndTocBox (left panel), hwndSplitter and hwndCanvas (right panel).
hwndTocBox has a child hwndTreeView, which is a TreeView control. When I drag hwndSplitter to the right (i.e want to make hwndTocBox and hence hwndTreeView bigger), the content (and background?) of hwndCanvas and hwndSplitter will remain for a while. (When I drag the splitter to the left, there is no problem at all.)
When hwndSplitter is draged, it uses DeferWindowPos() to resize and move hwndTocBox, hwndSplitter and hwndCanvas. When hwndTocBox is resized, in WM_SIZE case of its windows procedure, it resizes hwndTreeView (still using DeferWindowPos(), since it resizes not only hwndTreeView but also others).
I have tried to use CLIPCHILDREN and WS_CLIPSIBLINGS in several places, but it doesn't solve the problem.
Why the contents remain there for a while and erased later?
Could you indicate me how to solve this issue, please.
You'll need to repaint the portions of the window that you've resized, otherwise you'll get these strange artifacts. There's a reason they look like smears, because that's almost exactly what they are. A certain portion of the content was painted and appeared on screen normally. Then you resized the window. The portion that had already been painted was not repainted because you didn't invalidate it, but the newly-exposed portion had to be repainted because there was nothing there before.
The fix is simple: add a call to the InvalidateRect() function at the bottom of your resizing code to ensure that the portion of the window you're resizing gets redrawn the next time that the window processes a WM_PAINT message.
If you want to make sure that a WM_PAINT message gets processed immediately (resulting in the immediate redrawing of your window's affected regions), follow up with a call to the UpdateWindow() function. But this really shouldn't be necessary. It's much more efficient to postpone all of the redrawing to later when everything is finalized, rather than doing it incrementally. Relatively speaking, repainting a window is an expensive operation.
I want to allow a user to drag my Win32 window around only inside the working area of the desktop. In other words, they shouldn't be able to have any part of the window extend outside the monitor(s) nor should the window overlap the taskbar.
I'd like to do it in a way that does cause any stuttering. Handling WM_MOVE messages and calling MoveWindow() to reposition the window if it goes off works, but I don't like the flickering effect that's caused by MoveWindow().
I also tried handling WM_MOVING which prevents the need to call MoveWindow() by altering the destination rectangle before the move actually happens. This resolves the flickering problem, but another issue I run into is that the cursor some times gets aways from the window when a drag occurs allowing the user to drag the window around while the cursor is not even inside the window.
How do I constrain my window without running into these issues?
Windows are, ultimately, positioned via the SetWindowPos API.
SetWindowPos starts by validating its parameters by sending the window being sized or moved a WM_WINDOWPOSCHANGING message, and then a WM_WINDOWPOSCHANGED message notifying the window proc of the changed size and/or position.
DefWindowProc handling of these messages is to, in turn, send WM_GETMINMAXINFO and then WM_SIZE or WM_MOVE messages.
Anyway, handle WM_WINDOWPOSCHANGING to filter both user, and code, based attempts to position a window out of bounds.
Keep in mind that users with multi-monitor setups may have a desktop that extends into negative x- and y-coordinates, or that is not rectangular. Also, some users use alternative window managers such as LiteStep, which implement virtual desktops by moving them off-screen; if you try to fight this, your application will break for these users.
You can do this by handling the WM_MOVING message and changing the RECT pointed to by the lParam.
lParam: Pointer to a RECT structure with the current position of the window, in screen coordinates. To change the position of the drag rectangle, an application must change the members of this structure.
you may also want to handle WM_ENTERSIZEMOVE to know when the window is beginning to move, and WM_EXITSIZEMOVE
WM_GETMINMAXINFO is what you seem to be looking for.
When I want to redraw a window, is there any preferred function to call between InvalidateRect and RedrawWindow?
For instance, are these two calls equal: (win would be a HWND)
RedrawWindow(win, NULL, NULL, RDW_INVALIDATE);
InvalidateRect(win, NULL, NULL);
The main question(s): When should I use one or the other? Are there any differences that happen in the background? (different WM_messages / focus / order / priorities..)
The reason that I want to redraw the window is because I send a new image to it that I want it to display, meaning the content of the window is no longer valid.
InvalidateRect does not immediately redraw the window. It simply "schedules" a future redraw for a specific rectangular area of the window. Using InvalidateRect you may schedule as many areas as you want, making them accumulate in some internal buffer. The actual redrawing for all accumulated scheduled areas will take place later, when the window has nothing else to do. (Of course, if the window is idle at the moment when you issue the InvalidateRect call, the redrawing will take place immediately).
You can also force an immediate redraw for all currently accumulated invalidated areas by calling UpdateWindow. But, again, if you are not in a hurry, explicitly calling UpdateWindow is not necessary, since once the window is idle it will perform a redraw for all currently invalidated areas automatically.
RedrawWindow, on the other hand, is a function with a much wider and flexible set of capabilities. It can be used to perform invalidation scheduling (i.e. the same thing InvalidateRect does) or it can be used to forcefully perform immediate redrawing of the specified area, without doing any "scheduling". In the latter case calling RedrawWindow is virtually equivalent to calling InvalidateRect and then immediately calling UpdateWindow.
RedrawWindow(win, NULL, NULL, RDW_INVALIDATE); and InvalidateRect(win, NULL, NULL); are equivalent. Both functions invalidate the window. The WM_PAINT occurs at the normal time (no other messages in the application queue) in both cases.
If you want the paint to be done immediately then calling either RedrawWindow(win, NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW) or InvalidateRect followed by an UpdateWindow will do that.
RedrawWindow simply gives more options with the RDW_* bits. If all you want is to invalidate the window without the immediate paint then calling InvalidateRect seems cleaner.
I don't like just giving links, but the MSDN gives you all the information you need and it would be a waste of time to re-type it all here.
RedrawWindow
InvalidateRect
In short, yes there are differences. The question is, why do you want to redraw the window? Is it because the contents are no longer valid? If so, use InvalidateRect, otherwise use RedrawWindow.
RedrawWindow repaints the window immediately. InvalidateRect only marks the window to be repainted on the next WM_PAINT message. But WM_PAINT messages have lower priority than other messages, so the repainting won't be immediately if your app is busy handling other messages.