MFC工具条与状态条设计

工具条/栏(tool bar)和状态条/栏(status bar)是构建友好GUI程序的通用标准,但它们并不是Windows API的标准部件,而是由应用程序框架(MFC)增加的一类控件。

工具条是CToolBar类的对象,状态条是CStatusBar类的对象,这两个类都是控制条(栏)CControlBar的派生类,而CControlBar类又是从CWnd类派生的:

CObject → CCmdTarget → CWnd → CControlBar → CToolBar / CStatusBar

<!--[if !vml]--><!--[endif]-->

 
工具条和状态条都是放置在框架窗口内部的特殊控制栏窗口,前者一般位于框架窗口顶部的菜单条之下,后者一般位于框架窗口的底部,它们随其父框架窗口的移动和大小改变而调整自己的长短与位置。
在MFC应用程序中,可以通过其“视图”菜单中的对应菜单项来启用(显示)/ 禁止(隐藏)工具条和状态条。而且从MFC 4.0 开始,工具条由Windows提供的工具栏通用控件来建立,是完全可停靠的(所以工具条应该改称为工具栏)。
由应用程序框架负责管理控制栏对象的构造、析构、及其窗口的创建与显示。MFC应用程序向导为框架窗口类产生的控制栏代码位于MainFrm.h / MainFrm.cpp中。
1.工具条
工具条由若干可分组的图形按钮组成,这些按钮的图像属于同一个横条状位图,存储在一个位图资源文件(*.bmp)中。其中,按钮的分组,完全由编程接口(源程序)决定,而与该位图无关。在应用程序中单击一个按钮后,会像菜单项和快捷键一样发送一个命令消息(一般对应于一个菜单项消息)。可以响应UI消息来改变按钮状态和图形。
1) 缺省工具条
缺省工具条包含“新建”、“打开”、“保存”,“剪切”、“复制”、“粘贴”,“打印”,“关于”等3组8个图形按钮,它们在同一个位图文件(res/Toolbar.bmp)中,每一个按钮按顺序对应于位图中一个16*15(即16像素宽*15像素高)位图片断。应用程序框架为每个按钮提供一个边框,并通过改变其边框和按钮图片的颜色来表示按钮的状态。

<!--[if !vml]--><!--[endif]-->

<!--[if !vml]--><!--[endif]-->

缺省工具条及其位图
可用VS的工具栏编辑器窗口和对应的属性窗口等,来修改缺省的工具条(资源标识为IDR_MAINFRAME)。MFC应用程序向导生成的缺省工具条资源文本为:(位于资源文件Student.rc中)
IDR_MAINFRAME TOOLBAR    16, 15
BEGIN

    BUTTON      ID_FILE_NEW

    BUTTON      ID_FILE_OPEN

    BUTTON      ID_FILE_SAVE

       SEPARATOR

    BUTTON      ID_EDIT_CUT

    BUTTON      ID_EDIT_COPY

    BUTTON      ID_EDIT_PASTE

       SEPARATOR

    BUTTON      ID_FILE_PRINT

    BUTTON      ID_APP_ABOUT

END
2) 编辑工具条
下面仍以Student程序为例,说明如何向工具条中添加按钮、设置响应、及添加新的工具条。下面是编辑工具条的若干操作于步骤:

<!--[if !supportLists]-->l         <!--[endif]-->在VC项目工作区的资源视图页中展开“Student/Student.rc”中的“Toolbar”资源列表,双击IDR_MAINFRAME打开工具栏编辑器(见下图)

<!--[if !vml]--><!--[endif]-->

工具条编辑器
 

<!--[if !supportLists]-->l         <!--[endif]-->选择当前按钮:单击位于VS窗口中部的工具条编辑窗口上部工具条栏中的所需按钮;

<!--[if !supportLists]-->l         <!--[endif]-->修改位图:对当前按钮,可以利用“图像”菜单、图像编辑器工具条和(位于属性窗口上部的)颜色窗口,在中部的图像编辑器窗口中绘制和修改当前按钮的位图;

<!--[if !supportLists]-->l         <!--[endif]-->修改属性:在属性窗口中可以

<!--[if !supportLists]-->n         <!--[endif]-->选择该按钮所对应的(菜单项)ID

<!--[if !supportLists]-->n         <!--[endif]-->修改该按钮位图的宽和高

<!--[if !supportLists]-->n         <!--[endif]-->键入/修改该按钮所对应的提示文本(/n后的为按钮的浮动提示文本)

<!--[if !supportLists]-->l         <!--[endif]-->删除按钮:将按钮拖离工具条即可

<!--[if !supportLists]-->l         <!--[endif]-->添加按钮:

<!--[if !supportLists]-->n         <!--[endif]-->将工具条最右边的空白按钮拖到你想加入按钮的位置

<!--[if !supportLists]-->n         <!--[endif]-->用“图像”菜单、图像编辑器工具条和颜色窗口来绘制按钮的位图(在空白按钮上绘图后,VS会自动在其右边添加一个新的空白按钮)

<!--[if !supportLists]-->n         <!--[endif]-->在属性窗口中选择该按钮所对应的(菜单项)ID

<!--[if !supportLists]-->n         <!--[endif]-->还可以修改该按钮位图的宽和高、键入/修改该按钮所对应的提示文本

<!--[if !supportLists]-->l         <!--[endif]-->分组:左/右拖动按钮半个按钮宽度,可将其

<!--[if !supportLists]-->n         <!--[endif]-->与右边/左边的按钮分开成不同的组

<!--[if !supportLists]-->n         <!--[endif]-->与左边/右边的按钮合并成同一个组

 
例如,在Student程序的工具条中,在问号按钮前加入分别用“+”与“-”号图形表示的添加菜单项(ID_ADD)与删除菜单项(ID_DEL)按钮。

<!--[if !vml]--><!--[endif]-->

<!--[if !vml]--><!--[endif]-->

3)添加新工具条
如果:

<!--[if !supportLists]-->①     <!--[endif]-->在使用应用程序向导创建程序时,在“MFC 应用程序向导”对话框的“用户界面功能”页的“工具栏”选项中,没有选“标准停靠”单选钮,则需要自己加入工具条;

<!--[if !supportLists]-->②     <!--[endif]-->或者原有的工具条不够用,需要加入第2个工具条;

<!--[if !supportLists]-->③     <!--[endif]-->或者在程序运行当中需要在多个工具条中切换;

对这些情况都需要自己创建新的工具条,并且自己写代码将它装入框架窗口。
(1) 创建工具条资源

<!--[if !supportLists]-->l         <!--[endif]-->在项目工作区的“资源视图”页中的Toolbar资源表项上单击鼠标右键,在弹出的浮动菜单中选“插入Toolbar”菜单项,VS会自动创建一个ID为IDR_TOOLBAR1的空工具条

<!--[if !supportLists]-->l         <!--[endif]-->可在该工具条中加入若干图形按钮(如Z、L、W)

<!--[if !supportLists]-->l         <!--[endif]-->在属性窗口中修改工具条的ID(如IDR_MYTB),选择按钮对应的ID(如ID_NAME_ZS、ID_NAME_LS、ID_NAME_WW)

(2) 创建、装入、显示工具条
针对前面所讲的3种情况,分别采用下列不同的方法来装入工具条:
<!--[if !supportLists]--> ①     <!--[endif]-->在没有工具条的框架窗口中加入工具条:

<!--[if !supportLists]-->l         <!--[endif]-->创建新工具条资源

<!--[if !supportLists]-->l         <!--[endif]-->打开头文件MainFrm.h,在CMainFrame类中加入工具条类CToolBar的对象m_ToolBar作为公共数据成员:(缺省的工具条对象为CToolBar m_wndToolBar;)

CToolBar m_ToolBar;

<!--[if !supportLists]-->l         <!--[endif]-->在CMainFrame类中WM_CREATE消息响应函数OnCreate(若无该函数则创建它)中的return 0;语句之前加入下列代码:

if (!m_ToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE |

CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |

CBRS_SIZE_DYNAMIC) || !m_ToolBar.LoadToolBar(IDR_MYTB))
       {
              TRACE0("未能创建工具栏/n");
              return -1;      // 未能创建
       }
       m_ToolBar.EnableDocking(CBRS_ALIGN_ANY);
       EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_ToolBar);
 
其中的CreateEx函数代替了下列三个函数的功能:

if (!m_ToolBar.Create(this)) {// 创建工具条

              TRACE0("未能创建工具栏/n");

              return -1;      // 创建失败

       }

       if (!m_ToolBar.LoadToolBar(IDR_MYTB)) { // 装入工具条

              TRACE0("未能创建工具栏/n");

              return -1;      // 装入失败

       }

       m_ToolBar.SetBarStyle(m_ToolBar.GetBarStyle() | CBRS_GRIPPER | CBRS_TOOLTIPS |

CBRS_FLYBY);
       // CBRS_GRIPPER :在工具条的左边加一个夹条
// CBRS_TOOLTIPS :激活工具条提示;
// CBRS_FLYBY :允许在鼠标滑过图形按钮时在显示提示(缺省只有在按下按钮时才提         示,且无浮动式提示)
 

<!--[if !supportLists]-->②     <!--[endif]-->在框架窗口中加入多个工具条:

<!--[if !supportLists]-->l         <!--[endif]-->创建新工具条资源

<!--[if !supportLists]-->l         <!--[endif]-->打开头文件MainFrm.h,在CMainFrame类中加入工具条类CToolBar的对象m_ToolBar作为公共数据成员:

CToolBar m_ToolBar;

<!--[if !supportLists]-->l         <!--[endif]-->在原有的OnCreate函数内加入似①的创建与装入工具条的代码,但要注意代码的顺序,且不需重复语句EnableDocking(CBRS_ALIGN_ANY); 参见下面代码的红色部分(其余部分为自动生成的缺省代码):

 

int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

       if (CFrameWnd::OnCreate(lpCreateStruct) == -1)

              return -1;

      

       if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP

              | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||

              !m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
       {
              TRACE0("未能创建工具栏/n");

              return -1;      // 未能创建

       }
 

       if (!m_ToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE |

              CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY |
              CBRS_SIZE_DYNAMIC) || !m_ToolBar.LoadToolBar(IDR_MYTB))
       {
              TRACE0(" 未能创建工具栏 /n");

              return -1;      // 未能创建

       }
 

       if (!m_wndStatusBar.Create(this) ||

              !m_wndStatusBar.SetIndicators(indicators,
               sizeof(indicators)/sizeof(UINT)))
       {
              TRACE0("未能创建状态栏/n");

              return -1;      // 未能创建

       }
 

       // TODO: 如果不需要工具栏可停靠,则删除这三行

       m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
       EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_wndToolBar);
 
       m_ToolBar.EnableDocking(CBRS_ALIGN_ANY);
       DockControlBar(&m_ToolBar);
 

       return 0;

}
 

<!--[if !supportLists]-->③     <!--[endif]-->显示/隐藏/切换工具条:

<!--[if !supportLists]-->l         <!--[endif]-->似②创建若干工具条资源

<!--[if !supportLists]-->l         <!--[endif]-->在OnCreate函数内加入相应代码,来创建与装入工具条

<!--[if !supportLists]-->l         <!--[endif]-->在这些代码后面,加上隐藏暂不显示的工具条的代码,如

ShowControlBar(&m_ToolBar, FALSE, FALSE);

这里用了框架窗口类的ShowControlBar成员函数,其原型为:

void ShowControlBar( CControlBar* pBar, BOOL bShow, BOOL bDelay );

<!--[if !supportLists]-->l         <!--[endif]-->在菜单资源中添加显示/隐藏/切换工具条的菜单项(如“视图/切换工具栏”ID_CHANGE_TOOL_BAR),在某一窗口派生类(如视图类CStudentView)中创建该菜单项的消息响应函数(如OnChangeToolBar),在该函数中隐藏/显示/切换工具条,例如:

void CStudentView::OnChangeToolBar()
{

       CMainFrame *pFrmWnd = (CMainFrame*)GetTopLevelFrame();

       if(m_bTBar) {

              pFrmWnd->ShowControlBar(&pFrmWnd->m_wndToolBar, FALSE, FALSE);

              pFrmWnd->ShowControlBar(&pFrmWnd->m_ToolBar, TRUE, FALSE);

              m_bTBar = false;
       }
       else {

              pFrmWnd->ShowControlBar(&pFrmWnd->m_ToolBar, FALSE, FALSE);

              pFrmWnd->ShowControlBar(&pFrmWnd->m_wndToolBar, TRUE, FALSE);

              m_bTBar = true;
       }
}
其中m_bTBar为bool型类变量,可在视图类的头文件中定义,在视图类的代码文件中的构造函数中设置初始值为true。
这里可能需要修改m_wndToolBar为公共的。
4)修改工具条的位图与ID
除了可装入和切换整个工具条(包括位图与ID),也可只装入位图而不改其原来的ID,这需要使用CToolBar类的成员函数LoadBitmap或SetBitmap,其原型分别为
BOOL LoadBitmap( LPCTSTR lpszResourceName );
BOOL LoadBitmap( UINT nIDResource );
BOOL SetBitmap( HBITMAP hbmImageWell );
其中的按钮图片个数必须原来的按钮数相同。
       也可不改变按钮的图片,而只是改变其ID、风格和位置:

void SetButtonInfo( int nIndex, UINT nID, UINT nStyle, int iImage );

5)设置按钮状态
(1) 禁止与激活
工具条上图形按钮的禁止与激活是与其对应菜单项同步的,并不需要另外处理。例如在Student程序中,在还没有按“添加”菜单项时,应该禁止“删除”菜单项功能的使用;同样,如果最多只允许加入两个菜单项,则在已经加入了两个菜单项后,也应该禁止“添加”菜单项功能的使用。具体步骤如下:

<!--[if !supportLists]-->l         <!--[endif]-->可在CStudenView类中设置一个整数型数据成员m_iAddNum (int m_iAddNum;)

<!--[if !supportLists]-->l         <!--[endif]-->在类的构造函数中将该变量初始化为0 (m_iAddNum = 0;)

<!--[if !supportLists]-->l         <!--[endif]-->在消息响应函数OnAdd中,将该变量加一 (m_iAddNum++;)

<!--[if !supportLists]-->l         <!--[endif]-->在消息响应函数OnDel中,将该变量减一 (m_iAddNum--;)

<!--[if !supportLists]-->l         <!--[endif]-->在“删除”菜单项的UI更新响应函数OnUpdateDel中,根据m_iAddNum的值设置“删除”按钮(和菜单项)的禁止与激活状态:

void CStudentView::OnUpdateDel(CCmdUI* pCmdUI) {
       pCmdUI->Enable(m_iAddNum);
}

<!--[if !supportLists]-->l         <!--[endif]-->在“添加”菜单项的UI更新响应函数OnUpdateAdd中,根据m_iAddNum的值设置“添加”按钮(和菜单项)的禁止与激活状态:

void CStudentView::OnUpdateAdd(CCmdUI *pCmdUI) {
       pCmdUI->Enable(m_iAddNum<2);
}
       注意:禁止与激活状态对直接位于菜单条中的菜单项是无效的,但对于位于下拉式或浮动式弹出菜单中菜单项则是有效的。为了观察对比,可以在原来的缺省菜单条中再增加一个“加删”菜单,并且通过拷贝和粘贴将“添加”和“删除”菜单项也加进“加删”菜单中。运行结果参见下图:

<!--[if !vml]--><!--[endif]-->

(2) 是否按下
工具条上图形按钮是否被按下是与其对应菜单项是否已被选中(带有√)同步的,也不需要另外处理。如在Student程序中,切换到MYTB工具条后,可单击按钮Z让其在按下与还原之间切换。具体步骤如下:

<!--[if !supportLists]-->l         <!--[endif]-->可在CStudenView类中设置一个布尔型数据成员zs (bool zs;)

<!--[if !supportLists]-->l         <!--[endif]-->在类的构造函数中将该变量初始化为假 (zs = false;)

<!--[if !supportLists]-->l         <!--[endif]-->在消息响应函数OnNameZs中,切换该变量的真假 (zs = !zs;)

<!--[if !supportLists]-->l         <!--[endif]-->在Z按钮(ID_NAME_ZS)UI更新响应函数OnUpdateNameZs中,根据zs的值来设置按钮是否按下:

void CStudentView::OnUpdateNameZs(CCmdUI* pCmdUI) {
    pCmdUI->SetCheck(zs);
}
2.状态条
状态条既不接受用户输入,也不产生命令消息,只能显示提示/状态信息和其他文本串。状态条窗口由若干文本窗格(pane)组成,窗格分成两类:消息行窗格和状态指示窗格。若想在状态条中显示应用程序数据,则必须禁用标准的状态条。
1) 缺省状态条
缺省状态条用于显示菜单提示和键盘状态。

<!--[if !vml]--><!--[endif]-->

缺省状态条在CMainFrame类中对应于保护型数据成员CStatusBar m_wndStatusBar; 在MainFrm.cpp文件的前面部分中有数组:

static UINT indicators[] =
{
       ID_SEPARATOR,           // 状态行指示器
       ID_INDICATOR_CAPS,        // Caps Lock 指示符
       ID_INDICATOR_NUM,  // Num Lock 指示符
       ID_INDICATOR_SCRL,        // Scroll Lock 指示符
};
在CMainFrame类的消息响应函数OnCreate内有相应的创建代码:
       if (!m_wndStatusBar.Create(this) ||
              !m_wndStatusBar.SetIndicators(indicators,
               sizeof(indicators)/sizeof(UINT)))
       {
              TRACE0("未能创建状态栏/n");
              return -1;      // 未能创建
       }
可用状态条类的成员函数SetPaneText在状态条中显示提示信息。例如

m_wndStatusBar.SetPaneText(0, L"Message line for first pane");

其函数原型为

BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );

其中的nIndex可取不同的值,对应于不同的窗格。
2)定制状态条/显示应用程序数据

<!--[if !supportLists]-->l         <!--[endif]-->将CMainFrame类中的保护数据成员m_wndStatusBar改为公共的

<!--[if !supportLists]-->l         <!--[endif]-->在头文件MainFrm.h中加入窗格ID的枚举变量。如

enum SBID {prompt, xName, xVal, yName, yVal};

<!--[if !supportLists]-->l         <!--[endif]-->去掉原indicators数组中的三个状态指示窗格的ID,加入若干(n个)消息行窗格ID (ID_SEPARATOR),其中第1个(nIndex = 0)用于显示提示信息,其余的(n个)用作应用程序的数据显示。如

static UINT indicators[] =
{

       ID_SEPARATOR,        // 提示  nIndex = 0

       ID_SEPARATOR,          // "x:"     nIndex = 1

       ID_SEPARATOR,          // x      nIndex = 2

       ID_SEPARATOR,         // "y:"     nIndex = 3

       ID_SEPARATOR,         // y      nIndex = 4
};

<!--[if !supportLists]-->l         <!--[endif]-->在创建状态条的代码后(如在CMainFrame::OnCreate函数的尾部),用状态条的成员函数SetPaneInfo来设置每个窗格的ID、风格和宽度(单位似对话框,为1/4英文字母),其函数原型为

void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );

其中nStyle可取值:

<!--[if !supportLists]-->n         <!--[endif]-->SBPS_NOBORDERS  窗格周围无三维边框

<!--[if !supportLists]-->n         <!--[endif]-->SBPS_POPOUT       窗格突出显示

<!--[if !supportLists]-->n         <!--[endif]-->SBPS_DISABLED     不画文本

<!--[if !supportLists]-->n         <!--[endif]-->SBPS_STRETCH     伸缩窗格以填满空间(每个状态条中只能有一个窗格可以被设置成伸缩的)

<!--[if !supportLists]-->n         <!--[endif]-->SBPS_NORMAL      不伸缩、无边框、不凸显

还可以用状态条类的另一成员函数SetPaneText在窗格中显示文本信息。如
m_wndStatusBar.SetPaneInfo(0, prompt, SBPS_STRETCH,0); // 提示
m_wndStatusBar.SetPaneInfo(1, xName, SBPS_NOBORDERS, 8); // "x:"
m_wndStatusBar.SetPaneText(xName, L"x:");
m_wndStatusBar.SetPaneInfo(2, xVal, SBPS_NORMAL, 24); // x
m_wndStatusBar.SetPaneInfo(3, yName, SBPS_NOBORDERS, 8); // "y:"
m_wndStatusBar.SetPaneText(yName, L"y:");
m_wndStatusBar.SetPaneInfo(4, yVal, SBPS_NORMAL, 24); // y

<!--[if !supportLists]-->l         <!--[endif]-->在应用程序中用函数SetPaneText动态修改窗格中的文本串。如

void CStudentView::OnMouseMove(UINT nFlags, CPoint point) {
       wchar_t buf[20];

       CMainFrame *pFrmWnd = (CMainFrame*)GetTopLevelFrame();

       _itow_s(point.x, buf, 20, 10);

       pFrmWnd->m_wndStatusBar.SetPaneText(pFrmWnd->xVal, buf);

       _itow_s(point.y, buf, 20, 10);

       pFrmWnd->m_wndStatusBar.SetPaneText(pFrmWnd->yVal, buf);

       CView::OnMouseMove(nFlags, point);

}
这里可能需要在视图代码文件的开始处包含主框架类的头文件(#include "MainFrm.h");而且需要在视图类中,为WM_MOUSEMOVE消息添加响应函数OnMouseMove。

<!--[if !vml]--><!--[endif]-->

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值