I am developing a form with custom painting and sizing of the non client area. I am handling all of the appropriate NC window messages and everything is working great except for a certain sequence of actions. If the form is maximized, minimized and then click the task bar to maximize again, I do not receive a WM_NCCALCSIZE message. I receive the message when the form is maximized and minimized but not when maximized from the taskbar. My problem is that I am calculating the title bar rectangle when receiving the WM_NCCALCSIZE message, so when I redraw after this sequence, my title bar rectangle is the size of the task bar window of the minimized form. There are several places I could put in a hack to recalculate the title bar rectangle when painting, etc, but I'd prefer to find the intended method for calculating the non client area in this situation. Anyone know how or when I am supposed to recalculate the non client area?
Related
Does someone know a message that gets send at the end of a resizing event (like double clicking app bar, maximize button click, drag to the top of the screen, ...), a good example is WM_EXITSIZEMOVE, but it's only at the end of the dragging of the window size bar.
So my question is, does it exist a message that gets called when any sizing event has occured, at the end of it (not like WM_SIZE)?
You'll get a WM_WINDOWPOSCHANGED message with the SWP_NOSIZE flag cleared at the end of any sizing event. There's no other message that indicates sizing has finished other than WM_EXITSIZEMOVE which indicates the end of a modal moving/sizing loop. If you get WM_WINDOWPOSCHANGED without previously getting WM_ENTERSIZEMOVE then you can assume you're not being resized modally.
I'm faced with a problem where I need to display some characters in a tree-view item (those belonging to the Symbol charset) using Symbol font while others in the default System font (Segoi UI on my Windows 7).
Custom draw allows us to draw different items using different fonts, but I would like to draw the same item string using different fonts as it applies to each character in the string as told above.
So, what I've done with not-so-pleasing results w.r.t. drawing performance upon a horizontal scroll when the number of items is more so far is this:
I disabled horizontal scrolling in my tree-view control using TVS_NOHSCROLL style (since I'm using my own scroll bar control inside the tree-view window to handle all horizontal scrolling)
I sub-classed the treeview control and in the sub-classed winproc, I handle the horizontal scroll notification and mouse notification (where I do my own hittesting and send message like TVM_EXPAND and TVM_SELECT as a result of mosue clicks/double-clicks). Also the scroll bar range is set based on how wide my custom drawn string is (the maximum length amongst all items).
I draw the string for each item upon receiving CDDS_ITEMPOSTPAINT using my own fonts for each character in the item.
The above approach (I left out some details for the sake of brevity) works BUT there are some problems which makes me post this question here and look for an alternare way:
Problems:
The horizontal scroll bar control I create is hosted "inside" the tree-view control at the bottom of the tree-view window. However, when the number of items goes beyond what the tree-view client area can accommodate vertically, the last visible tree-view item gets obscured by the scroll bar control. This can be solved by not making the scroll bar a child of the tree-view and hosting it outside the tree-view window just below it. But I don't want to do this since the scroll bar should typically be a child window of the tree-view.
This is the major one. Since I draw the items myself at each horizontal scroll, the drawing performance upon horizontal scrolling is very slow and also leads to flicker upon scrolling.
Any ideas will be much appreciated as I've been grappling with this for the last one week without success.
I can also post the relevant code here if you want to see the approach I took but I'm sure there shoould be a better approach to this and there must be some other people who would've faced this problem and solved it in the past.
Thanks in advance.
Custom-draw allows you to draw items however you want. You are not limited to a single font per item. When you receive the NM_CUSTOMDRAW notification, draw whatever you want on the provided HDC for the specified item. You can draw pieces of text in one font, pieces of text in a different font, etc. Be sure to return CDRF_SKIPDEFAULT so the TreeView itself will not try to draw anything on the item.
#Anurag S Sharma: I tried to edit this into Remy's answer. It's incomplete as is, but addresses your comment/concerns and answers this particularly vexing/useful question...
The problem is that ff I return CDRF_SKIPDEFAULT, Windows does not even draw the +/- buttons (expanding/collapsing) nor the indent lines in the control which I do want Windows to draw. – Anurag S Sharma
To retain the lines, buttons, and icons you can use ExcludeClipRect to mask only the text region and instead of returning CDRF_SKIPDEFAULT, return 0 as if you didn't draw anything. This itself would not be necessary if the text of the tree item was empty, except that the margins of the text will always be drawn by the default handler (note that Microsoft's controls do not always respect clipping shapes, but in this case they do.)
To replicate the classic TreeView label style in your custom draw procedure you need to do something like the following:
HTREEITEM item = (HTREEITEM)p->dwItemSpec;
TreeView_GetItemRect(p->hdr.hwndFrom,item,&p->rc,1);
RECT cr, rc = p->rc; GetClientRect(p->hdr.hwndFrom,&cr);
DrawTextW(p->hdc,text,-1,&rc,DT_CALCRECT|DT_NOPREFIX|DT_NOCLIP);
rc.right+=4; rc.bottom+=2; IntersectRect(&rc,&cr,&rc);
ExtTextOutW(p->hdc,rc.left+2,rc.top+1,ETO_CLIPPED|ETO_OPAQUE,&rc,text,wcslen(text),0);
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,
In almost any Windows application, I notice that holding the mouse button down in a non-client area causes the painting to stop. Why is this required?
For example, I have a Managed Direct 3D application which displays a spinning cube. If I place the pointer over the title bar and hold the mouse button down, the cube ceases to spin even though I have not coded any such condition into my loop.
Why is painting halted? What are the benefits? Most importantly, how can I work around this?
When you click on the title bar, there's a brief pause while the window manager tries to determine whether or not you're clicking or beginning a drag (moving the window). If you're still holding down the button, then it's a drag: the window manager sets up its own message loop and pumps messages until you release the mouse. Your window should still be able to process messages, because they'll still be dispatched, but if your animation depends on a custom message loop then you'll be stuck 'till the modal drag loop ends.
Work around it by triggering your animation in response to messages: a timer seems like a good choice to me.