窗口风格对窗口有很多影响,我先简单将一些使用常见窗口风格的结果,展现如下。我们知道
· WS_BORDER Creates a window that has a border.
· WS_DLGFRAME Creates a window with a double border but no title.
· WS_CAPTION Creates a window that has a title bar (implies the WS_BORDER style). Cannot be used with the WS_DLGFRAME style.
· WS_THICKFRAME Creates a window with a thick frame that can be used to size the window.
· WS_EX_WINDOWEDGE Specifies that a window has a border with a raised edge.
· WS_EX_CLIENTEDGE Specifies that a window has a 3D look — that is, a border with a sunken edge.
· WS_EX_STATICEDGE Creates a window with a three-dimensional border style intended to be used for items that do not accept user input.
这些风格都可以改变窗口的边界。
1.WS_BORDER
int nBorder = GetSystemMetrics(SM_CYBORDER); // nBorder为1
m_tWnd.Create(NULL, NULL, WS_VISIBLE|WS_BORDER, CRect(100,100,200,200), GetDesktopWindow(), 0);
CRect rcWnd;
CRect rcClient;
m_tWnd.GetWindowRect(rcWnd);
m_tWnd.GetClientRect(rcClient);
// 结果:rcWnd(top=100,left=100,right=300,bottom=300)
// rcClient(top=0,left=0,right=198,bottom=198)
这里很明显nBorder的值为1,实际上客户区就是排除了该Border的值来设定的。
2.WS_DLGFRAME
int nDlgFrame = GetSystemMetrics(SM_CYDLGFRAME); // nDlgFrame为3
m_tWnd.Create(NULL, NULL, WS_VISIBLE|WS_DLGFRAME, CRect(100,100,300,300), GetDesktopWindow(), 0);
CRect rcWnd;
CRect rcClient;
m_tWnd.GetWindowRect(rcWnd);
m_tWnd.GetClientRect(rcClient);
// 结果:rcWnd(top=100,left=100,right=300,bottom=300)
// rcClient(top=0,left=0,right=194,bottom=194)
这里窗口的非客户区的宽度四个方向均为3,可见就是GetSystemMetrics(SM_CYDLGFRAME)的值。
3.再看下WS_CAPTION(虽然MSDN说不要WS_CAPTION不能和WS_DLGFRAME一同使用,但我们知道WS_CAPTION是WS_BORDER和WS_DLGFRAME的集合)
int nCaption = GetSystemMetrics(SM_CYCAPTION); // nCaption为22
m_tWnd.Create(NULL, NULL, WS_VISIBLE|WS_CAPTION, CRect(100,100,300,300), GetDesktopWindow(), 0);
CRect rcWnd;
CRect rcClient;
m_tWnd.GetWindowRect(rcWnd);
m_tWnd.GetClientRect(rcClient);
// 结果:rcWnd(top=100,left=100,right=200,bottom=200)
// rcClient(top=0,left=0,right=194,bottom=172)
这里很明显了,窗口先切去FRAME这个框架的四个方向的宽度,为3。然后切去CAPTION占用的高度,为22。剩余的就是客户区的高度(即200 - 3 - 22)。
但是实际上我截取的窗口范围是210X210(本文开头的图片有表示)。窗口无缘无故的扩张了10X10的范围,但是客户区的范围是正确的。这是为什么呢?
为什么边界被扩张了呢?我发贴也没人解答,但是你们打开任务管理器(在WIN7下面)是不是看到了dwm.exe这个程序。这个程序叫Desktop Window Manager,查了一下有关这方面的资料。的确是这个程序捣鬼的。我在服务里面关闭了该程序,显示的实际窗口和程序获得的窗口就一致了。
下面的几个窗口风格,凡是被扩张了10X10的边界的,都是dwm.exe这个程序捣鬼的,这里我就不一一表述了。
但是我还想再追加几个问题,如果你想自绘标题栏,你该如何是好呢?
第一,你得自己设定哪里是客户区,哪里是非客户区。
使用WM_NCCALCSIZE该消息,把你认为是非客户区的部分截去。代码如下:
CDrawTitleBarDlg::CDrawTitleBarDlg(CWnd* pParent /*=NULL*/)
: CDialog(CDrawTitleBarDlg::IDD, pParent)
{
// ...
//Thickness of the sizing border around
m_nNcFrameThick = GetSystemMetrics(SM_CYFRAME);
//Height of a button in a window's caption or title bar, in pixels.
m_nCaptionThick = GetSystemMetrics(SM_CYCAPTION);
// ...
}
void CDrawTitleBarDlg::OnNcCalcSize(BOOL bCalcValidRects, NCCALCSIZE_PARAMS* lpncsp)
{
if (!bCalcValidRects) {
return;
}
// 自己计算客户区大小
lpncsp->rgrc[0].left += m_nNcFrameThick;
lpncsp->rgrc[0].top += m_nNcFrameThick + m_nCaptionThick;
lpncsp->rgrc[0].right -= m_nNcFrameThick;
lpncsp->rgrc[0].bottom -= m_nNcFrameThick;
}
这里是按照系统绘制具有WS_CAPTION来设定的,你也可以自己改变边框以及标题栏厚度。
重载WM_NCPAINT消息,自己绘制。
有关桌面窗口管理器的知识:
在vista系统中,应用程序的非客户区域(标题栏,图标,边框,标题栏按钮)的外观都是DWM控制的.使用DWM的API,你可以控制DWN渲染窗口的边框.
DWM AP的一个特性是允许扩展应用程序边框到客户端区域。这使你可以集成客户端的用户界面,比如工具栏,到外框中,使某些控件显示在系统界面的最突出的位置。比如,vista上的IE7就通过扩展上边框在外框集成了导航条
关闭桌面窗口管理器dwm.exe服务的办法:
>Start
>Control Panel
>Administrative Tools
>Services
>Look down the list for 'Desktop Window Manager Session Manager' and double click. Select startup type 'Disabled' and reboot the machine or just force the service to stop.