在这个图像处理工具软件中,需要实现的工具栏比较多。我想让每个工具栏都在浮动的时候没有关闭按钮,同时在工具箱Toolbar中还可以设置工具栏显示的列数。根据类抽象的原则,我们给所有的工具栏建立一个基类CBaseToolBar,从CToolBar派生。CBaseToolBar需实现的主要功能有:浮动时去掉关闭按钮和设置工具栏的列数。
从Visual Studio.Net开始,包括Visual C++ 2005,去掉了Visual C++ 6.0中类向导功能。一些概念上也发生了变化。可以包含多个工程的Workspace被Solution替代,称为一个解决方案。
在Visual C++ 2005添加一个新的类,只需要在解决方案资源管理器中选择相应的工程,右键点击的弹出菜单中选择添加类,就会弹出添加类的向导对话框。如下图:
在出现的类向导对话框中,选择添加MFC类,然后点击添加按钮,最后选择CToolBar做为基类,派生类名输入CBaseToolBar。Visual C++ 2005中的向导功能比Visual C++ 6.0更完善,选择功能更丰富了。如果是想在6.0版本中添加CToolBar的派生类是无法直接选择CToolBar类的,一般采用的方法是先选择CToolBarCtrl,添加完成后再采用手动修改的方法改为CToolBar,而现在可以直接选择CToolBar,省去了很多麻烦。
建立好CToolBar的派生类,我们看看如何实现设置工具栏列数和去掉关闭按钮。设置列数时我们给类添加一个函数:void SetColumns(int nColumn);给某个特定的类添加函数需要先从解决方案资源管理器切换到类视图,这里会显示所有的类。在对应的类名上的右键弹出菜单中选择添加函数或者变量:如下图:
在随后出现添加函数对话框,提供了非常丰富的功能,直接鼠标点击就可以为函数加上virtual、static、inline等关键字。
设定好函数的返回类型和名称后,就添加参数。参数名框输入第一个参数的名称,然后点击添加按钮这个参数就被添加到右边的参数列表里。同时在下面的函数签名中可以预览函数的形式。是不是感觉功能比以前更丰富,使用更简单。添加完后在CPP文件中加入函数的实现代码:
void CBaseToolBar::SetColumns(int nColumns)
{
int nCount = GetToolBarCtrl().GetButtonCount();
for (int i = 0; i < nCount; i++)
{
UINT nStyle = GetButtonStyle(i);
BOOL bWrap = (((i + 1) % nColumns) == 0);
if (bWrap)
nStyle |= TBBS_WRAPPED; //或上TBBS_WRAPPED风格就是换行
else
nStyle &= ~TBBS_WRAPPED;
SetButtonStyle(i, nStyle);
}
Invalidate();
GetParentFrame()->RecalcLayout();
}
设置列数的功能完成,接着看如何去掉浮动关闭按钮。如果里曾经用向导建立过基于对话框的程序,那么你注意了在对话框的OnInitDialog函数里,有默认生成的将“关于...”菜单项添加到系统菜单中的代码。看出了点什么——其实标题栏上的右键和关闭按钮可以通过系统菜单进行控制。所以我们实现去掉浮点时的参数和关闭按钮也可以从这里开始。首先我们要判断工具栏时浮点还是停靠的,这个可以通过WM_WINDOWPOSCHANGED消息得到通知。
在Visual C++ 2005给某个类添加消息映射函数,同样在类视图里选择相应的类,然后在右边弹出属性设置界面,如果这个属性设置框没有出现,可以通过工具栏按钮打开界面:
在属性设置界面中,存在过滤的工具栏,选择第五个的消息事件按钮,下面就列出了此类所有可用的消息,选择对应的消息,在右边的下拉框你添加消息响应函数即可。选择消息的时候最下面还会有消息的一些说明帮助我们理解这个消息。
在WM_WINDOWPOSCHANGED消息函数里,我们先判断工具栏是否处于停靠状态,如果是浮动状态就去掉系统菜单。这里需要注意的时,虽然在界面上看工具栏时浮动非停靠的,实际上工具栏是停靠在一个CMiniFrameWnd框架里。我们这里所指的系统菜单就是这个CMiniFrameWnd的系统菜单。
void CBaseToolBar::OnWindowPosChanged(WINDOWPOS FAR* lpwndpos)
{
CToolBar::OnWindowPosChanged(lpwndpos);
if(IsFloating())
{
if(m_pDockBar) // m_pDockBar指向停靠的窗口对象
{
//如果停靠窗口是 CMiniFrameWnd就去掉系统菜单
//在IsFloating函数为FALSE的时候这个m_pDockBa的父窗口就是主框架
CWnd* pParent = m_pDockBar->GetParent();
if( pParent->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
pParent->ModifyStyle(WS_SYSMENU, 0, 0 );
}
}
}