I want to custom draw the ComboBoxEx control, but it seems WM_PAINT is never called. Is there some trick there? Also, how can I override the size of the control, it's calculated depending on font, but I need to fix it.
Combo Boxes use the older WM_DRAWITEM messages (sent to the box's parent) rather than the WM_NOTIFY with NM_CUSTOMDRAW codes. I'm not sure why you think you'd see the WM_PAINT for the combobox, unless you've subclassed it.
Related
I have created my own custom drawn list with checkboxesin WTL, I want to make it scrollable now, the thing is that I am subclassing a Static Text control over which I draw.. And I don't know if static controls support scrolling in any way..
Anyway my question is how do I make my custom made controll scrollable, do I have to impement the mechanism myself?
Yes, you'll have to implement it entirely by hand. That's the drawback of not using a built-in control. It probably would have been a better idea to start off with a ListBox and then customize that to your desire. That way, you would get all of the scrolling, selection, and other logic for free.
The steps are roughly as follows (there are probably ATL/WTL idioms for some or all of these, but any ATL/WTL programmer can convert back and forth from raw Win32):
Add the WS_HSCROLL and/or WS_VSCROLL window styles to your custom static control, depending on if you want a horizontal, vertical, or both scroll bars. You would add these to list of window styles passed in to the CreateWindow/CreateWindowEx function.
By default, those scroll bars won't do anything at all. You need to tell them what to do using the SetScrollInfo function. In your case:
The first parameter (hwnd) would be the handle to your control window.
The second parameter (fnBar) should be either SB_HORZ to adjust the horizontal scroll bar, or SB_VERT to adjust the vertical scroll bar.
The third parameter (lpsi) is a pointer to a SCROLLINFO structure, filled in with the desired scrolling parameters, including the current position of the thumb, the minimum and maximum values, and the "page" size used to set up the proportional scroll bar.
The fourth parameter (fRedraw) should probably be set to TRUE.
You will also need the EnableScrollBar function to enable/disable the scroll bar as appropriate. Like the previous function,
hwnd is a handle to your control window
wSBflags is either SB_HORZ, SB_VERT, or SB_BOTH
wArrows is one of the ESB_* values, depending on what you want
Finally, you will want to write code in your custom control's window procedure to handle the WM_HSCROLL and/or WM_VSCROLL messages. These are sent to the window whenever the scroll bar is moved. Inside of the handler for these messages, you will want to do the following things to update the control's state:
Call the SetScrollInfo function to update the thumb to its new position
Redraw the contents of your control in accordance with the scrolled distance. There are multiple ways of doing this, but I'd probably use the ScrollWindowEx function.
The custom control's window procedure will also need to handle the WM_SIZE message to update the scroll bar state (by calling SetScrollInfo and/or EnableScrollBar) in response to changes in the window's size.
Cody Gray provided excellent introduction into adding support for scrolling, however what you also have is the help from the WTL itself.
WTL's atlscrl.h offers you classes to inherit from and implement a custom window/control with scrolling.
// Classes in this file:
//
// CScrollImpl<T>
// CScrollWindowImpl<T, TBase, TWinTraits>
// CMapScrollImpl<T>
// CMapScrollWindowImpl<T, TBase, TWinTraits>
// CFSBWindowT<TBase>
// CZoomScrollImpl<T>
// CZoomScrollWindowImpl<T, TBase, TWinTraits>
// CScrollContainerImpl<T, TBase, TWinTraits>
// CScrollContainer
Not so much code/snippets around to demo the use, but there is still one WTL sample that covers the basics and it should be a good starting point for you as well. \Samples\BmpView has a class for scrollable bitmap:
class CBitmapView :
public CScrollWindowImpl<CBitmapView>
{
public:
You will see it's really small and it covers most of the complexity.
I used UpdateLayeredWindow to draw a window which use png as background. But this window contain some self-draw buttons which would change when user hover/click these buttons and then the window should change.
Now the problem is when should I call UpdateLayeredWindow. Shoud I call UpdateLayeredWindow after the user changed the button apperance, that is when user hover the mouse above the buttons or clicked the buttons?
When need to update the layeredwindow, call UpdateLayeredWindow, but be really careful with this.
Call it too frequently do cause performance problem, its not WM_PAINT which could combine to one if there is too much in the message queue. UpdateLayeredWindow do not...
Windows sends several messages when a window is resized:
WM_GETMINMAXINFO
WM_ENTERSIZEMOVE
WM_EXITSIZEMOVE
WM_NCCALCSIZE
WM_SIZING
WM_SIZE
WM_WINDOWPOSCHANGING
WM_WINDOWPOSCHANGED
and possibly more.
If I would like to re-position the children when my window is resized, where and how should I do so?
I'm looking for the "best" method -- i.e. the method with the fewest gotcha's and the least flicker.
My current method is to perform all the repositioning inside WM_NCCALCSIZE, using DeferWindowPos.
However, I've also tried handling it inside WM_WINDOWPOSCHANGED... but no matter where I handle it, it seems like there is always at least one "moment" when the window is painted in an in-between state, where the window's size has changed, but its contents have yet to be resized.
Another effect I would also like to avoid: moving a child after it has already moved. I don't want the user to see a control sliding down and then back up because of my change -- it should have as few transient effects as possible.
Am I doing this correctly? Is there a better place I can lay out the window's children?
You should re-position the window in the WM_SIZE message, because that is the last one that the window recieves before complete it's task...To re-position the window you can use MoveWindow
I've created a window with a custom chrome by:
Handling WM_NCHITTEST and returning the appropriate values for the window caption and borders,
Swallowing WM_NCPAINT (and WM_NCUAHDRAWCAPTION, WM_NCUAHDRAWFRAME),
Handling WM_SETTEXT, WM_SETICON and WM_NCACTIVATE with DefWindowProc by temporarily removing WM_VISIBLE,
Handling WM_WINDOWPOSCHANGED to apply a window region for rounded corners.
Moving/Resizing is handled fine by Windows. I added WS_THICKFRAME to the window styles to enable Aero Snap functionality. But now when the window is maximized it is positioned at (-5,-5) and my custom titlebar is cut off (this doesn't happen without WS_THICKFRAME).
What is the proper way to fix that? What influences that position? It seems to be unrelated to values returned for WM_NCHITTEST.
Late answer, but it seems like noone else has answered.
You can check when the window is maximized and account for the margin when the window is maximized. You may want to handle WM_NCCALCSIZE rather than WM_NCPAINT to make the entire window appear as client area, rather than painting the non-client area.
This describes one approach to implementing custom chrome (I was the author):
http://blogs.msdn.com/b/wpfsdk/archive/2008/09/08/custom-window-chrome-in-wpf.aspx
Hope that helps,
While resizing win32 window, with OpenGL context, it just shows black on the newly exposed area.
I do get WM_PAINT message while resizing, and I do try to render new content, but it seems as if SwapBuffers does nothing, while resizing.
How should window resizes be handled correctly, so that there is no "broken" content while resizing?
This usually happens if you have a background brush configured for your window's class (see the WNDCLASS or WNDCLASSEX structure). If there's a brush, the system will clear the window right after each redraw step, then send the WM_PAINT. In case of V-Synced SwapBuffers your picture may have been overdrawn by the next resizing step before the buffer swap happened, or just right after it, but before that part of the screen was sent to the display device.
Either way, the solution is to set the background brush of the window to NULL. Also tinkering with the WM_ERASEBKGND message handling may give results.
EDIT due to comment
If the content of the last frame stays visible, you probably just don't react to resizing with a redraw. The easiest solution to this is calling the drawing function from the WM_SIZING (or the WM_SIZE, just try both) message handler.