每次研究一点东西,都没有记录,下次需要的时候又浪费时间重新去研究。本人就是个没有总结习惯的人,这样等于没用积累,实在不行。
这2天研究了一下WS_BORDER和WX_EX_CLIENTEDGE的不同,以及在动态创建,和窗口绑定时候效果的不同。
下面开始:
1.先看MSDN有关WS_BORDER窗口风格,和WS_EX_CLIENTDEGE扩展窗口风格的定义。
WS_BORDER Creates a window that has a border.创建一个有边界的窗口。
WS_EX_CLIENTEDGE Specifies that a window has a 3D look — that is, a border with a sunken edge.指定窗口具有3D外观,也即是一个下沉的边缘。
2.在此之前先简单说下GetWindowRect和GetClientRect的区别
GetWindowRect获取窗口的整个区域,包括菜单,标题栏,边界。很明显加了WS_BORDER与WS_EX_CLIENTEDGE画出的边界不属于客户区。
GetClientRect获取的窗口的客户区,这里是在用于给用户作图用的。
3.总结的现象
http://
以上是创建CWnd时的统计的结果。很多时候我们需要通过ModifyStyleEx修改窗口风格,然后需要使用SetWindowPos来改变窗口风格。
4.以自绘CListBox来举例使用
直接附上我创建带有WS_BORDER和WS_EX_CLIENTEDGE风格CTListBox的例子
DWORD dwStyle = WS_CHILD|WS_VISIBLE|WS_BORDER|WS_TABSTOP|WS_VSCROLL|LBS_NOTIFY|LBS_OWNERDRAWFIXED|LBS_HASSTRINGS|LBS_NOINTEGRALHEIGHT|LBS_EXTENDEDSEL;m_tlstbox.Create(dwStyle, CRect(10,10,110,110), this, ID_XLISTBOX);DWORD dwExStyle = WS_EX_LEFT|WS_EX_LTRREADING|WS_EX_RIGHTSCROLLBAR|WS_EX_NOPARENTNOTIFY|WS_EX_CLIENTEDGE;m_tlstbox.ModifyStyleEx(0, dwExStyle);
CRect rcWnd;m_tlstbox.GetWindowRect(rcWnd);CRect rc;m_tlstbox.GetClientRect(rc);
我是应用ModifyStyleEx来给CTListBox增加扩展风格的。下面列出应用WS_BORDER和WS_EX_CLIENTEDGE的四种情况。
细心的朋友会发现,在此图第三个和第四个窗口的客户区和之前CWnd的窗口区域不一样。共通点,都是WS_EX_CLIENTEDGE没用。
我在
void CTListBox::DrawItem(LPDRAWITEMSTRUCT lpDIS)
{CRect rcWnd;GetWindowRect(rcWnd);CRect rcClient;GetClientRect(rcClient);
}
里面测试的结果也是如此。
原来我们通过ModifyStyleEx改变窗口扩展风格后,需要使用
m_tlstbox.SetWindowPos(&wndTop, 10,10,0,0, SWP_DRAWFRAME | SWP_NOSIZE);
来确保刚才添加的扩展风格被应用了。
虽然MSDN说ModifyStyleEx会调用SetWindowPos这个API来设定窗口位置,但是没用。
我们必须用如上的语句手动设置。
5.至于为什么不能使用ModifyStyle或者ModifyStyleEx正确的修改窗口风格?
MSDN的描述如下:
Certain window data is cached, so changes you make using SetWindowLong will not take effect until you call the SetWindowPos function. Specifically, if you change any of the frame styles, you must call SetWindowPos with the SWP_FRAMECHANGED flag for the cache to be updated properly.
6.但是经过研究发现使用ModifyStyleEx并带上SWP_FRAMECHANGED也能改变Frame Style,为什么呢?
m_xlstbox.ModifyStyleEx(0, dwExStyle, SWP_NOSIZE|SWP_NOMOVE|SWP_FRAMECHANGED);
也可以正确的改变窗口的frame style,为什么呢?因为ModifyStyleEx和SetWindowPos都是调用::SetWindowPos这个API。虽然是MSND没有为ModifyStyleEx指定了该风格,但是SetWindowPos具有的nFlags我们都可以使用。
7.继续深究,为什么带有SWP_FRAMECHANGED能改变窗口的Frame Style呢?我找到原因了。
因为带有SWP_FRAMECHANGED标识,会向该窗口发送WM_NCCALCSIZE消息,我们可以手动拦截该消息,使WS_EX_CLIENTEDGE永远不被调用,但是最好不要这样。
至于WM_NCCALCSIZE如何实现的,那可是微软的秘密了。虽然不能看到他们的代码,但是我猜也是在这个消息的处理函数根据窗口的风格(例如,标题,菜单,滚动条,状态栏等等)来划分客户区的吧。
有关窗口的其他框架风格如WS_THICKFRAME, WS_SIZEBOX。下次再总结。。吃饭去了。。。。