510 likes | 724 Views
第 5 章 菜单、工具栏和状态栏. 文档应用程序的框架窗口常常包含菜单、工具栏、状态栏、图标和光标等内容,它们是 Windows 应用程序中不可缺少的界面元素,其风格和外观有时直接影响着用户对软件的评价。许多优秀的软件 ( 如 Microsoft Office ) 为增加对用户的吸引力,不惜资源将它们做得多姿多彩,甚至达到真三维的效果。本章将从它们最简单的用法开始入手,逐步深入直到对其进行编程控制。. 5.1 菜单. 为了使 Windows 程序更容易操作,菜单的显示都遵循下列一些规则: ● 若单击某菜单项后,将弹出一个对话框,那么在该菜单项文本后有“ …” 。
E N D
第5章 菜单、工具栏和状态栏 • 文档应用程序的框架窗口常常包含菜单、工具栏、状态栏、图标和光标等内容,它们是Windows应用程序中不可缺少的界面元素,其风格和外观有时直接影响着用户对软件的评价。许多优秀的软件(如Microsoft Office )为增加对用户的吸引力,不惜资源将它们做得多姿多彩,甚至达到真三维的效果。本章将从它们最简单的用法开始入手,逐步深入直到对其进行编程控制。
5.1 菜单 • 为了使Windows程序更容易操作,菜单的显示都遵循下列一些规则: • ●若单击某菜单项后,将弹出一个对话框,那么在该菜单项文本后有“…”。 • ●若某项菜单有子菜单,那么在该菜单项文本后有“”。 • ●若菜单项需要助记符,则用括号将带下划线的字母括起来。助记符与Alt构成一 • 个组合键,当按住“Alt”键不放,再敲击该字母时,对应的菜单项就会被选中。 • ●若某项菜单需要快捷键的支持,则一般将其列在相应菜单项文本之后。所谓 • “快捷键”是一个组合键,如Ctrl+N,使用时是先按下“Ctrl”健不放,然后再按“N” • 键。任何时候按下快捷键,相应的菜单命令都会被执行。
5.1 菜单 • 图5.1是一个菜单样例,注意它们的规则含义。需要说明的是,在常见的菜单系 • 统中,最上面的一层水平排列的菜单称为“顶层菜单”,每一个顶层菜单项可以是 • 一个简单的菜单命令,也可以是下拉(Popup)菜单,在下拉菜单中的每一个菜单 • 项也可是菜单命令或下拉菜单,这样一级一级下去可以构造出复杂的菜单系统。 顶层菜单 弹出菜单 图5.1 菜单样例
5.1.1 用编辑器设计菜单 • 1. 编辑菜单 • 在顶层菜单的最后一项,Visual C++为用户留出了一个空位置,用来输入新的顶层菜单 • 项。在菜单的空位置上双击鼠标左键,出现菜单项的属性对话框,在标题框中输入“测试 • (&T)”,结果如图5.2所示,其中符号&用来将其后面的字符作为该菜单项的助记符,这样当 • 按住“Alt”键不放,再敲击该助记符键时,对应的菜单项就会被选中,或在菜单打开时,直 • 接按相应的助记符键,对应的菜单项也会被选中。 顶层菜单的空位置 子菜单的空位置 保存可见按钮 图5.2 Ex_SDI菜单资源
5.1.1 用编辑器设计菜单 • 1. 编辑菜单 • 单击“测试”菜单项下方的空位置,在菜单项属性对话框中,输入标题“切换菜单 • (&D)”,在ID框输入该菜单项的资源标识符:ID_TEST_CHANGE,结果如图5.3 • 所示。 图5.3 修改菜单项属性 关闭菜单项属性对话框,将新添加的菜单项拖放到“查看”和“帮助”菜单项之间,结果如图5.4所示。需要说明的是,菜单项位置改变后,其属性并没改变。 图5.4 菜单项“测试”拖放后的位置
5.1.1 用编辑器设计菜单 • 2. 菜单命令的消息映射 • (1) 选择“查看”→“建立类向导”菜单命令或按Ctrl+W快捷键,则出现MFC • ClassWizard对话框,并自动切换到Message Maps页面。从“Class name”列表 • 中选择CMainFrame,在IDs列表中选择ID_TEST_CHANGE,然后在Messages • 框中选择COMMAND消息。如图5.5所示。 图5.5 菜单命令消息的映射
2. 菜单命令的消息映射 • (2) 单击[Add Function]按钮或双击COMMAND消息,出现“Add Member • Function”对话框以输入成员函数的名称。系统默认的函数名为OnTestChange, • 如图5.6所示。该函数是对菜单项ID_TEST_CHANGE的映射,也就是说,当应 • 用程序运行后,用户选择“测试”→“对话框”菜单时,该函数OnTestDlg被调用,执 • 行函数中的代码。 图5.6 添加映射函数 (3) 单击[OK]按钮,在ClassWizard的“Member functions”列表中将列出新增加的成员函数。选择此函数,单击[Edit Code]按钮(或直接在函数名双击鼠标),在此成员函数中添加下列代码: void CMainFrame::OnTestChange() { // TODO: Add your command handler code here AfxMessageBox("现在就切换吗?"); }
2. 菜单命令的消息映射 • (4) 编译并运行。在应用程序的顶层菜单上,单击“测试”菜单项,然后将鼠标移动 • 到弹出的子菜单项“切换菜单”上,则结果如图5.7所示,此时状态栏上显示该菜单 • 项的提示信息,该信息就是在前图5.3的菜单项属性对话框“提示”框中设置的内 • 容。单击“切换菜单”,则弹出一个消息对话框,显示内容“现在就切换吗?”。 图5.7 Ex_SDI运行后的菜单
5.1.2 使用键盘快捷键 • (1) 展开项目工作区窗口中Accelerator的资源项,双击IDR_MAINFRAME,出现 • 如图5.8的加速键资源列表。 下端的空行 图5.8 Ex_SDI的加速键资源
5.1.2 使用键盘快捷键 • (2) 建立一个新的加速键时,只要双击加速键列表的最下端的空行,弹出如图5.9 • 所示的“Accel Properties”(加速键属性)对话框,其中可设置的属性如表5.2所示 图5.9 加速键属性对话框 表5.2 加速键General属性对话框的各项含义
5.1.2 使用键盘快捷键 • (3) 在加速键属性对话框中,先选择在Ex_SDI应用程序菜单资源添加的“切换菜 • 单”菜单项ID_TEST_CHANGE作为要联用的加速键的ID标识符,然后单击[下一 • 键]按钮,并按下Ctrl+1作为此加速键的键值。需要说明的是,为了使其他用户能 • 查看并使用该加速键,还需在相应的菜单项文本后面添加加速键内容。例如,可 • 将ID_TEST_CHANGE菜单项的标题改成“切换菜单(&C)\tCtrl+1”,其中“\t”是将后 • 面的“Ctrl+1”定位到一个水平制表位。 • (4) 编译运行并测试。当程序运行后,按Ctrl+1键将执行相应的菜单命令。
5.1.3 菜单的编程控制 • 1. 创建菜单 • CMenu类的CreateMenu和CreatePopupMenu分别用来创建一个菜单或子菜单框 • 架,它们的原型如下: • BOOL CreateMenu( ); // 产生一个空菜单 • BOOL CreatePopupMenu( ); // 产生一个空的弹出式子菜单 • 2. 装入菜单 • 将菜单从资源装入应用程序中,需调用CMenu成员函数LoadMenu,或者用 • SetMenu对应用程序菜单进行重新设置。 • BOOL LoadMenu( LPCTSTR lpszResourceName ); • BOOL LoadMenu( UINT nIDResource ); • 其中,lpszResourceName为菜单资源名称,nIDResource为菜单资源ID标识 • 符。
5.1.3 菜单的编程控制 • 3. 添加菜单项 • 当菜单创建后,用户可以调用AppendMenu或InsertMenu函数来添加一些菜单项。但每次添加 • 时,AppendMenu是将菜单项添加在菜单的末尾处,而 • InsertMenu在菜单的指定位置处插入菜单项,并将后面的菜单项依次下移。 • BOOL AppendMenu( UINT nFlags, UINT nIDNewItem = 0,LPCTSTR lpszNewItem = NULL ); • BOOL AppendMenu( UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp ); • BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem = 0, • LPCTSTR lpszNewItem = NULL ); • BOOL InsertMenu( UINT nPosition, UINT nFlags, UINT nIDNewItem, const CBitmap* pBmp ); • 其中,nIDNewItem表示新菜单项的资源ID标识符,lpszNewItem表示新菜单项的内容,pBmp用 • 于菜单项的位图指针,nPosition表示新菜单项要插入的菜单项位置。nFlags表示要增加的新菜单 • 项的状态信息,它的值影响其他参数的含义,如表5.3所示。
5.1.3 菜单的编程控制 • 4. 删除菜单项 • 调用DeleteMenu函数可将指定的菜单项删除,函数DeleteMenu的原型如下: • BOOL DeleteMenu( UINT nPosition, UINT nFlags ); • 其中,参数nPosition表示要删除的菜单项位置,它由nFlags进行说明。若当 • nFlags为MF_BYCOMMAND时,nPosition表示菜单项的ID标识符,而当nFlags • 为MF_BYPOSITION时,nPosition表示菜单项的位置(第一个菜单项位置为0)。 • 5. 获取菜单项 • 下面的3个CMenu成员函数分别获得菜单的项数、菜单项的ID标识符以及弹出式 • 子菜单的句柄。 • UINT GetMenuItemCount( ) const; • 该函数用来获得菜单的菜单项数,调用失败后返回-1。 • UINT GetMenuItemID( int nPos ) const; • 该函数用来获得由nPos指定菜单项位置(以0为基数)的菜单项的标识号,若nPos • 是SEPARATOR(分隔符),则返回-1。 • CMenu* GetSubMenu( int nPos ) const; • 该函数用来获得指定菜单的弹出式菜单的菜单句柄。该弹出式菜单位置由参数 • nPos指定,开始的位置为0。若菜单不存在,则创建一个临时的菜单指针。
5.1.3 菜单的编程控制 • [例Ex_Menu] 用程序添加并处理一个菜单项 • 创建一个默认的单文档应用程序Ex_Menu。 • (2) 选择“查看”菜单→“Resource Symbols…”命令,弹出如图5.10所示的“资源符 • 号”对话框,它能对应用程序中的资源标识符进行管理。由于程序中要添加的菜 • 单项需要一个标识值,最好用一个标识符来代替这个值,这是一个好的习惯。因 • 此这里通过“资源符号”对话框来创建一个新的标识符。 图5.10 “资源符号”对话框
[例Ex_Menu] • (3) 单击[新建]按钮,弹出如图5.11所示的“New Symbol”(新标识符)对话框。在名 • 字(Name)框中输入一个新的标识符ID_NEW_MENUITEM。在值(Value)框中, • 输入该ID的值,系统要求用户定义的ID值应大于15(0X000F)而小于 • 61440(0XF000)。保留默认的ID值101,单击[确定]按钮。 图5.11 新标识符对话框
[例Ex_Menu] • (4) 关闭“资源符号”对话框,在CMainFrame::OnCreate函数中添加下列代码,该函数在框 • 架窗口创建时自动调用。 • int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) • { ... • CMenu* pSysMenu = GetMenu(); // 获得程序菜单指针 • CMenu* pSubMenu = pSysMenu->GetSubMenu(1); // 获得第二个子菜单的指针 • CString StrMenuItem("新的菜单项"); • pSubMenu->AppendMenu(MF_SEPARATOR); // 增加一水平分隔线 • pSubMenu->AppendMenu(MF_STRING,ID_NEW_MENUITEM,StrMenuItem); • // 在子菜单中增加一菜单项 • m_bAutoMenuEnable = FALSE; // 关闭系统自动更新菜单状态 • pSysMenu->EnableMenuItem(ID_NEW_MENUITEM,MF_BYCOMMAND|MF_ENABLED); • // 激活菜单项 • DrawMenuBar(); // 更新菜单 • return 0; • }
[例Ex_Menu] • (5) 此时编译运行后,结果如图5.12所示。但此时选择“新的菜单项”命令不会有反 • 应。 图5.12 程序添加的菜单项
[例Ex_Menu] • (6) 用MFC ClassWizard在CMainFrame添加OnCommand消息函数的重载,并 • 添加下列代码: • BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) • { • // wParam的低字节表示菜单、控件、加速键的命令ID • if (LOWORD(wParam) == ID_NEW_MENUITEM) • MessageBox("你选中了新的菜单项"); • return CFrameWnd::OnCommand(wParam, lParam); • } • (7) 编译运行并测试。这时当选择菜单“编辑”→“新的菜单项”命令后,就会弹一个 • 对话框,显示“你选中了新的菜单项”消息。
5.1.4 使用快捷菜单 • 快捷菜单是一种浮动的弹出式菜单,它是一种新的用户界面设计风格。当用户按 • 下鼠标右键时,就会相应地弹出一个浮动菜单,其中提供了几个与当前选择内容 • 相关的选项。 • 用资源编辑器和MFC库的CMenu::TrackPopupMenu函数可以很容易地创建这样 • 的菜单,CMenu::TrackPopupMenu函数原型如下: • BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL ); • 该函数用来显示一个浮动的弹出式菜单,其位置由各参数决定。其中,nFlags表示 • 菜单在屏幕显示的位置以及鼠标按钮标志,如表5.4所示。 表5.4 nFlags的值及其对其他参数的影响
5.1.4 使用快捷菜单 • [例Ex_ContextMenu] 使用快捷菜单 • (1) 创建一个默认的单文档应用程序Ex_ContextMenu。 • 用MFC ClassWizard在CEx_ContextMenuView类添加WM_CONTEXTMENU消息映射,并在映 • 射函数中添加下列代码: • void CEx_ContextMenuView::OnContextMenu(CWnd* pWnd, CPoint point) • { • CMainFrame* pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd;// 获得主窗口指针 • CMenu* pSysMenu = pFrame->GetMenu(); // 获得程序窗口菜单指针 • int nCount = pSysMenu->GetMenuItemCount(); // 获得顶层菜单个数 • int nSubMenuPos = -1; • for (int i=0; i<nCount; i++) • { // 查找“文件”菜单 • CString str; • pSysMenu->GetMenuString(i, str, MF_BYPOSITION); • if (str.Left(4) == "文件") • { nSubMenuPos = i; break; } • } • if (nSubMenuPos<0) return; // 没有找到,返回 • pSysMenu->GetSubMenu( nSubMenuPos) • ->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON, point.x, point.y, this); • }
[例Ex_ContextMenu] • (3) 在Ex_ContextMenuView.cpp文件的前面添加CMainFrame类的文件包含: • #include "Ex_ContextMenuView.h" • #include "MainFrm.h" • (4) 运行并测试。当用户在应用程序窗口的客户区中右击鼠标,会弹出如图5.13 • 的快捷菜单。 客户区 图5.13 快捷菜单
5.2 工具栏 • 5.2.1 使用工具栏编辑器 • 选择菜单“文件”→“打开工作区”,将前面的单文档应用程序Ex_SDI调入或重新创 • 建。在项目工作区窗口中选择ResourceView页面,双击“Toolbar”项中的 • IDR_MAINFRAME,则工具栏编辑器出现在主界面的右边,如图5.14所示。 空按钮 图形工具箱 颜色工具箱 图5.14 工具栏编辑器窗口
5.2.1 使用工具栏编辑器 • 下面就工具栏按钮的一般操作进行说明。 • (1) 创建一个新的工具栏按钮。 • (2) 移动一个按钮。 • (3) 删除一个按钮。 • (4) 在工具栏中插入空格。 • 在工具栏中插入空格有以下几种情况: • ●如果按扭前没有任何空格,拖动该按钮向右移动并当覆盖相邻按钮的一半以上时,释放鼠标键,则此按钮前出现空格。 • ●如果按钮前有空格而按钮后没有空格,拖动该按钮向左移动并当按钮的左边界接触到前面按钮时,释放鼠标键,则此按钮后将出现空格。 • ●如果按钮前后均有空格,拖动该按钮向右移动并当接触到相邻按钮时,则此按钮前的空格保留,按钮后的空格消失。相反,拖动该按钮向左移动并当接触到前一个相邻按钮时,则此按钮前面的空格消失,后面的空格保留。
5.2.1 使用工具栏编辑器 • 工具栏按钮的一般操作进行说明 • (5) 工具栏按钮属性的设置。双击某按钮弹出其属性对话框,如图5.15所示。属 • 性对话框中的各项说明见表5.5。 图5.15 工具栏按钮属性对话框 表5.5 工具栏按钮属性对话框的各项含义
5.2.1 使用工具栏编辑器 • 工具栏按钮的一般操作进行说明 • (6) 工具栏和菜单相结合。工具栏和菜单相结合是指当选择工具按钮或菜单命令 • 时,操作结果是一样的。使它们结合的具体方法是在工具按钮的属性对话框中将 • 按钮的ID标识符设置为相关联的菜单项ID。需要说明的是,对于单独工具按钮命 • 令消息的映射方法跟菜单命令是一样的。
5.2.2 多个工具栏的使用 • [例Ex_SDI] 使用多个工具栏 • 1) 添加并更改应用程序菜单 • (1) 创建一个默认的单文档应用程序Ex_SDI。 • (2) 按快捷键Ctrl+R,弹出“插入资源”对话框,在资源类型中选定“Menu”,如图 • 5.16。 图5.16 “插入资源”对话框
[例Ex_SDI] • 1) 添加并更改应用程序菜单 • (3) 单击[新建]按钮,系统就会为应用程序添加一个新的菜单资源,并自动赋给它 • 一个默认的标识符名称(第一次为IDR_MENU1,以后依次为IDR_MENU2、IDR_ • MENU3、...),同时自动打开这个新的菜单资源,如图5.17所示。 菜单空位置 菜单默认ID 图5.17 添加菜单资源后的开发环境
[例Ex_SDI] • 1) 添加并更改应用程序菜单 • (4) 在Menu资源的ID_MENU1上右击鼠标,从弹出的快捷菜单中选择 • “Properties”命令,出现如图5.18所示的菜单属性对话框,在这里可以重新指定菜 • 单资源ID,设置菜单资源的语言和条件,这个条件用来决定菜单资源包含到哪个 • 环境中,例如当指定条件为_DEBUG,则菜单资源只存在于Debug编译环境中。 图5.18 菜单属性对话框
[例Ex_SDI] • 1) 添加并更改应用程序菜单 • (5) 为菜单ID_MENU1添加一个顶层弹出菜单项“测试(&T)”,并在该菜单下添加一 • 个子菜单项“返回(&R)”,ID设为ID_TEST_RETURN,如图5.19所示。需要再次 • 强调的是,符号&用来指定后面的字符是一个助记符。 • (6) 打开Ex_SDI程序菜单资源IDR_MAINFRAME,在“查看”菜单的最后添加一个 • 子菜单项“显示测试菜单(&M)”,ID设为ID_VIEW_TEST。 图5.19 设计新的菜单资源
[例Ex_SDI] • 1) 添加并更改应用程序菜单 • (7) 为CMainFrame类添加一个CMenu类型的成员变量m_NewMenu。如下面的 • 代码: • class CMainFrame : public CFrameWnd • { • … • // Attributes • public: • CMenu m_NewMenu; • (8) 按快捷键Ctrl+W打开MFC ClassWizard对话框,切换到Message Maps页 • 面,从“Class name”列表中选择CMainFrame,分别为菜单项ID_VIEW_TEST和 • ID_TEST_RETURN添加COMMAND消息映射,使用默认的消息映射函数名,并 • 添中下列代码:
[例Ex_SDI] • (8)添中下列代码: • void CMainFrame::OnViewTest() • { • m_NewMenu.Detach(); // 使菜单对象和菜单句柄分离 • m_NewMenu.LoadMenu( IDR_MENU1 ); • SetMenu(NULL); // 清除应用程序菜单 • SetMenu( &m_NewMenu ); // 设置应用程序菜单 • } • void CMainFrame::OnTestReturn() • { • m_NewMenu.Detach(); • m_NewMenu.LoadMenu( IDR_MAINFRAME ); • SetMenu(NULL); • SetMenu( &m_NewMenu ); • } • 代码中,LoadMenu和Detach都是CMenu类成员函数,LoadMenu用来装载菜单资源,而 • Detach是使菜单对象与菜单句柄分离。在调用LoadMenu后,菜单对象m_NewMenu就拥 • 有一个菜单句柄,当再次调用LoadMenu时,由于菜单对象的句柄已经创建,因而会发生 • 运行时错误,但当菜单对象与菜单句柄分离后,就可以再次创建菜单了。SetMenu是 • CWnd类的一个成员函数,用来设置应用程序的菜单。 • (9) 第一次编译运行并测试。
[例Ex_SDI] • 2. 添加并设计工具栏按钮 • (1) 在项目工作区的ResourceView页面中,展开Toolbar(工具栏)资源,双击双击 • “Toolbar”项中的IDR_MAINFRAME,显示工具栏编辑器。 • (2)利用工具栏编辑器设计两个工具按钮,其位置和内容如图5.20所示。 • (3)双击刚才设计的第一个工具按钮,弹出该工具按钮的属性对话框,将该工具 • 按钮的ID号设为ID_TEST_RETURN,在提示框内键入“返回应用程序主菜单\n返 • 回主菜单”。 图5.20 设计的两个工具栏按钮
[例Ex_SDI] • 2. 添加并设计工具栏按钮 • (4)双击刚才设计的第二个工具按钮,弹出该工具按钮的属性对话框,将该工具 • 按钮的ID号设为ID_VEW_TEST,在提示框内键入“显示测试菜单\n显示测试菜 • 单”。 • (5) 第二次编译运行并测试。当程序运行后,将鼠标移至刚才设计的第一个工具 • 按钮处,这时在状态栏上显示出“返回应用程序主菜单”信息,若稍等片刻后,还 • 会弹出提示小窗口,显示出“返回主菜单”字样,如图5.21所示。单击新添加的这 • 两个按钮,会执行相应的菜单命令。 图5.21 工具按钮提示
[例Ex_SDI] • 3. 添加工具栏 • (1) 在项目工作区切的ResourceView页面中,展开Toolbar(工具栏)资源,用鼠标 • 单击IDR_MAINFRAME不松开,然后按下Ctrl键,移动鼠标将IDR_MAINFRAME • 拖到Toolbar资源名称上,这样就复制了工具栏默认资源IDR_MAINFRAME,复 • 制后的资源标识系统自动设为IDR_MAINFRAME1。 • (2) 右击工具栏资源IDR_MAINFRAME1,从弹出的快捷菜单中选择Properties命 • 令,如图5.22所示,将ID设为IDR_TOOLBAR1。 • (3) 双击IDR_TOOLBAR1,打开工具栏资源,按图5.23删除不要的工具按钮。 图5.23 删除不要的工具按钮 图5.22 工具栏属性对话框 (4)在CMainFrame类中添加一个成员变量m_wndTestBar,变量类型为CToolBar。CToolBar类封装了工具栏的操作。
[例Ex_SDI] • 3. 添加工具栏 • (5) 在CMainFrame::OnCreate函数中添加下面的工具栏创建代码: • int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) • { • if (CFrameWnd::OnCreate(lpCreateStruct) == -1) • return -1; • int nRes = m_wndTestBar.CreateEx(this, TBSTYLE_FLAT, • WS_CHILD | WS_VISIBLE | • CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | • CBRS_FLYBY | CBRS_SIZE_DYNAMIC, • CRect(0,0,0,0), AFX_IDW_TOOLBAR + 10); • if (!nRes || !m_wndTestBar.LoadToolBar(IDR_TOOLBAR1)) • { • TRACE0("Failed to create toolbar\n"); • return -1; // fail to create • } • … • m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); • m_wndTestBar.EnableDocking(CBRS_ALIGN_ANY); • EnableDocking(CBRS_ALIGN_ANY); • DockControlBar(&m_wndToolBar); • DockControlBar(&m_wndTestBar); • … • return 0; • }
[例Ex_SDI] • 4. 完善程序代码 • (1) 事实上这不是本例要的结果。还需调用CFrameWnd类的成员函数 • ShowControlBar来使程序一开始运行时隐藏工具栏IDR_TOOLBAR1。 • (2) 在CMainFrame::OnCreate函数中添加下列代码: • int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) • { • … • ShowControlBar( &m_wndTestBar, FALSE, FALSE ); // 关闭测试工具栏 • return 0; • } • 代码中,ShowControlBa函数有三个参数,第一个参数用来指定要操作的工具栏 • 或状态栏指针,第二个参数是一个布尔型,当为TRUE时表示显示,否则表示隐 • 藏,第三个参数用来表示是否延迟显示或隐藏,当为FALSE时表示立即显示或隐 • 藏。
[例Ex_SDI] • 4. 完善程序代码 • (3) 在CMainFrame::OnViewTest和CMainFrame::OnTestReturn函数中添加下列 • 代码: • void CMainFrame::OnViewTest() • { • … • ShowControlBar( &m_wndTestBar, TRUE, FALSE ); // 显示测试工具栏 • ShowControlBar( &m_wndToolBar, FALSE, FALSE ); // 关闭主工具栏 • } • void CMainFrame::OnTestReturn() • { • … • ShowControlBar( &m_wndTestBar, FALSE, FALSE ); // 关闭测试工具栏 • ShowControlBar( &m_wndToolBar, TRUE, FALSE ); // 显示主工具栏 • }
[例Ex_SDI] • 4. 完善程序代码 • (4) 编译运行并测试,结果如图5.25所示,左边是一开始运行的结果,右边是单击工具按钮 运行的结果。 图5.25 Ex_SDI最后运行结果
5.3 状态栏 • 状态栏是一条水平长条,位于应用程序的主窗口的底部。它可以分割成几个窗 • 格,用来显示多组信息。 • 状态栏的定义 • 用MFC AppWizard创建的单文档或多文档应用程序框架中,有一个静态的 • indicators数组,它是在MainFrm.cpp文件中定义的,被MFC用作状态栏的定义。 • 图5.26列出了indicators数组元素与标准状态栏窗格的关系。 图5.26 indicators数组的定义
5.3.2 状态栏的常用操作 • Visual C++ 6.0中可以方便地对状态栏进行操作,如增减窗格、在状态栏中显示 • 文本、改变状态栏的风格和大小等,并且MFC的CStatusBar类封装了状态栏的 • 大部分操作。 • 1. 增加和减少窗格 • 状态栏中的窗格可以分为信息行窗格和指示器窗格两类。若在状态栏中增加一个 • 信息行窗格,则只需在indicators数组中的适当位置中增加一个ID_SEPARATOR • 标识即可;若在状态栏中增加一个用户指示器窗格,则在indicators数组中的适 • 当位置增加一个在字符串表中定义过的资源ID,其字符串的长度表示用户指示器 • 窗格的大小。若状态栏减少一个窗格,其操作与增加相类似,只需减少 • indicators数组元素即可。
5.3.2 状态栏的常用操作 • 2. 在状态栏上显示文本 • 有3种办法可以在状态栏窗格显示文本信息: • (1) 调用CWnd::SetWindowText更新信息行窗格(或窗格0)中的文本。由于状态栏 • 也是一种窗口,故在使用时可直接调用。若状态栏变量为m_wndStatusBar,则 • m_wndStatusBar. SetWindowText(“消息”)语句将在信息行窗格(或窗格0)内显示 • “消息”字样。 • (2) 手动处理状态栏的ON_UPDATE_COMMAND_UI更新消息,并在处理函数中 • 调用CCmdUI::SetText函数。 • (3) 调用CStatusBar::SetPaneText函数更新任何窗格(包括信息行窗格)中的文 • 本。此函数原型描述如下: • BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE ); • 其中,lpszNewText表示要显示的字符串。nIndex是表示设置的窗格索引(第一个 • 窗格的索引为0)。若bUpdate为TRUE,则系统自动更新显示的结果。 • 值得注意的是,在使用第2种方法时,应按一定的步骤进行。例如下面的示例过 • 程是在状态栏的最右边两个窗格中显示出当前鼠标在窗口客户区的位置。
5.3.2 状态栏的常用操作 • [例Ex_SDIMouse] 将鼠标在窗口客户区的位置显示在状态栏上 • (1) 创建一个默认的单文档应用程序Ex_SDIMouse。 • (2) 将项目工作区切换到ClassView页面,展开CMainFrame所有项,双击构造函 • 数CMainFrame,在文档窗口中出现该函数的定义,在它的前面就是状态栏数组 • 的定义。 • (3) 将状态栏indicators数组的定义改为下列代码: • static UINT indicators[] = • { ID_SEPARATOR, • ID_SEPARATOR, • };
[例Ex_SDIMouse] • (4) 由于鼠标移动消息WM_MOUSEMOVE在CMainFrame类映射后不起作用,因此只能映 • 射到CEx_SDIMouseView类中。但是,这样一来,就需要更多的代码,因为状态栏对象 • m_wndStatusBar是在CMainFrame类定义的成员变量,因而需要在CEx_SDIMouseView • 类中添加访问CMainFrame类的代码。CEx_SDIMouseView::OnMouseMove函数代码如下: • void CEx_SDIMouseView::OnMouseMove(UINT nFlags, CPoint point) • { • CString str; • CMainFrame* pFrame=(CMainFrame*)AfxGetApp()->m_pMainWnd; // 获得主窗口指针 • CStatusBar* pStatus=&pFrame->m_wndStatusBar; // 获得主窗口中的状态栏指针 • if (pStatus) • { • str.Format("X=%d, Y=%d",point.x, point.y); // 格式化文本 • pStatus->SetPaneText(1,str); // 更新第二个窗格的文本 • } • CView::OnMouseMove(nFlags, point); • }
[例Ex_SDIMouse] • (5) 将MainFrm.h文件中的受保护变量m_wndStatusBar变成公共变量。 • (6) 在Ex_SDIMouseView.cpp文件的开始处增加下列语句: • #include "Ex_SDIMouseView.h" • #include "MainFrm.h" • (7) 编译并运行,结果如图5.27所示。 图5.27 鼠标的位置显示在状态栏上
5.3.2 状态栏的常用操作 • 3. 改变状态栏的风格 • 在MFC的CStatusBar类中,有两个成员函数可以改变状态栏风格,它们是: • void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth ); • void SetPaneStyle( int nIndex, UINT nStyle ); • 其中,参数nIndex表示要设置的状态栏窗格的索引,nID用来为状态栏窗格指定 • 新的ID,cxWidth表示窗格的像素宽度,nStyle表示窗格的风格类型,用来指定 • 窗格的外观,例如SBPS_POPOUT表示窗格是凸起来的,具体见表5.6。 表5.6 状态栏窗格的风格类型
5.4 交互对象的动态更新 • [例Ex_Update] 交互对象的动态更新 • (1) 创建一个默认的单文档应用程序Ex_Update。 • (2) 将项目工作区窗口切换到ResourceView页面,展开Toolbar资源节点。 • (3) 选中Toolbar资源IDR_MAINFRAME,然后按下Ctrl键不放,移动鼠标将 • IDR_MAIN- FRAME拖到Toolbar资源名称上,这样就复制了工具栏默认资源 • IDR_MAINFRAME,复制后的资源标识系统自动设为IDR_MAINFRAME1。 • (4) 右击IDR_MAINFRAME1,从弹出的快捷菜单中选择Properties命令,在弹出 • 的属性对话框中将ID改为IDR_NEWBAR。 • (5) 将IDR_NEWBAR工具按钮删除几个以与IDR_MAINFRAME有所区别。 • (6) 打开MainFrm.h文件,在CMainFrame类中声明一个CToolBar类变量m_wnd • NewBar,一个BOOL型的成员变量m_bNewBar。 • protected: // control bar embedded members • CStatusBar m_wndStatusBar; • CToolBar m_wndToolBar; • CToolBar m_wndNewBar; • BOOL m_bNewBar;
[例Ex_Update] • (7)在CMainFrame::OnCreate中添加下列代码: • int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) • { • if (CFrameWnd::OnCreate(lpCreateStruct) == -1) • return -1; • if (!m_wndNewBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP • | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, • CRect(0,0,0,0), AFX_IDW_TOOLBAR + 10) || • !m_wndNewBar.LoadToolBar(IDR_NEWBAR)) • { • TRACE0("Failed to create newbar\n"); • return -1; // fail to create • } • … • m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); • m_wndNewBar.EnableDocking(CBRS_ALIGN_ANY); • EnableDocking(CBRS_ALIGN_ANY); • DockControlBar(&m_wndToolBar); • DockControlBar(&m_wndNewBar); • return 0; • }
[例Ex_Update] • (8)打开菜单资源IDR_MAINFRAME,在“查看”菜单下添加一个菜单项“新工具栏 • (&N)”,ID标识符设定为ID_VIEW_NEWBAR。 • (9)用MFC ClassWizard在CMainFrame类中添加菜单ID_VIEW_NEWBAR的 • COMMAND和UPDATE_COMMAND_UI两个消息映射,并在映射函数中添加下 • 列代码: • void CMainFrame::OnViewNewbar() • { • m_bNewBar = !m_bNewBar; • ShowControlBar( &m_wndNewBar, m_bNewBar, FALSE); • // 显示或隐藏工具栏 • } • void CMainFrame::OnUpdateViewNewbar(CCmdUI* pCmdUI) • { • m_bNewBar = m_wndNewBar.IsWindowVisible(); • pCmdUI ->SetCheck(m_bNewBar); • }