窗口风格的实际效果

时间:2022-05-04 00:16:54

窗口风格对窗口有很多影响,我先简单将一些使用常见窗口风格的结果,展现如下。



窗口风格的实际效果

我们知道

  • 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.