Visual c 第5章菜单、工具栏和状态栏编程 菜单、工具栏和状态栏是一个完善的 Windows应用程序的重要组成部分(但不是必需的)。在 Windows写字板应用程序中,菜单栏、工具栏、状态,mtx 旧网 栏及其所包含的元素如图5.1所示 )排)查者以人式0封吧 菜单是用户选择可用命令的一个最常用、也是最 典型的n对窗口的菜 重要的手段。在一些情况下,工具栏也是一种更快捷 工具按钮 更有效的命令输入方式。而状态栏则一般位于主框架 工具栏 菜单栏 下拉菜单菜单项 窗口的底部,主要用来显示一些提示信息,可细分为 几个窗格。 本章对使用 Visual c++开发 Windows程序中,菜 状态栏 单、工具栏和状态栏的设计与使用进行详细介绍 当前的所的段落 5.1菜单及其相关资源的使用 图5.1菜单栏、工具栏、状态栏及其所包含的元素 菜单是 Windows与用户交互的标准接口之一, Windows的大多数应用程序都提供了菜单操作。 个菜单项被选中时,它发出一个命令消息,从而引发相应的消息处理函数的执行。 5.1.1菜单的种类及开发步骤 在 indows窗口中,菜单有两种标准风格:下拉菜单和弹出菜单(也称上下文菜单) 口下拉菜单:一般在应用程序窗口的顶部罗列了 行按类别排列的菜单。如果用户选择了某 文伸q)编辑)查看(入①格式)帮助 类别,就会显示一个下拉式菜单。图5.1所示 弹出菜 即为下拉菜单 ① 口弹出菜单:一般在应用程序窗口区域的中间弹 弹出菜单 出显示,在应用程序工作区域上面处于自由浮 动状态。在写字板输入窗口中,单击鼠标右键, 即出现弹出式菜单,如图5.2所示 下拉菜单与弹出菜单只是在形式上不同,其消息 在这行前入一个攻目符号 及消息处理机制完全相同。 在程序开发中,简单的菜单编程一般可分为下面 图5.2弹出式菜单 个步骤 (1)编辑菜单资源,设置菜单属性(包括菜单名和ID) (2)用 Class wizard自动映射菜单消息和成员函数 (3)手工编辑成员函数,加入菜单消息处理代码 励志照亮人生编程改变命运
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 弹出式菜单 弹出菜单
第6章菜单、工具栏和状态栏 5.1.2菜单的创建与编辑 在 Visual C++6.0中,使用 MFC App Wizard生成的文档/视图结构的应用程序,系统已为框架创建了 个标准的主菜单,包括文件、编辑、视图和窗口帮助等标准菜单,定义了各菜单项的ID及相应的命 令处理函数。一般只需要通过菜单资源编辑器,在已有主菜单的基础上添加、设计需要的菜单项即可 下面结合一个具体的实例讲解菜单的创建与编辑。 1.创建SD项目 在 Visual c+6.0中,执行“File”→“New”菜单命令,在“ Project”选项卡中,创建一个MFC App Wizard[EXE]工程,工程名为“Ch6 Demol”。在 MFC App Wizard Step I的时候,选中“ Single document”,即基于单文档的MFC工程,其余的几步采用默认设置 在工作区窗口的 Resource view选项卡中,打开工程资源,选择“Menu”,会发现自动创建了 IDR MAINFRAME菜单资源,双击它,可打开菜单编辑器,如图5.3所示。 2.添加菜单项 在主菜单的最右边以及每个下拉菜单展开的最下边都有一个虚线框,该虚线框实际上就是菜单的“生长 点”。将光标移动到虚线框内,双击左键,就启动了菜单项的属性对话框,添加、设置菜单项的相关信息。本 例中,将在 IDR MAINFRAME菜单中添加一个“绘图”顶层菜单,其下设计两个菜单项:“圆形”和“矩形” (1)增加顶层菜单“绘图” 在主菜单右侧的虚线框内,双击左键,弹出菜单项属性对话框。在“ Caption”编辑框中输入菜单 名“绘图(&D)”,菜单名即显示在菜单上,如图54所示 文件①)编辑)查看帮助0抛图q) 文件吧)编)查看帮助 Ch6Dem。 I resources 2 Caption图p p Pop-up BreakBone Cb到Res回fh 图5.3 IDR MAINFRAME菜单资源 图54添加顶层菜单的属性对话框 表5.1菜单属性对话框中各选项及其含义 在菜单名中,可用【At】键加该字符作为选菜单属性项 说明择菜单的快捷方式。菜单“绘图(&D)”表示D 表示该菜单项的ID值 使用“At+D”作为该菜单的快捷键 表示该菜单项显示的文本 Separato 表示该菜单项是一条分隔线 此时,属性对话框中默认选中了“ Pop-up”选项, Checked表示该菜单项被选中显示一个标志 表示该项是一个顶层菜单,其本身不执行菜单命令 选择该菜单项显示一个子菜单 菜单属性对话框中各选项及其含义如表5.1所示。 Grayed 该菜单项变灰显示,被禁止 (2)添加、定义菜单项 nactive该菜单项不被激活 Help菜单,通常放在菜单的最右端 双击“绘图”菜单下的虚线框,即可打开菜单 选中该菜单项后就退出其所在菜单 属性对话框,添加菜单项。在 General页面上输入 Prompt 光标移至该菜单项状态栏显示的文本 励志照亮人生编程改变命运
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 光标移至该菜单项状态栏显示的文本
Visual c++ Caption菜单项名称及其ID值,在 Prompt:编辑框中的字符串是选择该菜单项时状态栏上显示的内容 别添加“圆形”和“矩形”两个菜单项,如图5.5所示。 如果要删除某个菜单项或弹出菜单,可用鼠标单击该菜单或用上下光标键选择,然后按【Del】 键删除。 文件吧)编①)查看Q帮助2图Q) General Extended r Separator r Popup r Inactive Break: None 厂 Checked厂 Grayed Prompt:在屏幕上绘制一个炬形 图5.5添加菜单项属性对话框 说明在菜单实际设计时,菜单的级数一般以2~3级为宜:若单击某菜单项会弹出一对话框,那么在 该菜单项文本后加上“…”。 此时编译、运行程序,则“绘图”菜单下的命令都是“灰色”的,即无法选择相应的菜单命令 这是因为还没有对菜单的命令消息进行映射。 513菜单消息 AFC程序可以处理两种菜单消息: WM COMMAND和 UPDATE COMMAND UI 口wM_ COMMAND:为菜单命令消息,当选择菜单项、工具栏按钮或加速键之一时会发出菜单 命令消息,MFC依据一定的消息传递途径将消息传递给相应的处理函数进行处理,如果在消息 传递途径的消息映射表中找不到相应的处理函数,该菜单项或按钮会被禁止使用 口 UPDATE COMMAND U:为菜单更新消息,处理菜单状态的动态变化。如希望根据程序的执行状 态,激活或禁用某些菜单项,设置选中标记,或更改菜单项文字等,就要定义这一消息处理函数 在某个菜单显示前,框架将发送菜单内所有菜单项的更新命令,有更新处理函数的菜单项,则调 用其处理函数更新菜单显示方式:没有更新处理函数的菜单项,查找其命令处理函数,若仍然没有, 则将菜单项禁用 在文档/视图结构的MFC应用程序框架中,在view类、Doc类、 MAinfRame类和App类中均可以 响应并处理菜单消息,菜单消息一旦在其中一个类中响应,则不再在其他类中查找响应函数。菜单消 息的传递顺序如图56所示 菜单消息 vew类 Doc类 MAin Frame类 App类 图56菜单消息的传递顺序 具体而言,当点击一个菜单项的时候,最先接受到菜单项消息的是 MAinframe框架类 励志照亮人生编程改变命运
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 菜单消息的传递顺序 具体而言,当点击一个菜单项的时候,最先接受到菜单项消息的是CMainFrame框架类, 90 励志照亮人生 编程改变命运 零基础学 Visual C++ 菜单消息 View类 Doc类 CMainFrame类 App类
第6章菜单、工具栏和状态栏 MAinframe框架类将会把菜单项消息交给它的子窗口view类,由View类首先进行处理:如果view类 到没对该菜单项消息做响应,则view类把菜单项消息交由文档类Doc类进行处理:如果Doc类检 测到Doc类中也没对该菜单项消息做响应,则Doc类又把该菜单项消息交还给view类,由Ⅴiew类再交 还给 MAin Frame类处理。如果 CMain frame类查看到 MAinframe类中也没对该消息做响应,则最终 交给App类进行处理 51.4菜单命令消息的处理 定义好菜单项及其ID后,就需要为菜单命令添加响应函数。实现方法是借助 Class wizard,在需 要响应菜单命令的类的消息映射表中增加一个入口,即定义一个命令消息 ON COMMAND宏。下面 就以为“圆形”菜单命令项添加 WM COMMAND消息处理函数为例,讲解处理菜单消息的实现过程 1.用 MFC ClassWizard自动映射菜单命令消息和成员函数 执行“view”→“ Class wizard”菜单命令项,或者使用【Ctrl+W】快捷键,打开“MFC Class wizard”对话框。在对话框的“ Message Map”选项卡中的“ Class Name”列表框中选择要响应 菜单命令的类“cCh6 Demol view”,在“ Object IDs”列表框中选择菜单ID“ID_ DRAWCIRCLE", 在“ Messages”列表框中选择“ COMMAND”菜单命令消息,如图5.7所示 Message Maps Member Variables I Automation ActiveX Events I Class Info I wCh6DemoIview.h, D: ChbDemo1lCh6DemoI view cp Add Function. Edit Code V OnEgin Printing crlption: Handle a command (from menu, accel, cmd button 图57“ MFC Class Wizard”对话框 然后单击“ Add function”按钮,弹出“ AddMember Function”对话框,可以修改函数名或接受默认函数名,如图「 Member function name 58所示。这里使用默认的函数名,单击“OK”按钮,关闭这|omm Cancel 个对话框 AWCIRCLE 此时,在CCh6 Demo l view类所在cpp文件的开始部分会 发现自动添加的消息映射代码 图58“ AddMember function”对话框 BEGIN MESSAGE MAP(cCh6Demolview, cview) //[(AEX MSG MAP (cCh6Demolview) 励志照亮人生编程改变命
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”菜单命令项,或者使用【Ctrl+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 Function”按钮,弹出“AddMember Function”对话框,可以修改函数名或接受默认函数名,如图 5.8所示。这里使用默认的函数名,单击“OK”按钮,关闭这 个对话框。 此时,在CCh6Demo1View类所在.cpp文件的开始部分会 发现自动添加的消息映射代码: BEGIN_MESSAGE_MAP(CCh6Demo1View, CView) //{{AFX_MSG_MAP(CCh6Demo1View) 91 励志照亮人生 编程改变命运 第 6 章 菜单、工具栏和状态栏编程 图5.8 “AddMember Function”对话框
Visual c++ ON COMMAND(ID DRAWCIRCLE, OnDrawcircle //消息映射 END MESSAGE MAP() 2.手工添加函数的实现代码 添加函数后,在“ MFC Class wizard”对话框中单击“ Edit code”按钮,就可以直接跳至新增函 数代码的定义处。这时,需要手工添加 OnDrawcircleo函数的实现代码,如下 void cch DemolView:: OnDrawcircle ( / TODO: Add your command handler code here CDC*pDC=GetDc ( //使用 GetA()函数申请cDc类的指针 CRect rect(100,0,300,200); CBrush brush(RGB (180,180,180)) //定义画刷 pDC->FillRect(rect, &brush) //填充绘图区域 pDc->E11ipse(160,10,260,110); //画圆 pDC-> Textout(120,120,"绘制直径为100个像素的圆" //在圆下方输出文字 ReleaseD (pDc); //释放CDC类的指针 同样的方法,使用 MFC Class wizard为“矩形”菜单项添加“ COMMAND”消息映射和处理函数」 代码如下: void cch6Demo lView:: OnDrawrect ( / TODO: Add your command handler code here CDC*pDC=GetDC ( //使用 GetA()函数申请cDc类的指针 Rect 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的正方形”) //在矩形下方输出文字 //释放CDc类的指针 此时,编译运行程序,就可以运行菜单命令,如图5.9所 交吧排)查)助)烤母0) 5.15菜单更新消息的处理 般情况下,菜单项具有不止一种状态,经常需要根据应 用的内部状态来对菜单项作相应的改变。例如,在没有选择任 余制直径为100个像案的园 何内容时,编辑菜单下的“复制”、“剪切”等菜单是无效的 (灰色显示)。有时还会看到在菜单项旁边可能还会有检查标 记,表示它是选中的还是不选中的。如在Word的视图菜单下, 在屏幕上绘制一个圆 根据用户所选的显示模式,在“普通”、“大纲”、“页面” 图59程序运行结果 “主控文档”前会出现一个点符号,标识当前所选的视图方式 菜单项的 UPDATE_ COMMAND_UI消息,就是专门用于处理菜单项的更新。可以为菜单项的 励志照亮人生编程改变命运
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 程序运行结果