现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

窗口风格的实际效果

2012-08-16 09:49 工业·编程 ⁄ 共 3387字 ⁄ 字号 暂无评论

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

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

这些风格都可以改变窗口的边界。

clip_image001

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.

给我留言

留言无头像?