为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

05 菜单、工具栏和状态栏编程

2011-09-29 19页 pdf 2MB 28阅读

用户头像

is_823761

暂无简介

举报
05 菜单、工具栏和状态栏编程 88 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 第5 章 菜单、工具栏和状态栏编程 菜单、工具栏和状态栏是一个完善的Windows应用程序的重要组成部分(但不是必需的)。在 Windows写字板应用程序中,菜单栏、工具栏、状态 栏及其所包含的元素如图5.1所示。 菜单是用户选择可用命令的一个最常用、也是最 重要的手段。在一些情况下,工具栏也是一种更快捷、 更有效的命令输入方式。而状态栏则一般位于主框架 窗口的底部,主要用来显示一些提示信息,可细分为 几个窗格。 本章对使用Vi...
05 菜单、工具栏和状态栏编程
88 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 第5 章 菜单、工具栏和状态栏编程 菜单、工具栏和状态栏是一个完善的Windows应用程序的重要组成部分(但不是必需的)。在 Windows写字板应用程序中,菜单栏、工具栏、状态 栏及其所包含的元素如图5.1所示。 菜单是用户选择可用命令的一个最常用、也是最 重要的手段。在一些情况下,工具栏也是一种更快捷、 更有效的命令输入方式。而状态栏则一般位于主框架 窗口的底部,主要用来显示一些提示信息,可细分为 几个窗格。 本章对使用Visual C++开发Windows程序中,菜 单、工具栏和状态栏的与使用进行详细介绍。 5.1 菜单及其相关资源的使用 菜单是Windows与用户交互的接口之一,Windows的大多数应用程序都提供了菜单操作。当 一个菜单项被选中时,它发出一个命令消息,从而引发相应的消息处理函数的执行。 5.1.1 菜单的种类及开发 在Windows窗口中,菜单有两种标准风格:下拉菜单和弹出菜单(也称上下文菜单)。 ❑ 下拉菜单:一般在应用程序窗口的顶部罗列了 一行按类别排列的菜单。如果用户选择了某一 类别,就会显示一个下拉式菜单。图5 .1所示 即为下拉菜单。 ❑ 弹出菜单:一般在应用程序窗口区域的中间弹 出显示,在应用程序工作区域上面处于自由浮 动状态。在写字板输入窗口中,单击鼠标右键, 即出现弹出式菜单,如图5.2所示。 下拉菜单与弹出菜单只是在形式上不同,其消息 及消息处理机制完全相同。 在程序开发中,简单的菜单编程一般可分为下面 三个步骤: (1)编辑菜单资源,设置菜单属性(包括菜单名和ID); (2)用ClassWizard自动映射菜单消息和成员函数; (3)手工编辑成员函数,加入菜单消息处理代码。 图5.1 菜单栏、工具栏、状态栏及其所包含的元素 命令提示 状态栏 菜单栏工具栏 工具按钮 典型的Windows窗口的菜单、工具栏 下拉菜单菜单项 窗 格 图5.2 弹出式菜单 弹出菜单 5.1.2 菜单的创建与编辑 在Visual C++6.0中,使用MFC AppWizard生成的文档/视图结构的应用程序,系统已为框架创建了 一个标准的主菜单,包括文件、编辑、视图和窗口帮助等标准菜单,定义了各菜单项的ID及相应的命 令处理函数。一般只需要通过菜单资源编辑器,在已有主菜单的基础上添加、设计需要的菜单项即可。 下面结合一个具体的实例讲解菜单的创建与编辑。 1. 创建SDI项目 在Visual C++6.0中,执行“File”→“New”菜单命令,在“Project”选项卡中,创建一个MFC AppWizard[EXE]工程,工程名为“Ch6Demo1”。在MFC AppWizard Step 1的时候,选中“Single document”,即基于单文档的MFC工程,其余的几步采用默认设置。 在工作区窗口的Resource View选项卡中,打开工程资源,选择“Menu”,会发现自动创建了 IDR_MAINFRAME菜单资源,双击它,可打开菜单编辑器,如图5.3所示。 2. 添加菜单项 在主菜单的最右边以及每个下拉菜单展开的最下边都有一个虚线框,该虚线框实际上就是菜单的“生长 点”。将光标移动到虚线框内,双击左键,就启动了菜单项的属性对话框,添加、设置菜单项的相关信息。本 例中,将在IDR_MAINFRAME菜单中添加一个“绘图”顶层菜单,其下设计两个菜单项:“圆形”和“矩形”。 (1)增加顶层菜单“绘图” 在主菜单右侧的虚线框内,双击左键,弹出菜单项属性对话框。在“Caption”编辑框中输入菜单 名“绘图(&D)”,菜单名即显示在菜单上,如图5.4所示。 说明 在菜单名中,可用【Alt】键加该字符作为选 择菜单的快捷方式。菜单“绘图(&D)”示 使用“Alt+D”作为该菜单的快捷键。 此时,属性对话框中默认选中了“Pop-up”选项, 表示该项是一个顶层菜单,其本身不执行菜单命令。 菜单属性对话框中各选项及其含义如表5.1所示。 (2)添加、定义菜单项 双击“绘图”菜单下的虚线框,即可打开菜单 项属性对话框,添加菜单项。在General页面上输入 89 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 图5.3 IDR_MAINFRAME菜单资源 图5.4 添加顶层菜单的属性对话框 表5.1 菜单属性对话框中各选项及其含义 菜单属性项 含 义 ID 表示该菜单项的ID值 Caption 表示该菜单项显示的文本 Separator 表示该菜单项是一条分隔线 Checked 表示该菜单项被选中显示一个标志 Pop-up 选择该菜单项显示一个子菜单 Grayed 该菜单项变灰显示,被禁止 Inactive 该菜单项不被激活 Help Help菜单,通常放在菜单的最右端 Break 选中该菜单项后就退出其所在菜单 Prompt 光标移至该菜单项状态栏显示的文本 Caption菜单项名称及其ID值,在Prompt编辑框中的字符串是选择该菜单项时状态栏上显示的内容。 分别添加“圆形”和“矩形”两个菜单项,如图5.5所示。 如果要删除某个菜单项或弹出菜单,可用鼠标单击该菜单或用上下光标键选择,然后按【Del】 键删除。 图5.5 添加菜单项属性对话框 说明 在菜单实际设计时,菜单的级数一般以2~3级为宜;若单击某菜单项会弹出一对话框,那么在 该菜单项文本后加上“⋯”。 此时编译、运行程序,则“绘图”菜单下的命令都是“灰色”的,即无法选择相应的菜单命令, 这是因为还没有对菜单的命令消息进行映射。 5.1.3 菜单消息 MFC程序可以处理两种菜单消息:WM_COMMAND和UPDATE_COMMAND_UI。 ❑ WM_COMMAND:为菜单命令消息,当选择菜单项、工具栏按钮或加速键之一时会发出菜单 命令消息,MFC依据一定的消息传递途径将消息传递给相应的处理函数进行处理,如果在消息 传递途径的消息映射表中找不到相应的处理函数,该菜单项或按钮会被禁止使用。 ❑UPDATE_COMMAND_UI:为菜单更新消息,处理菜单状态的动态变化。如希望根据程序的执行状 态,激活或禁用某些菜单项,设置选中标记,或更改菜单项文字等,就要定义这一消息处理函数。 在某个菜单显示前,框架将发送菜单内所有菜单项的更新命令,有更新处理函数的菜单项,则调 用其处理函数更新菜单显示方式;没有更新处理函数的菜单项,查找其命令处理函数,若仍然没有, 则将菜单项禁用。 在文档/视图结构的MFC应用程序框架中,在View类、Doc类、CMainFrame类和App类中均可以 响应并处理菜单消息,菜单消息一旦在其中一个类中响应,则不再在其他类中查找响应函数。菜单消 息的传递顺序如图5.6所示。 图5.6 菜单消息的传递顺序 具体而言,当点击一个菜单项的时候,最先接受到菜单项消息的是C M a i n F r a m e框架类, 90 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 菜单消息 View类 Doc类 CMainFrame类 App类 CMainFrame框架类将会把菜单项消息交给它的子窗口View类,由View类首先进行处理;如果View类 检测到没对该菜单项消息做响应,则View类把菜单项消息交由文档类Doc类进行处理;如果Doc类检 测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给View类,由View类再交 还给CMainFrame类处理。如果CMainFrame类查看到CMainFrame类中也没对该消息做响应,则最终 交给App类进行处理。 5.1.4 菜单命令消息的处理 定义好菜单项及其ID后,就需要为菜单命令添加响应函数。实现方法是借助ClassWizard,在需 要响应菜单命令的类的消息映射表中增加一个入口,即定义一个命令消息ON_COMMAND宏。下面 就以为“圆形”菜单命令项添加WM_COMMAND消息处理函数为例,讲解处理菜单消息的实现过程。 1. 用MFC ClassWizard自动映射菜单命令消息和成员函数 执行“View”→“ClassWizard”菜单命令项,或者使用【Ctr l+W】快捷键,打开“MFC ClassWizard”对话框。在对话框的“Message Map”选项卡中的“Class Name ? ? ? ? ? ? ? ? ? ? @6X?@6X?hf? @@1?@@1?hf? @?e@?hf? ?J5??J5?hf? W.Y?W.Y?hf? .Ye.Yhg? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? 列表框中选择要响应 菜单命令的类“CCh6Demo1View”,在“Object IDs”列表框中选择菜单ID“ID_DRAWCIRCLE”, 在“Messages”列表框中选择“COMMAND”菜单命令消息,如图5.7所示。 图5.7 “MFC ClassWizard”对话框 然后单击“Add Funct ion”按钮,弹出“AddMember Function”对话框,可以修改函数名或接受默认函数名,如图 5.8所示。这里使用默认的函数名,单击“OK”按钮,关闭这 个对话框。 此时,在CCh6Demo1View类所在.cpp文件的开始部分会 发现自动添加的消息映射代码: BEGIN_MESSAGE_MAP(CCh6Demo1View, CView) //{{AFX_MSG_MAP(CCh6Demo1View) 91 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 图5.8 “AddMember Function”对话框 ON_COMMAND(ID_DRAWCIRCLE, OnDrawcircle) //消息映射 ⋯⋯ END_MESSAGE_MAP() 2. 手工添加函数的实现代码 添加函数后,在“MFC ClassWizard”对话框中单击“Edit Code”按钮,就可以直接跳至新增函 数代码的定义处。这时,需要手工添加OnDrawcircle()函数的实现代码,如下: void CCh6Demo1View::OnDrawcircle() { // TODO: Add your command handler code here CDC*pDC=GetDC(); //使用GetDC()函数申请CDC类的指针 CRect rect(100,0,300,200); CBrush brush(RGB(180,180,180)); //定义画刷 pDC->FillRect(rect,&brush); //填充绘图区域 pDC->Ellipse(160,10,260,110); //画圆 pDC->TextOut(120,120,"绘制直径为100个像素的圆"); //在圆下方输出文字 ReleaseDC(pDC); //释放CDC类的指针 } 同样的方法,使用MFC ClassWizard为“矩形”菜单项添加“COMMAND”消息映射和处理函数, 代码如下: void CCh6Demo1View::OnDrawrect() { // TODO: Add your command handler code here CDC*pDC=GetDC(); //使用GetDC()函数申请CDC类的指针 CRect rect(100,0,300,200); CBrush brush(RGB(180,180,180)); //定义画刷 pDC->FillRect(rect,&brush); //填充绘图区域 pDC->Rectangle(160,10,260,110); //画矩形 pDC->TextOut(120,120,"绘制边长为100的正方形"); //在矩形下方输出文字 ReleaseDC(pDC); //释放CDC类的指针 } 此时,编译运行程序,就可以运行菜单命令,如图5.9所 示。 5.1.5 菜单更新消息的处理 一般情况下,菜单项具有不止一种状态,经常需要根据应 用的内部状态来对菜单项作相应的改变。例如,在没有选择任 何内容时,编辑菜单下的“复制”、“剪切”等菜单是无效的 (灰色显示)。有时还会看到在菜单项旁边可能还会有检查标 记,表示它是选中的还是不选中的。如在Word的视图菜单下, 根据用户所选的显示模式,在“普通”、“大纲”、“页面”、 “主控文档”前会出现一个点符号,标识当前所选的视图方式。 菜单项的UPDATE_COMMAND_UI消息,就是专门用于处理菜单项的更新。可以为菜单项的 92 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 图5.9 程序运行结果 UPDATE_COMMAND_UI消息编写消息处理函数来处理菜单的更新。 下面就为例子中添加的菜单项实现菜单更新处理。当执行“圆形”菜单命令画圆后,再展开“绘图” 下拉菜单时,“圆形”菜单项前添加一选中标志,而当执行了“矩形”菜单命令后,展开“绘图”下拉 菜单时,“矩形”菜单项前添加一选中标志,而“圆形”菜单项前的选中标志消失。实现过程如下。 1. 用MFC ClassWizard自动映射菜单更新消息和成员函数 执行“View”→“ClassWizard”菜单命令项,或者使用【Ctrl+W】快捷键,打开“MFC ClassWizard” 对话框。在对话框的“Message Map”选项卡中的Class Name列表框中选择要响应菜单命令的类 “CCh6Demo1View”,在“Object IDs”列表框中选择菜单ID“ID_DRAWCIRCLE”,在“Messages”列表 框中选择“UPDATE_COMMAND_UI”菜单命令消息。然后单击“Add Function”按钮,弹出 “AddMember Function”对话框,采用默认的函数名,如图5.10所示。单击“OK”按钮,关闭此对话框。 图5.10 “MFC ClassWizard”对话框 2. 手工添加函数的实现代码 (1)在CCh6Demo1View类的头文件中,声明指示变量m_nDdrawtype,指明当前绘制的图形(值 为1,表示为圆;值为2,表示为矩形)。代码如下: class CCh6Demo1View : public CView { ⋯⋯ public: int m_nDdrawtype; ⋯⋯ (2)在CCh6Demo1View类的构造函数中,将变量m_nDdrawtype初始化为0。代码如下: CCh6Demo1View::CCh6Demo1View() { // TODO: add construction code here m_nDdrawtype=0; } 93 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 (3)在菜单项命令响应函数中,分别将变量m_nDdrawtype设置为相应的值。代码如下: void CCh6Demo1View::OnDrawcircle() { // TODO: Add your command handler code here m_nDdrawtype=1; //表示绘制圆 CDC*pDC=GetDC(); //使用GetDC()函数申请CDC类的指针 ⋯⋯ } void CCh6Demo1View::OnDrawrect() { // TODO: Add your command handler code here m_nDdrawtype=2; //表示绘制矩形 CDC*pDC=GetDC(); //使用GetDC()函数申请CDC类的指针 ⋯⋯ } (4)在菜单项更新命令响应函数中,实现菜单项的更新。代码如下: void CCh6Demo1View::OnUpdateDrawcircle(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->SetCheck(m_nDdrawtype==1); //若为圆形,设置选中标记 } void CCh6Demo1View::OnUpdateDrawrect(CCmdUI* pCmdUI) { // TODO: Add your command update UI handler code here pCmdUI->SetCheck(m_nDdrawtype==2); //若为矩形,设置选中标记 } 其中,CCmdUI类是MFC专门为更新命令提供的一 个类,对于菜单项而言,其相关的函数及其作用如下: • Enable():设置菜单项的允许/禁止状态。 • SetCheck():设置是否在菜单项前面打勾(√)。 • SetRadio():设置是否在菜单项前面画点(·)。 • SetText():设置菜单项显示的的文字。 此时编译运行程序,就实现了菜单的更新操作, 结果如图5.11所示。 5.1.6 为菜单项设置快捷键 快捷键的主要作用就是在选择菜单命令时,不用 鼠标而用事先定义的组合键。如在Word软件中,用户可以使用【Ctrl+C】组合键复制文本,而使用 【Ctrl+V】组合键粘贴文本。这样做的好处就是熟练操作应用程序的用户可以不用鼠标,而用键盘直 接同应用程序实现交互。下面就对程序“Ch6Demo1”新创建的菜单项“圆形”和“矩形”分别添加 快捷键【Ctrl+Y】、【Ctrl+J】。 1. 为菜单项添加快捷键提示 在菜单资源编辑器中,双击“圆形”菜单项,打开菜单项属性对话框。在“Caption”编辑框中, 94 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 图5.11 程序运行结果 在菜单项名后,添加“\t”在字符后,加上快捷键组合【Ctrl+Y】,如图5.12所示。快捷键组合会出 现在菜单项名右端,目的是给用户一个提示。 使用同样的方法,为“矩形”菜单项添加 【Ctrl+J】快捷键提示。 2. 创建快捷键资源 在Visual C++6.0中,快捷键是作为一种资源 存在的,要使用快捷键,需要创建快捷键资源。 在工作区窗口的“ResourceView”选项卡中, 展开快捷键Accelerator资源,MFC AppWizard 为应用程序生成了默认加速键资源,名称为“IDR_MAINFRAME”。双击它打开快捷键列表,在已有 快捷键表后面,有一个空白行,双击它打开快捷键属性对话框。 编辑框中ID栏中需要填写快捷键所代表的菜单项的ID值,在Key栏中键入快捷键,Modifiers栏中 选中按键的组合键(【Shift】、【Alt】或【Ctrl】),Type中一般选择“VirKey”。为“圆形”菜单项设 置快捷键【Ctrl+Y】的属性对话框如图5.13所示。设置完毕,关闭对话框后,定义的快捷键信息就加 入到资源中。 图5.13 添加快捷键提示 使用同样的方法,为“矩形”菜单项添加【Ctrl+J】快捷键资源。 注意 不要对不同菜单命令使用相同的快捷键组合,以免产生二意性;快捷键命令必须有菜单命令与 之对应,快捷键不应该是某个命令唯一启动方式。 此时,编译运行程序,直接通过快捷键【Ctrl+Y】和【Ctrl+J】就可以执行与相应的菜单命令 相同的操作。 5.1.7 弹出菜单的创建与使用 弹出菜单一般在单击鼠标右键时出现,在应用程序工作区域上面处于自由浮动状态,也称为上下 文菜单。与下拉菜单的最大不同是,弹出菜单需要用户手工编程动态加载。下面就为前面创建的 “Ch6Demo1”程序创建一个绘图操作的弹出菜单,在单击鼠标右键时,菜单弹出,菜单显示的内容与 “绘图”下拉菜单完全相同。 95 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 图5.12 添加快捷键提示 1. 创建弹出菜单资源 弹出式菜单可以有两种实现方法。一种方法是单独设计一个明确的菜单用作弹出菜单;另一种方 法是使用已经设计完的主菜单中的一个下拉菜单 作弹出菜单。这里采用前者的方法。 在Visual C++6.0中,打开工程“Ch6Demo1”。 执行“Insert”→“Resource...”菜单命令,在弹 出的对话框中选择“Menu”,如图5.14所示。单 击“New”按钮,即为工程新建了一个菜单资源, 并进入编辑状态。通过属性窗口设置其 I D为 “IDR_POPUPMENU”。 与前面介绍的下拉菜单的资源设计完全相 同,这里为新菜单添加一个“绘图”顶层菜单, 在其下添加“圆形”和“矩形”两个菜单命令项。 通过属性窗口将菜单项的ID分别设置为下拉菜单 相应命令项的ID,如图5.15所示。 2. 弹出菜单的加载 该程序实现的是,当用户在客户窗口单击鼠 标右键时,在鼠标指针所在位置将弹出菜单。 (1)使用MFC AppWizard添加鼠标消息映射 及处理函数 执行“View”→“ClassWizard”菜单命令项,或者使用【Ctr l+W】快捷键,打开“MFC ClassWizard”对话框。在对话框的“Message Map”选项卡中的“Class Name”列表框中选择响应鼠 标消息的类“CCh6Demo1View”,在“Objec t IDs”列表框中选择“CCh6Demo1View”,在 “Messages”列表框中选择“WM_RBUTTONDOWN”消息,单击“Add Function”按钮,即完成了 鼠标消息映射及处理函数的添加,如图5.16所示。 图5.16 添加鼠标消息映射及处理函数对话框 96 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 图5.14 “Insert Resource”对话框 图5.15 弹出菜单的设计 (2)手工添加代码实现弹出菜单 在“MFC ClassWizard”对话框中,单击“Edi t Code”按钮,进入按下鼠标右键处理函数 OnRButtonDown()的入口,在其中添加代码,实现弹出菜单。代码如下: void CCh6Demo1View::OnRButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default CMenu menu; //定义菜单 menu.LoadMenu(IDR_POPUPMENU); //载入浮动菜单资源 CMenu* pM=menu.GetSubMenu(0); //菜单的第一项作为浮动菜单 CPoint pt; GetCursorPos(&pt); //获得鼠标位置 pM->TrackPopupMenu(TPM_LEFTALIGN,pt.x,pt.y,this); //弹出浮动菜单 CView::OnRButtonDown(nFlags, point); } 在MFC中,类CMenu用来处理和菜单有关的功能,CMenu类中包含了许多关于菜单操作的方法函 数,有显示菜单的函数,还可以动态地在菜单中添加、删除菜单项。CMenu类中常用的函数及其功能 如表5.2所示。 表5.2 CMenu类中常用的函数及其功能 函 数 类 别 函 数 名 称 函 数 作 用 GetSafeHmenu 获取由CMenu对象封装的菜单句柄m_hMenu CreateMenu 为CMenu对象创建一个空菜单 初始化函数 CreatePopupMenu 为CMenu对象创建一个空的下拉式菜单 LoadMenu 从资源文件中载入菜单资源并把它附给CMenu对象 LoadMenuIndirect 从内存的菜单模板中载入菜单资源并把它附给CMenu对象 菜单操作函数 TrackPopupMenu 在指定位置显示一个浮动菜单,并跟踪菜单项的选择 DeleteMenu 删除特定的菜单项及其子菜单 AppendMenu 把一个新菜单项添加到指定菜单的末端 GetSubMenu 某一位置得到子菜单的指针,因为一个CMenu对象只能表示一个 弹出菜单,如果菜单中的某一项也为弹出菜单,就需要通过该函数 获取指针 InsertMenu 用于在指定位置插入一菜单 菜单项操作函数 ModifyMenu 用于修改某一位置的菜单 RemoveMenu 用于删除某一位置的菜单 EnableMenuItem 设置菜单有效、无效状态 GetMenuState 获取指定弹出式菜单的状态或得到菜单项的数目 GetMenuString 获取指定菜单项的名称 重载函数 DrawItem 运行用户自行绘制菜单项,并且可以随时改变菜单形状 MeasureItem 获取自己绘制的菜单的大小 其中,TrackPopupMenu函数用于菜单的弹出,其原型如下: BOOL TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pWnd, LPCRECT lpRect = NULL ) 97 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 此函数的参数用于指定弹出菜单显示的位置和方式,含义如下。 ❑ 参数nFlags,指定一个屏幕位置和一个鼠 标按钮标志,可能取值及含义如表5.3所示。 ❑ 参数x,y,指定弹出式菜单坐标的水平位 置和菜单顶部在屏幕上的屏幕坐标中的垂 直位置。 ❑ 参数pWnd,标识拥有此弹出式菜单的窗 口。该窗口接收来自该菜单的所有消息, 当TrackPopupMenu()函数返回时,才接 收WM_COMMAND消息。 ❑ 参数L p R e c t,指向一个R E C T结构或 CRect对象。该结构或者对象中包含一个矩形的屏幕坐标,用户可以在该矩形内单击而不会撤 销此弹出式菜单。如果该参数为NULL,则当用户在此弹出式菜单外单击时,该菜单将消失。 3. 菜单命令的响应 当用户单击弹出菜单的菜单项时,将触发该菜单项的ON_COMMAND消息映射,执行其对应的 菜单消息响应函数,这与下拉菜单完全相同。 然而与下拉菜单不同,当显示弹出菜单时, 并不执行UPDATE_COMMAND_UI消息映射, 也就是说,在操作弹出菜单时,各菜单项的 UPDATE_COMMAND_UI消息映射对应的处理 函数将无法被执行。因此如过需要修改弹出菜单 项的外观、状态等,只能通过使用CMenu类的成 员函数来实现。 编译运行程序,右击客户窗口,弹出菜单, 通过执行其菜单项也能实现相应的绘图操作,如 图5.17所示。 5.2 工具栏的使用 工具栏是一个包含一个或多个命令按钮的窗口,一般情况下附着在窗口客户区上方菜单栏下 面,也可作为一个浮动的小窗口。工具栏为菜单命令提供可视化的快捷操作方式,模拟大部分的 菜单行为。 5.2.1 工具栏的创建 在使用MFC AppWizard创建基于文档/视图结构的MFC应用程序项目时,如前面创建的SDI程序 “Ch6Demo1”,在应用向导的“MFC AppWizard Step 4”的时候,默认选中了“Docking toolbar”, 如图5.18所示。这样生成的应用程序框架就自动添加了可浮动的工具栏。 98 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 表5.3 参数nFlags的取值及其含义 取 值 含 义 TPM_CENTERALIGN 将弹出式菜单相对于x所指定 的坐标水平居中 TPM_LEFTALIGN 定位弹出式菜单使其左边界对 齐x所指定的坐标 TPM_RIGHTALIGN 定位弹出式菜单使其右边界对 齐x所指定的坐标 TPM_LEFTBUTTON 使弹出式菜单跟踪鼠标左键 TPM_RIGHTBUTTON 使弹出式菜单跟踪鼠标右键 图5.17 程序运行结果 图5.18 “MFC AppWizard Step 4”对话框 1. MFC AppWizard自动创建的工具栏资源 打开程序“Ch6Demo1”,在工作区窗口的“Resource View”选项卡中,打开工程资源,选择 “Toolbar”,会发现自动创建了IDR_MAINFRAME工具栏资源,双击它,可打开工具栏编辑器,如图 5.19所示。该窗口的上部显示出了工具栏上的按钮,当用户用鼠标选择某一按钮时,在窗口的下部会 显示该按钮的位图。在窗口旁边有一个绘图工具面板和一个颜色面板,供用户编辑按钮位图时使用。 图5.19 IDR_MAINFRAME工具栏资源 2. 工具栏加载的实现代码 在MFC中,工具栏的功能由类CToolBar实现。工具栏实际上是主框架窗口的子窗口,因此工具栏 对象依附于主框架窗口对象,工具栏的加载也就是在CMainFrame类中完成的。 打开“Ch6Demo1”工程,在工作区窗口的ClassView标签页中,展开CMainFrame类,会发现该 类有一个名为m_wndToolbar的成员。双击该成员,会自动打开类CMainFrame所在的头文件,并将光 标停在对m_wndToolbar成员的定义处。 CToolBar m_wndToolBar; 由此可见m_wndToolBar是一个CToolBar对象,它是CMainFrame的成员。工具栏的实际创建工作 在CMainFrame::OnCreate()函数中完成。 99 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 说明 OnCreate()函数是在创建窗口时被调用的,这时窗口的创建已部分完成,窗口对象的m_hWnd成 员中存放的HWND句柄也已有效,但窗口还是不可见的。因此一般在OnCreate()函数中作一些诸 如创建子窗口的初始化工作。 MFC AppWizard自动生成的OnCreate()函数代码如下: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; //为窗口创建工具栏,并加载IDR_MAINFRAME工具栏资源 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("Failed to create toolbar\n"); return -1; // fail to create } ⋯⋯ //下面的代码使得创建的工具栏具有浮动和停靠功能 // TODO: Delete these three lines if you don't want the toolbar tobe dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); return 0; } 实际上,实现过程可简单描述如下: ❑ 调用CToolBar::CreateEx()函数创建工具栏窗口,参数中的this指针表明主框架窗口是工具栏的 父窗口,余下的参数指定了工具栏的风格。 ❑ 接着调用CToolbar::LoadToolBar(IDR_MAINFRAME)函数以载入工具栏资源。 ❑ 而后调用CToolBar::EnableDocking(CBRS_ALIGN_ANY)函数使工具栏是可以停泊的,但还需调 用CFrameWnd::EnableDocking(CBRS_ALIGN_ANY)函数,只有这样才能实现可停泊的工具栏。 ❑ 最后调用CFrameWnd::DockControlBar函数以停泊工具栏。 说明 初学者了解了MFC AppWizard自动生成的工具栏的创建过程后,就不难手工创建加载自己创建 的工具栏。 5.2.2 编辑工具栏 创建了工具栏后,就需要编辑工具栏资源。工具栏资源由一组按钮组成,每个按钮是一个16色位 图图标,工具栏编辑器提供一个简单的位图编辑器,点击某个图标即可编辑它。 这里同样以“Ch6Demo1”工程为例,在自动生成的“IDR_MAINFRAME”菜单资源中,为5.1 节创建的菜单项“圆形”和“矩形”添加两个对应的工具按钮,实现相同的功能。 在资源编辑器中,单击“IDR_MAINFRAME”菜单资源后的空白按钮后就可以编辑其图像,同 时系统在随后的位置自动添加一个空白按钮。 100 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 双击按钮,即可打开工具按钮属性对话框,如图5.20所示。在ID列表框中列出了当前工程中已存 在的ID,分别为两个按钮设置“ID_DRAWCIRCLE”和“ID_DRAWRECT”。在Prompt编辑框中显示 的是状态栏上的提示命令,在“\n”字符后的文本将显示在按钮的提示窗格中。 图5.20 为程序添加、编辑工具按钮 技巧 如果觉得按钮太小,读者可以用鼠标拖动围绕按钮放大位图的虚框的右下角,把按钮放大些。 注意这样做时工具栏内的所有按钮都将被放大。 在编辑工具按钮时,有下面一些常用的操作。 ❑ 用鼠标可以将一个按钮拖放到工具栏上的其他位置上。若拖动时按下【Ctrl】键,则复制一个 工具按钮。若将工具按钮拖出工具栏,则该工具按钮被删除。 ❑ 按【Delete】键可以将当前工具按钮的图像用背景色填充。 ❑ 在工具按钮之间添加间隔时,可按不同情况来操作。若工具按钮前没有任何间隔,拖动该工具 按钮向右直到它覆盖相邻工具按钮的一半以上后,释放鼠标,则此工具按钮前出现间隔。若工 具按钮前面有间隔而后面没有间隔,拖动该工具按钮向左直到它的左边界接触到它前面的工具 按钮为止,释放鼠标,则此工具按钮后面将出现间隔。若工具按钮前后均有间隔,拖动该工具 按钮向右直到它接触相邻工具按钮,则此工具按钮前的间隔保留,工具按钮后的间隔消失。反 之,若拖动该工具按钮向左直到它接触相邻的前一个工具按钮,则此工具按钮前面的间隔消失, 后面的间隔仍保留。 ❑ 删除工具按钮间隔时,只要将间隔一端的工具按钮拖向间隔另一端的工具按钮,直到与另一个 按钮重叠一半以上即可。 5.2.3 工具栏命令处理 与菜单命令项相同,MFC程序可以处理两种工具栏按钮消息:命令消息WM_COMMAND和更新 消息UPDATE_COMMAND_UI。通过ClassWizard可以方便地为工具按钮添加WM_COMMAND和 UPDATE_COMMAND_UI消息映射和消息处理函数。其实现过程与菜单项完全相同,可参阅5.1.4和 5.1.5节的介绍。 如果工具栏按钮与某个菜单项有相同的ID,则它们共享一个命令响应函数,不需要另外定义命令 响应函数。具有相同ID的菜单项和工具栏按钮还共享提示字符串,它们的显示状态也同步变化。 101 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 如果与工具栏按钮对应的菜单项定义了更新函数,工具栏按钮也会同步实现状态的动态变化。 在前面“Ch6Demo1”程序添加的两个工具栏按钮 的ID分别与绘图下拉菜单下的两个菜单项ID相同,因 此并不需要添加任何代码,即可实现相应功能。 编译运行“Ch6Demo1”程序,使用工具按钮时的 程序运行状态如图5.21所示。 5.2.4 工具栏类CToolBar的简单介绍 在MFC中,CToolBar类包揽了创建工具栏的主要 工作。CToolBar类提供了带有位图按钮和可选分隔符 的工具栏。工具栏按钮可以是下压式按钮、复选按钮 或单项按钮。C To o l B a r对象通常被嵌入派生于类 CFrameWnd或CMDIFrameWnd的框架窗口对象的成 员。CToolBar类在MFC中的继承关系如图5.22所示。 可见,CToolBar类也是窗口类,但它不是直接从 CWnd类派生,而是从控件栏类CCon t ro lBa r派生。 CToolBar类中,除了CControlBar类中的函数外,还有 一些常用的函数及用途,如表5.4所示。 表5.4 CToolBar类中常用的函数及用途 类 别 函 数 名 用 途 Creat 创建工具栏控件,并将它于CToolBar对象关联 SetSize 设置按钮及其表明位图的大小 SetHeight 设置工具栏的高度 CToolBar构造相关函数 LoadToolBar 载入资源管理器所创建的工具栏资源 LoadBitmap 载入包含位图按钮的图像 SetBitmap 设置位图图像 SetButton 设置按钮风格以及按钮上的图像在整个位图中的序号 CommandToIndex 根据指定的命令ID,获取相应工具栏中的按钮序号 GetItemID 获取指定序号的按钮或分隔符的命令ID GetItemRect 获取指定序号按钮所占显示区域的大小 GetButtonStyle 获取按钮风格 CToolBar操作函数 SetButtonStyle 设置按钮风格 GetButtonInfo 获取按钮的信息,包括ID风格、位图序号等 SetButtonInfo 设置按钮的信息 GetButtonText 获取按钮上显示的文字 SetButtonText 设置按钮上显示的文字 说明 本节只是简单介绍了CToolBar类,只有掌握了CToolBar类,才能对工具栏进行深层开发。 102 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ 图5.21 使用工具按钮程序运行结果 图5.22 CToolBar类在MFC中的继承关系 CObject CCmdTarget CWnd CControlBar CToolBar 5.3 状态栏的使用 状态栏是一个水平长条,位于应用程序主窗口的底部。它可以分割成几个窗格,用来显示多组信息。 5.3.1 状态栏的创建 在使用MFC AppWizard创建基于文档/视图结构的MFC应用程序项目时,如前面创建的SDI程序 “Ch6Demo1”,在应用向导的“MFC AppWizard Step 4”的时候,默认选中了“Initial status bar”,如图5.18 所示。这样生成的应用程序框架就自动添加了状态栏。 该状态栏包括4个窗格,分别用来显示状态栏提 示信息和CAPS LOCK、NUM LOCK 、SCROLL LOCK键的状态,如图5.23所示。 在MFC中,工具栏的功能由类CStatusBar实现。 与工具栏相同,状态栏的加载也是在CMainFrame类 中完成的。 打开“Ch6Demo1”工程,在工作区窗口的ClassView标签页中,展开CMainFrame类,会发现该 类有一个名为m_wndStatusBar的成员。双击该成员,会自动打开类CMainFrame所在的头文件,并将 光标停在对m_wndStatusBar成员的定义处。 CStatusBar m_wndStatusBar; 可见m_wndToolBar是一个CStatusBar对象,它是CMainFrame的成员。状态栏的创建工作也是在 CMainFrame::OnCreate()函数中完成。其相关创建代码如下: int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { ⋯⋯ if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT))) { TRACE0("Failed to create status bar\n"); return -1; // fail to create } ⋯⋯ } 可见,状态栏的创建过程共分为三步: (1)构建一个CStatusBar类对象; (2)调用CStatusBar类的Create()函数创建状态栏窗口,参数中的this指针表明主框架窗口是状态 栏的父窗口; (3)调用CStatusBar类的SetIndicators()函数,设置状态栏窗格ID。 SetIndicators()函数的第一个参数indicators是一个ID数组,在CMainFrame类所在的.cpp文件的开 头部分可以找到该数组,如下: 103 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 图5.23 AppWizard自动生成的状态栏 static UINT indicators[] = { ID_SEPARATOR, //状态栏指示器 ID_INDICATOR_CAPS, //显示Caps Lock键状态 ID_INDICATOR_NUM, //显示Num Lock键状态 ID_INDICATOR_SCRL, //显示Scroll Lock键状态 }; indicator数组提供了状态栏窗格的分配信息,它的第一项一般为ID_SEPARATOR,该ID对应的窗 格用来显示命令提示信息,后三项都是字符串ID,可以在String Table字符串资源中找到这三个字符串, 分别是“大写”、“数字”和“滚动”。它们对应的三个窗格用来显示键盘的状态。 掌握了MFC App Wizard生成的应用程序框架中状态栏的创建过程,简单的状态栏编程就显得很容易。 5.3.2 状态栏编程 本节将通过具体的实例讲解状态栏编程的过程。所实现的目标是在“Ch6Demo1”工程已有状态 栏的基础上,添加一个状态栏窗格,用于显示系统当前时间,时间精确到秒,即每秒要更新一次。 1. 添加状态栏窗格 由5.3.1节介绍的状态栏的创建过程可知,可以向数组indicator中增加ID以增加状态栏上的显示窗 格。该ID表示的是一个字符串资源,对于本例,需要显示的是当前时间字符串。在Visual C++中可以 通过字符串资源编辑器添加、编辑字符串资源。 在Visual C++中,打开“Ch6Demo1”工程。在工作区窗口的“Resource View”选项卡中,打开 工程资源,选择“String Table”,在右侧编辑窗口显示了已经创建的字符串资源。在列表最下边的虚 线框中,双击鼠标左键,即弹出字符串属性对话框。在 I D编辑框中,输入需创建的字符串 I D “ID_INDICATOR_CLOCK”;“Caption”编辑框中键入需要的时间格式,如图5.24所示。 图5.24 添加字符串资源 说明 状 态 栏 将 根 据 字 符 串 的 长 度 来 确 定 相 应 窗 格 的 默 认 宽 度 , 因 此 添 加 的 I D 为 “ID_INDICATOR_CLOCK”的字符串资源,其值设定为需要的时间格式即可。 创建了字符串资源后,只需将其 I D“ I D _ I N D I C AT O R _ C L O C K”添加到在资源文件 “MainFrm.cpp”中的indicator数组中即可。其在数组中的位置决定了窗格的位置。这里添加到窗口状 态栏最右边的窗格,代码如下: 104 励 志 照 亮 人 生   编 程 改 变 命 运 零基础学 Visual C++ static UINT indicators[] = { ID_SEPARATOR, //状态栏指示器 ID_INDICATOR_CAPS, //显示Caps Lock键状态 ID_INDICATOR_NUM, //显示Num Lock键状态 ID_INDICATOR_SCRL, //显示Scroll Lock键状态 ID_INDICATOR_CLOCK, //显示时间 }; 此时,编译运行程序,会发现状态栏窗格已添加,只是其显示的是字符串资源设定的固定时间。 下面将实现时间的更新。 2. 更新状态栏窗格 时间窗格显示的时间必须每隔一秒钟更新一次。CStatusBar类的SetPaneText()函数用于设定状态 栏窗格显示的文本信息,而要定时更新,就需要用到定时器。定时器每隔一定的时间间隔就会自动发 出一个WM_TIMER消息,而这个时间间隔可由用户指定。MFC的Window类提供了WM_TIMER消息 处理函数OnTimer(),在该函数内进行更新时间窗格的工作。 (1)创建定时器 SetTimer()函数用于创建定时器,定时器的创建时机显然需要在状态栏创建之后,因此需要在 CMainFrame的OnCreate()函数中完成。 int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; ⋯⋯ SetTimer(1,1000,NULL); //创建定时器 return 0; } SetTimer()函数的第一个参数指定计时器ID为1,第二个参数指定了计时器的时间间隔为1000毫秒 即1秒。这样,每隔1秒,就会发出一个WM_TIMER消息,其处理函数OnTimer()就会被调用一次。 (2)添加WM_TIMER消息映射及处理函数 WM_TIMER消息映射及处理函数的添加可 以通过ClassWizard方便地实现。 执行“View”→“ClassWizard”菜单命令 项,或者使用【Ctrl+W】快捷键,打开“MFC ClassWizard”对话框。在对话框的“Message Map”选项卡中的“Class Name”列表框中选择 响应WM_TIMER消息的类“CMainFrame”,在 “Object IDs”列表框中选择“CMainFrame”,在 “Messages”列表框中选择“WM_TIMER”消息, 单 击 “ Add Func t ion” 按 钮 , 即 完 成 了 WM_TIMER消息映射及处理函数OnTimer()的添 加,如图5.25所示。 105 励 志 照 亮 人 生   编 程 改 变 命 运 第 6 章 菜单、工具栏和状态栏编程 图5.25 添加WM_TIMER消息映射及处理函数对话框 单击“Edit”按钮,进入OnTimer()函数的入口,编辑代码如下: void CMainFrame::OnTimer(UINT nIDEvent) { //
/
本文档为【05 菜单、工具栏和状态栏编程】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索