分享

CStatusBar和CStatusBarCtrl默认行为差异

 株野 2018-08-11

来源:https://blog.csdn.net/laohu6599/article/details/8481871

标签:CStatusBar  CStatusBarCtrl

时间:2001

因为今天在基于对话框的程序中,测试了CStatusBarCtrl和CStatusBar两种“状态栏”,发现默认的情况下,调用Create构造出来的状态栏的行为还是有不小的差异,所以在此总结出来。

首先强调,下文中,CStatusBar和CStatusBarCtrl会多次出现,请一定不要搞混淆了!!!

首先说明这个现象,然后我再来解释原因。
现象:
当运行程序,对话框显示出来,你先将对话框的大小随意改变(最好是变大,才好看效果),然后再尝试通过size-grip改变CStatusBarCtrl对象的大小。此时你会发现,神奇的事情发生了!!!!
和你想象的不一样,它竟然会自动移动到对话框的底部(因为你此处指定的是CCS_BOTTOM,如果指定的是CCS_TOP,那么它会自动跳到对话框顶部),而且,大小也还原为开始的值(后面你会知道, 这是系统预定义的默认值)。
而对于你构造的CStatusBar对象,你改变它的大小的时候,它确实按照你所想象的那样,仅仅改变了大小而已。

我百思不得其解,到底发生了什么事?为什么会这样呢?

我的源代码是这样的:
1、 首先在Dialog类里面添加两个成员变量
CStatusBar m_wndStatusBar;
CStatusBarCtrl m_statusBarCtrl;
2、分别调用其Create函数构造“两种”状态栏。
m_statusBarCtrl.Create(WS_VISIBLE | WS_CHILD | CCS_TOP | SBARS_SIZEGRIP,
CRect(0,0,0,0), this, IDC_STATUSBAR_CTRL);
m_wndStatusBar.Create(this,WS_VISIBLE | WS_CHILD | CBRS_BOTTOM | SBARS_SIZEGRIP);
注意,我这里都添加了SBARS_SIZEGRIP风格,使得在状态栏的右下角有一个size-grip可以改变其大小。
用途下面有说明。
3、最后一步,一定要记得,把对话框的属性Border改为Resizing。同样,用途下面有说明

好,接下来,看看MFC的源码,看看它对于CStausBar和CStatusBarCtrl的Create的不同实现。

一、对于CStatusBarCtrl的Create函数,MFC的实现如下:定义于WINCTRL2.CPP
BOOL CStatusBarCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd,
UINT nID)
{
// initialize common controls
VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));

CWnd* pWnd = this;
return pWnd->Create(STATUSCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID);
}

可见,MFC只是简单的注册一个预定义的common control类,并且调用虚函数CWnd::Create来创建一个窗口。很明了。

二、对于CStatusBar::Create,MFC的实现如下:定义于BARSTAT.CPP
BOOL CStatusBar::CreateEx(CWnd* pParentWnd, DWORD dwCtrlStyle, DWORD dwStyle, UINT nID)
{
ASSERT_VALID(pParentWnd); // must have a parent

// save the style (some of these style bits are MFC specific)
m_dwStyle = (dwStyle & CBRS_ALL);

// translate MFC style bits to windows style bits
dwStyle &= ~CBRS_ALL; //清空所有风格
dwStyle |= CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE;
//加上MFC预定义的四个风格
//关于CCS_XXXX等风格的详细解释可在MSDN中查找

// 如果父窗口有WS_THICKFRAME风格(a sizing border),则状态栏右下角会有一个size-grip
// 关于WS_THICKFRAME,详见MSDN中CreateWindow的关于nStyle参数的解释
if (pParentWnd->GetStyle() & WS_THICKFRAME)
dwStyle |= SBARS_SIZEGRIP;
dwStyle |= dwCtrlStyle; //加上第二个参数指定的风格

// initialize common controls
VERIFY(AfxDeferRegisterClass(AFX_WNDCOMMCTL_BAR_REG));

// create the HWND
CRect rect; rect.SetRectEmpty();
return CWnd::Create(STATUSCLASSNAME, NULL, dwStyle, rect, pParentWnd, nID);
}

对于CStatusBar::Create,将其与CStatusBarCtrl::Create对比,将发现有些不同,具体有几个地方想要说明:
1、解释文章最开始那个现象的原因:
首先,在CStatusBar::Create中有这么一行:

dwStyle |= CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE;

它将dwStyle(窗口风格)指定为了CCS_NOPARENTALIGN|CCS_NOMOVEY|CCS_NODIVIDER|CCS_NORESIZE。

这里重点说明一下CCS_NOPARENTALIGN和CCS_NORESIZE(因为是它们导致了上面的不同结果)
CCS_NOPARENTALIGN:防止控件自动移动到父窗口的顶部或者底部,当父窗口的尺寸发生变化时,该控件保持在原来的位置不变。如果,此时还指定了CCS_TOP或者CCS_BOTTOM,那么,高度将设为默认的值,但是位置和宽度都不会变。
CCS_NORESIZE:防止在初始化或者更新窗口尺寸的时候使用默认值,相反,控件会根据制定的高度和宽度的要求来响应初始化和尺寸的改变。

这时候,你便知道,就是因为此处设置了CCS_NOPARENTALIGN和CCS_NORESIZE,所以,当你尝试通过size-grip(就是状态栏右下角的那个可以改变其大小的东东)改变CStatusBar的大小时,他会按照你所想象的那样,是的,就仅仅是改变了大小。而CStatusBarCtrl却会自动置于对话框的顶(或者底)部。

2、CStatusBar的size-grip设置与否,和你一开始是否设置了SBARS_SIZEGRIP是没有什么关系的。CStatusBar是否具有SBARS_SIZEGRIP风格,只决定于父窗口是否具有WS_THICKFRAME风格(也就是,在资源属性中指定Border为Resizing,使窗口大小可改变时,创建出来的CStatusBar对象将会添加上SBARS_SIZEGRIP风格,在右下角添加一个size-grip用于调整CStatusBar的大小。)
所以,只要你在最开始设置对话框的时候设置了Resizing风格的border,那么,即使你在调用Create函数时没有指定SBARS_SIZEGRIP,MFC也会帮你加上去。所以,此时,你只需要这样调用:
m_wndStatusBar.Create(this); //因为第二个参数的默认值为WS_VISIBLE | WS_CHILD | CBRS_BOTTOM,
//就是前面去掉了SBARS_SIZEGRIP所剩下的风格就构造了一个带有size-grip的状态栏。
而,如果你没有设置对话框的resizing风格,那么,即使你在调用Create时指定了SBARS_SIZEGRIP,最终创建出来的CStatusBar还是不会有SBARS_SIZEGRIP的。(这就是我文章最开始为什么要设置对话框的resizing风格的原因)

其实,之前也有发现,CStatusBarCtrl和CStatusBar还是有一些不同的地方,在使用的时候需要留意。

转载自CSDN博客:http://blog.csdn.net/beckle_ye/archive/2010/07/09/5722209.aspx

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多