第六章 菜单、工具栏和状态栏

75
1 返返 第第第 第第 第第第第第第第 返返返返 第第第第第第第第第第第第 第第第第第第第第第第第第第第第第第第第第第第 ,。 第第 CMenu 第第第第第第第第第第第第第第第第第 第第第第第第第第第第第第 第第第第第第第第第第第第第第第第第第第第第第第第第第第第第第 第第第第第第第第第第第第第第第第第第第 ,。 第第第第第第第第第第第第第第第第第第 CMenu 第CStatusBar 第CToolBar 第CCmdUI 第第第第第第第第第第第第第第第第 第第第第第第第第 Windows 第第第第第第第第第第第第第第第第第 第第第第第第第第第第第第第第

description

第六章 菜单、工具栏和状态栏. 本章导读 掌握菜单的创建步骤和方法,如何进行命令消息的映射和编写相应的程序代码。 掌握 CMenu 类及其常用成员函数的功能和使用方法,掌握利用这些成员函数创建快捷菜单和实现动态增加或减少菜单项。 掌握工具栏的创建方法和步骤,如何将工具栏的功能与菜单的功能相对应。 掌握创建状态栏的方法和步骤。 学习和掌握 CMenu 类、 CStatusBar 类、 CToolBar 类、 CCmdUI 类及常用成员函数的功能和使用。 菜单、工具栏和状态栏是 Windows 应用程序中最重要的三个用户界面元素,是应用程序设计中不可缺少的步骤。. - PowerPoint PPT Presentation

Transcript of 第六章 菜单、工具栏和状态栏

Page 1: 第六章 菜单、工具栏和状态栏

1返回返回

第六章 菜单、工具栏和状态栏 本章导读 掌握菜单的创建步骤和方法,如何进行命令消息的映

射和编写相应的程序代码。 掌握 CMenu 类及其常用成员函数的功能和使用方法,

掌握利用这些成员函数创建快捷菜单和实现动态增加或减少菜单项。 掌握工具栏的创建方法和步骤,如何将工具栏的功能

与菜单的功能相对应。 掌握创建状态栏的方法和步骤。 学习和掌握 CMenu 类、 CStatusBar 类、 CToolBar 类、

CCmdUI 类及常用成员函数的功能和使用。 菜单、工具栏和状态栏是 Windows 应用程序中最重要的三个用户界面元素,是应用程序设计中不可缺少的步骤。

Page 2: 第六章 菜单、工具栏和状态栏

2返回返回

6.1 创建菜单 菜单是一系列命令的列表,是最常用的命令输入方式。在 Windows 中,几乎所有的命令操作都与菜单有关。 Windows 应用程序中的菜单是按照一定层次来进行组织的,包括菜单项和弹出菜单,其中弹出菜单又可以包括菜单项和其他的弹出菜单。1. 创建菜单资源 菜单中的每一个菜单项都由菜单项名和命令 ID 号两个基本要素组成。在菜单资源中,每个菜单项都必须有一个唯一的命令 ID 号来对它进行标识,这个 ID 号是系统在对菜单项进行识别时使用的。对于用户而言,菜单项的标识是利用它所属的弹出菜单和菜单项的句子来标识的,比如 ID_FILE_OPEN ,其所属的弹出菜单是【文件】,菜单项名称为【打开】。

Page 3: 第六章 菜单、工具栏和状态栏

3返回返回

创建菜单可以有几种方法,最简单的方法是用菜单资源编辑器进行设计。在这里,我们把第五章关于模式对话框的例子进行改造,使对话框的弹出方式由在窗口中双击鼠标改为由单击某个菜单命令实现。具体步骤如下:步骤一:在 Visual C++ 6.0 中,选【 File 】菜单中的【 Open Workspace 】菜单项,打开已创建的“ Dialog.dsw” 文件。步骤二:在工作区窗口中选择【 Resource View 】选项卡,展开【 Dialog Resources 】目录,再展开【 Menu 】文件 ,将会看到菜单 IDR_MAINFRAME 。 步骤三:双击 IDR_MAINFRAME ,将在菜单资源编辑器中打开菜单资源。步骤四:在主菜单中增加一个【显示】菜单。用鼠标双击主菜单最右边的空菜单项,或者用鼠标右击,在弹出的快捷菜单中选择【 Properties 】菜单项。系统将弹出属性对话框。

Page 4: 第六章 菜单、工具栏和状态栏

4返回返回

在【 Caption 】栏中输入“显示( &P )”,括号中的 &P 表示紧跟在它后面的字母“ P” 是助记符,这样,在程序运行过程中,就可以用 Alt+P 键来激活【显示】菜单。按【 Enter 】键继续。 这时,在主菜单中将增加一个“显示”菜单,在助记符 P 下面有下划线。同时,在生成的菜单的右面和下面各出现一个新的菜单或菜单项,可以继续添加新的菜单或菜单项。步骤五:在【显示】菜单中增加一个【个人资料】菜单项。用鼠标右键单击【显示】菜单中的空菜单项,在弹出菜单中选择【 Properties 】选项。单击属性对话框左上角的“图钉”按钮,把对话框“钉”在屏幕上。在属性对话框的【 Caption 】栏中输入“个人资料( &D )” 。

Page 5: 第六章 菜单、工具栏和状态栏

5返回返回

对于【个人资料】菜单项, Visual C++ 6.0 将为该菜单项自动分配一个 ID 号。单击其他菜单项或者屏幕的其他部分,再选中【个人资料】菜单项,系统在【 ID 】栏中显示出为该菜单项分配的 ID 号,其一般格式为 MENUITEMxxxxx(xxxxx 代表一个整数 ) 。【 Prompt 】框中的文本是光标处于菜单项时,状态栏显示的帮助信息在菜单项属性对话框的【 General 】选项卡中,各选项的含义如下图所示。步骤六:用鼠标左键按住【显示】菜单,将其拖到【编辑】与【帮助】菜单中间。 这样,利用菜单资源编辑器,我们就很轻松地创建了一个标准的 Windows 菜单。

Page 6: 第六章 菜单、工具栏和状态栏

6返回返回

项目 含义ID

Caption

Separator

Checked

Pop_up

Grayed

Inactive

Help

Break

Prompt

菜单的资源 ID号菜单项的标题文本,当其中某一字母的前面含有 & 符号时,则该字母与 Alt 键构成组合键选中时,则相应的菜单项是一个分隔符或一条水平线选中时,则相应的菜单项前显示一个选中标记“√”选中时,表示该菜单项含有弹出式子菜单选中时,表示该菜单项呈灰色显示,该菜单项被禁用选中时,表示该菜单项没有被激活,用户不能选用选中时,表示该菜单项在程序运行时被放于顶层菜单的最右端其默认值为 None ,表示菜单项按常规形式显示。该项的取值还可为 Column 或 Bar , 指明当光标移到该菜单项时在状态栏上显示的提示

表 6.1 菜单 General属性对话框的各项含义

Page 7: 第六章 菜单、工具栏和状态栏

7返回返回

2. 建立快捷键 在 Windows 应用程序中的某些菜单项后面有一个组合键,表示一个快捷键( shortcut key ),在程序运行过程中,如果用户按下了该组合键,则相应的菜单命令就会被执行。当然,若要使用快捷键选择某个菜单项,就必须事先对其作出定义。现在我们来为刚才创建的菜单添加快捷键,具体步骤如下:步骤一:在工作区窗口的【 Resource View 】选项卡中,双击【 Accelerator 】文件夹,双击 IDR_MAINFRAME ,则系统会弹出一个加速器表 。步骤二:在加速器表中浏览一下,发现 Ctrl+D 还没有被使用,我们就把 Ctrl+D 设置为菜单项【个人资料】的快捷键。方法是双击加速器表末尾的空行,将弹出快捷键的属性对话框( Accel Properties )。

Page 8: 第六章 菜单、工具栏和状态栏

8返回返回

在属性对话框( Accel Properties )中,各项的含义如表 6.2所示。 表 6.2 Accel Properties 对话框中各选项的含义

选项 含义 ID

Modifiers

Type

KeyNext Key Typed

为了能使设定的快捷键与某个菜单项的功能相对应,从中选择所需的菜单资源 ID号用来选择 Ctrl 、 Alt 、 Shift 键是否为快捷键的组成键用来确定快捷键的值是虚拟键 (VirKey)还是 ASCII是指启动快捷键的键盘按键单击此按钮时,用户所按的任何按键将成为快捷键的键值

Page 9: 第六章 菜单、工具栏和状态栏

9返回返回

步骤三:在对话框中的【 ID 】下拉列表中选择【 ID_DISPLAY_DATA 】选项,当选中 ID 号时,【 ID 】框中同时显示出此 ID 号对应的整数,如 ID_DISPLAY_DATA=32771 。步骤四:在【 Key 】列表框中输入“ D” ,确认【 Modifiers 】栏中的【 Ctrl 】复选框被选中,而且【 Alt 】和【 Shift 】都未被选中;或者,直接单击【 Next Key Typed 】按钮,按下 Ctrl+D 组合键放开,此时系统会自动记录所按下的 Ctrl+D 键为所要设定的组合键。按【 Enter 】键继续。步骤五:为了在【显示】菜单中提示【个人资料】菜单项的快捷键,可以返回 6.1.1 节中的步骤五,将【 Caption 】框中的内容修改为“个人资料 (D)\tCtrl+D” 。这样,我们就建立了一个完整的菜单资源。

Page 10: 第六章 菜单、工具栏和状态栏

10返回返回

3 菜单功能的实现 在 MFC 框架中,菜单命令消息是按照一定的顺序进行传递的。对于一个单文档应用程序,消息传递的顺序为:视图类→文档类→框架类→应用程序类。因此,如果我们在视图类和文档类中同时定义了某个菜单项的消息映射接口时,由于消息首先传递给视图类,在视图类中对此消息做出了响应,所以,文档类中定义的此菜单项的消息映射函数就无法执行。 在菜单资源中,我们定义了 MFC 如何来构造菜单的结构,同时还指定了菜单的资源 ID 号, MFC 通过 ClassWizard 会自动把菜单和相应的框架窗口联系在一起。但除了由系统产生的少量代码外, MFC 不能自动地对程序的菜单项进行响应,必须用手工实现。

Page 11: 第六章 菜单、工具栏和状态栏

11返回返回

对于每个菜单项,系统提供了 COMMAND 和UPDATE_COMMAND_UI 两种消息可供选择:( 1 ) COMMAND 消息需要用户的干预,如单击、双击等操作;( 2 ) UPDATE_COMMAND_UI 消息系统会自动进行响应,通过它可以实现对菜单项外观的动态管理。例如,设计人员可以使菜单有效、无效或给菜单项动态添加检查标记等。 可以利用 ClassWizard 同时设置这两种消息,但是在实际编程中,必须为每个菜单项提供有关 WM_COMMAND 类型消息映射接口。 下面,我们在视图类中对前面已建立的“个人资料( &D )”菜单项的消息做出响应。具体步骤如下:

Page 12: 第六章 菜单、工具栏和状态栏

12返回返回

步骤一:选择【 View 】菜单中的【 ClassWizard 】菜单项,弹出【 MFC ClassWizard 】对话框。步骤二:在【 MFC ClassWizard 】对话框中,选择【 Message Maps 】选项卡。在【 Class name 】下拉列表框中,选择类 CDialogView ;在 【 Object Ids 】中单击选择 ID_DISPLAY_DATA 选项;在 【 Messages 】 栏中将出现 COMMAND 和 UPDATE_COMMAND_UI 两个选项,选中其中的 COMMAND 。步骤三:单击对话框右侧的【 Add Function 】 按钮,系统将会弹出【 Add Member function 】对话框。系统将自动生成一个缺省名称为 OnDisplayData 的映射函数亦可另取别的名称,在此取缺省名称,单击【 OK 】按钮继续。步骤四:单击【 Edit Code 】按钮退出【 MFC ClassWizard 】 对话框,并编辑新增加的函数 OnDisplayData 。

Page 13: 第六章 菜单、工具栏和状态栏

13返回返回

经过以上操作完成后, Visual C++ 会对程序中的一些程序文件的代码进行必要的修改,其中粗体部分的代码是由 ClassWizard 自动添加的代码。1. 在 CDialogView 类的定义文件 DialogView.h 中的消息映射部分将会改变为:// Generated message map functions

protected:

//{{AFX_MSG(CDialogView)afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);

afx_msg void OnDisplayData(); //ClassWizard 自动添加的//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

Page 14: 第六章 菜单、工具栏和状态栏

14返回返回

其中://{{AFX_MSG(CDialogView)

……

//}}AFX_MSG

是 ClassWizard 分别用来识别命令消息处理函数定义的起始标记和结束标记,在 AFX_MSG(CDialogView) 后面括号内的 CDialogView 表示是处理该消息的类。2. 在 CDialogView 类的实现文件 DialogView.cpp 中的消息映射部分也进行了一些修改:BEGIN_MESSAGE_MAP(CDialogView, CView)

//{{AFX_MSG_MAP(CDialogView)

Page 15: 第六章 菜单、工具栏和状态栏

15返回返回

ON_WM_LBUTTONDBLCLK()

ON_COMMAND(ID_DISPLAY_DATA,

OnDisplayData) //ClassWizard 自动添加的//}}AFX_MSG_MAP

END_MESSAGE_MAP()

其中://{{AFX_MSG_MAP(CDialogView)

……

//}}AFX_MSG_MAP

是 ClassWizard 标识命令消息处理映射机制的起始标记和结束标记。

Page 16: 第六章 菜单、工具栏和状态栏

16返回返回

3. 在 DialogView.cpp 文件中编写 OnDisplayData 函数的代码。 把 DialogView.cpp 文件中响应双击窗口的函数 OnLButtonDBLCLK() 的代码复制到 OnDisplayData() 函数中,具体代码如下:void CDialogView::OnDisplayData() {// TODO: Add your command handler code hereCMydataDialog dlg;dlg.m_radio_m=0;dlg.m_edit_name="";CString msg;if(dlg.DoModal()==IDOK){msg="< 确定 > 按钮被按下! "; }Else {msg="< 取消 > 按钮被按下! ";}

Page 17: 第六章 菜单、工具栏和状态栏

17返回返回

msg+="\r\n";msg+=" 姓名: ";msg+=dlg.m_edit_name;msg+="\r\n";msg+=" 性别: ";switch(dlg.m_radio_m){case 0:msg+=" 男 "; break;case 1:msg+=" 女 "; break; }msg+="\r\n";msg+=" 最高学历: ";msg+=dlg.m_combo_school;msg+="\r\n";msg+=" 爱好: ";

Page 18: 第六章 菜单、工具栏和状态栏

18返回返回

if(dlg.m_check_art==TRUE)

msg+=" 艺术 ";

if(dlg.m_check_music==TRUE)

msg+=" 音乐 ";

if(dlg.m_check_sport==TRUE)

msg+=" 体育 ";

AfxMessageBox(msg);

}

步骤五:编译运行并测试此应用程序。当选择【显示】菜单中的【个人资料】菜单项,或单击 Ctrl+D 键时,将弹出【个人资料】对话框,在对话框内可以进行各种设置,然后单击【确认】或【取消】按钮退出。可以看到其效果与双击应用程序窗口是一样的。

Page 19: 第六章 菜单、工具栏和状态栏

19返回返回

4. CMenu 类及其常用成员函数介绍 Visual C++ 的 MFC 提供的菜单类 Cmenu 的对象可以用来表示各种 Windows 菜单,其中包括顶层菜单项及其相应的弹出式菜单。并且该类可以在程序运行时处理有关菜单的操作,如创建菜单、装入菜单、删除菜单项、获取或设置菜单项的状态等。创建菜单 CMenu 类的成员函数 CreateMenu 和 CreatePopupMenu 分别用来创建一个菜单或子菜单框架,其函数原型如下:BOOL CreateMenu(); // 产生一个空菜单BOOL CreatePopupMenu(); // 产生一个空弹出式子菜单

Page 20: 第六章 菜单、工具栏和状态栏

20返回返回

装入菜单 CMenu 类的成员函数 LoadMenu 可用来将菜单资源装入应用程序中,它的函数原型有两种,如下所示:BOOL LoadMenu(LPCTSTR lpszResourceName);

BOOL LoadMenu(UNIT nIDResource);

其中:形参 lpszResourceName 表示菜单资源的名称,形参 nIDResource 为菜单资源的 ID 号。添加菜单项当菜单创建后,可以调用 CMenu 类提供的成员函数 AppendMenu 或 InsertMenu 来向菜单中添加一些菜单项,但每次添加时,函数 AppendMenu 是将菜单项添加在菜单的末尾处,而 InsertMenu 是在指定的位置处插入菜单项,并将后面的菜单项依次下移。它们的函数原型如下:

Page 21: 第六章 菜单、工具栏和状态栏

21返回返回

BOOL AppendMenu(UNIT nFlags, UNIT nIDNewItem,const CBitmap * pBmp);

BOOL AppendMenu(UNIT nFlags, UNIT nIDNewItem=0,LPCTSTR lpszNewItem=NULL);

BOOL InsertMenu(UNIT nPosition, UNIT nFlags, UNIT nIDNewItem,const CBitmap *pBmp);

BOOL InsertMenu(UNIT nPosition, UNIT nFlags, UNIT nIDNewItem=0,LPCTSTR lpszNewItem=NULL);

其中:形参 nIDNewItem 表示新增菜单项的资源 ID 号,形参 lpszNewItem 表示新增菜单项的标题内容,形参 pBmp 是新增菜单项的位图指针,形参 nPosition 表示新增菜单项要插入的菜单项的位置, nFlags 表示要增加的菜单项的状态信息,其取值的不同会影响其他参数的含义,见表 6.3 。

Page 22: 第六章 菜单、工具栏和状态栏

22返回返回

nFlags 的取值 含义 nPosition值

nIDNewItem 值 lpszNewItem 值

MF_BYCOMMAND

 

MF_BYPOSITION 

MF_POPUP

MF_SEPARATOR

MF_OWNERDRAW

MF_STRING

MF_CHECKED

 

MF_UNCHECKED 

MF_DISABLED

MF_ENABLED

MF_GRAYED

菜单项以 ID号来标识菜单项以位置来标识菜单项有弹出式子菜单分隔线自画菜单项字符串标志设置菜单项的选中标记取消菜单项的选中标记禁用菜单项菜单项可用菜单项变灰

菜单项资源 ID

菜单项的位置

 

 

  

弹出式菜单句柄忽略

  

 

 

 

忽略自画所需的数据字符串指针

Page 23: 第六章 菜单、工具栏和状态栏

23返回返回

注意:( 1 )当形参 nFlags 为 MF_BYPOSITION 时, nPosition表示新菜单项要插入的位置,该位置为 0 时表示新菜单项插入到第一个菜单项,为 1 时表示新菜单项插入到第二个菜单项,……,当为 -1 时,表示新菜单项插入到菜单的末尾( 2 )在形参 nFlags 中,可以用按位或运算符“ |” 将某些取值组合起来,如: MF_CHECKED|MF_STRING 等。但有些组合是不允许的,如: MF_DISABLED 、 MF_ENABLED 和 MF_GRAYED 等。( 3 )当利用以上函数向菜单中新增菜单后,不管菜单所在的窗口是否改变,都应调用 CWnd 类的成员函数 CWnd::DrawMenuBar 来更新菜单,函数 DrawMenuBar 的原型为:void DrawMenuBar();

Page 24: 第六章 菜单、工具栏和状态栏

24返回返回

删除菜单项 当要删除指定的菜单项时,可利用 CMenu 类的成员函数 DeleteMenu 来完成,该函数的原型为:BOOL DeleteMenu(UNIT nPosition,UNIT nFlags);

其中:形参 nPosition 的值表示要删除的菜单项的位置,其值的选取要受到形参 nFlags 的取值的影响。当 nFlags 的取值为 MF_BYCOMMAND 时, nPosition 表示要删除的菜单项的 ID 号,而当 nFlags 的取值为 MF_BYPOSITION 时, nPosition 表示要删除的菜单项的位置(第一个菜单项的位置为 0 ,第二个菜单项的位置为 1 ,……)。注意: 当调用 DeleteMenu 函数删除某个菜单项后,不管菜单所依附的窗口是否改变,也必须调用 CWnd 类的成员函数 CWnd::DrawMenuBar 来更新菜单。

Page 25: 第六章 菜单、工具栏和状态栏

25返回返回

获取菜单项 可以利用 CMenu 类的以下三个成员函数分别获得菜单的项数、菜单项的 ID 号以及弹出式子菜单的句柄。( 1 ) GetMenuItemCount 函数该函数的原型为:UNIT GetMenuItemCount() const; 该函数的功能是取得菜单中的菜单项数,如果调用失败则返回值为 -1 。( 2 ) GetMenuItemID 函数该函数的原型是:UNIT GetMenuItemID(int nPos) const; 该函数的功能是返回由参数 nPos 所指定的菜单项位置的菜单项的 ID 号,若 nPos 所指定的位置处为分隔线,则该函数的返回值为 -1 。

Page 26: 第六章 菜单、工具栏和状态栏

26返回返回

( 3 ) GetSubMenu 函数该函数的原型为:CMenu *GetSubMenu(int nPos) const;

该函数的功能是获得指定菜单的弹出式菜单的菜单句柄。该弹出式菜单位置由参数 nPos 给定,开始的位置为 0 ,若菜单不存在,则创建一个临时的菜单指针。 此外,在主框架 CMainFrame 类中,可以利用该类的成员函数 CMainFrame::GetMenu 来获得主菜单句柄。该函数的原型为:CMenu *GetMenu();

Page 27: 第六章 菜单、工具栏和状态栏

27返回返回

5. 快捷菜单的实现 利用 MFC 提供的 CMenu 类的 TrackPopupMenu 成员函数可以用来显示一个弹出式菜单,该函数的原型为: BOOL TrackPopupMenu(UNIT nFlags,int x,int y,CWnd *pWnd,LPCRECT lpRect=0); 其中:( 1 )形参 nFlags 表示菜单在屏幕上显示的位置以及鼠标的按钮状态,具体见表 6.4 所示。其中前三个值可分别与后两个值用“ |” 运算符进行组合。

nFlags 的值 含义及作用TPM_CENTERALIGNTPM_LEFTALIGNTPM_RIGHTALIGNTPM_LEFTBUTTONTPM_RIGHTBUTTON

决定菜单的屏幕位置,水平中心位置由 x 坐标确定决定菜单的屏幕位置,菜单的左边位置由 x 坐标确定决定菜单的屏幕位置,菜单的右边位置由 x 坐标确定鼠标按钮标志,当用户单击左键时弹出快捷菜单鼠标按钮标志,当用户单击右键时弹出快捷菜单

Page 28: 第六章 菜单、工具栏和状态栏

28返回返回

( 2 )形参 x 和 y 表示菜单的水平坐标和菜单的顶端的垂直坐标。( 3 ) pWnd 表示弹出菜单的窗口,此窗口将收到菜单全部的 WM_COMMAND 消息。( 4 ) lpRect 是一个 RECT 结构或 CRect 类的对象指针,它表示一个矩形区域,用户单击这个区域时,弹出菜单不消失,而当 lpRect 为 NULL 时,则当用户单击菜单外面时,菜单会立刻消失。 下面,我们在上例的基础上,添加一个快捷菜单,并使其能够完成与与双击应用程序窗口或选择【显示】菜单中的【个人资料】菜单项一样的功能。具体步骤如下:步骤一:在 Visual C++ 6.0 中,选择【 File 】菜单中的【 Open Workspace 】菜单项,打开上例中的“ Dialog.dsw”

Page 29: 第六章 菜单、工具栏和状态栏

29返回返回

步骤二:添加一个新的菜单资源。选择【 Insert 】菜单中的【 Resource 】菜单项,或直接按 Ctrl+R 键,在打开的【 Insert Resource 】对话框窗口中选择【 Menu 】,单击【 New 】按钮。步骤三:在工作区窗口中选择【 Resource View 】选项卡,展开【 Dialog Resources 】目录,再展开【 Menu 】文件夹,将会看到菜单 IDR_MENU1 (这是系统给该菜单资源的缺省 ID 号)。双击 IDR_ MENU1 ,将在菜单资源编辑器中打开菜单资源。用鼠标双击主菜单最右边的空菜单项,或者用鼠标右键单击它,在弹出的快捷菜单中选择【 Properties 】菜单项。在出现的“ Menu Item Properties” 对话框中的【 Caption 】栏中任意输入一个标题,最后按回车键退出该对话框。

Page 30: 第六章 菜单、工具栏和状态栏

30返回返回

步骤四:在快捷菜单中增加菜单项。在菜单资源编辑器中用鼠标右键单击【显示】菜单中的空菜单项,在出现的快捷菜单中选择【 Properties 】选项。在出现的“ Menu Item Properties” 属性对话框的【 Caption 】栏中输入“个人资料( &D )”, ID 号输入“ ID_MENU1_DATA” ,按回车键关闭“ Menu Item Properties” 对话框。以同样方法再增加一个【其他】菜单项,标题为“其他( &O )”, ID 号为“ __” 。步骤五:选择【 View 】菜单中的【 ClassWizard 】菜单项,将出现一对话框,询问是“创建一个新类 (Create a new class)” ,还是“选择一个已存在的类( Select an existing class )”,在此选择“选择一个已存在的类( Select an existing class )”,则系统又弹出“ Select Class” 对话框,在该对话框中,单击选择“ CDialogView” ,单击【 Select 】按钮,系统进入【 MFC ClassWizard 】对话框。

Page 31: 第六章 菜单、工具栏和状态栏

31返回返回

步骤六:在【 MFC ClassWizard 】对话框中,选择【 Message Maps 】选项卡。在【 Class name 】下拉列表框中,选择类 CDialogView ;在 【 Object Ids 】中选择 ID_MENU1_DATA 选项;在 【 Messages 】 栏中选择 COMMAND 。步骤七:单击对话框右侧的【 Add Function 】 按钮,系统将会弹出【 Add Member function 】对话框。系统将自动生成一个缺省名称为 OnMenu1Data 的映射函数,在此保留此默认名称,单击【 OK 】按钮继续。步骤八:单击【 Edit Code 】按钮退出【 MFC ClassWizard 】 对话框,并编辑新增加的函数 OnMenu1Data 。把 OnDisplayData() 函数中的代码复制到 OnMenu1Data() 中,具体代码如下,其中粗体字为新添加的代码:

Page 32: 第六章 菜单、工具栏和状态栏

32返回返回

void CDialogView::OnMenu1Data()

{

// TODO: Add your command handler code here

CMydataDialog dlg;

dlg.m_radio_m=0;

dlg.m_edit_name="";

CString msg;

if(dlg.DoModal()==IDOK)

{msg="< 确定 > 按钮被按下! ";}

else

{msg="< 取消 > 按钮被按下! "; }

Page 33: 第六章 菜单、工具栏和状态栏

33返回返回

msg+="\r\n\n";

msg+=" 姓 名: ";

msg+=dlg.m_edit_name;

msg+="\r\n";

msg+=" 性 别: ";

switch(dlg.m_radio_m)

{case 0:msg+=" 男 ";

break;

case 1:msg+=" 女 ";

break; }

msg+="\r\n";

msg+=" 最高学历: ";

msg+=dlg.m_combo_school;

msg+="\r\n";

msg+=" 爱 好: ";

Page 34: 第六章 菜单、工具栏和状态栏

34返回返回

if(dlg.m_check_art==TRUE)msg+=" 艺术 ";

if(dlg.m_check_music==TRUE)msg+=" 音乐 ";

if(dlg.m_check_sport==TRUE)msg+=" 体育 ";

AfxMessageBox(msg);}步骤九:选择【 View 】菜单中的【 ClassWizard 】菜单项 . 在出现的【 MFC ClassWizard 】对话框中,选择【 Message Maps 】选项卡。在【 Class name 】下拉列表框中,选择类 CMainFrame ;在 【 Object Ids 】中选择 CMainFrame 选项;在 【 Messages 】 栏中选择 WM_CONTEXTMENU 。单击对话框右侧的【 Add Function 】

Page 35: 第六章 菜单、工具栏和状态栏

35返回返回

按钮,系统将会弹出【 Add Member function 】对话框。系统将自动生成一个缺省名称为 OnContextMenu 的映射函数,单击【 OK 】按钮。单击【 Edit Code 】按钮退出【 MFC ClassWizard 】 对话框,并对 OnContextMenu 函数进行如下编辑:void CMainFrame::OnContextMenu(CWnd* pWnd, CPoint point) {// TODO: Add your message handler code hereCMenu menu;menu.LoadMenu(IDR_MENU1);menu.GetSubMenu(0)->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,this);}

Page 36: 第六章 菜单、工具栏和状态栏

36返回返回

步骤十:编译运行并测试此应用程序。当在应用程序窗口中,单击鼠标右键时,会弹出快捷菜单,选择其中的【个人资料】菜单项,则弹出【个人资料】对话框。在对话框内可以进行各种设置,然后单击【确认】或【取消】按钮退出。可以看到其效果与双击应用程序窗口或选择【显示】菜单中的【个人资料】菜单项是一样的。 6. 动态向菜单中添加新的菜单项下面,我们在上例的基础上,向程序中动态增加一个新的菜单项,具体步骤如下:步骤一:在 Visual C++ 6.0 中,选择【 File 】菜单中的【 Open Workspace 】菜单项,打开上例中的【 Dialog.dsw 】文件。步骤二:选择【 View 】菜单中的【 Resource Symbols 】菜单项,则会出现【 Resource View 】对话框。

Page 37: 第六章 菜单、工具栏和状态栏

37返回返回

步骤三:单击对话框中【 New… 】按钮,则出现 “ New Symbol” 对话框。在该对话框中的 Name 文本框中,输入一个用于菜单项的 ID 号,如:在本例中输入“ ID_NEW_MENUITEM” 。在 Value 文本框中输入对在该 ID 号的 ID 值,系统缺省为 101 ,用户也可以自行修改成新值,新值必须处在 15~61440 之间。在此取系统默认值,单击【 OK 】按钮。步骤四:利用 Visual C++ 的工作区窗口,打开 CMainFrame 类的实现文件 MainFrm.cpp 文件,在 CMainFrame::OnCreate 函数体中添加如下代码:int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{// 前一部分在此省略

Page 38: 第六章 菜单、工具栏和状态栏

38返回返回

CMenu *pMainMenu=GetMenu();

CMenu *pSubMenu=pMainMenu->GetSubMenu (4);

CString StrOfNewMenuItem(" 新建菜单项 ");

pSubMenu->AppendMenu (MF_SEPARATOR);

pSubMenu->AppendMenu (MF_STRING,ID_NEW_MENUITEM,StrOfNewMenuItem);

m_bAutoMenuEnable=FALSE;

pMainMenu->EnableMenuItem (ID_NEW_MENUITEM,MF_BYCOMMAND|MF_ENABLED);

DrawMenuBar();

return 0;

}

Page 39: 第六章 菜单、工具栏和状态栏

39返回返回

步骤五:选择【 View 】菜单中的【 ClassWizard 】菜单项,在出现的【 MFC ClassWizard 】对话框中,选择【 Message Maps 】选项卡。在【 Class name 】下拉列表框中,选择类CMainFrame ;在 【 Object Ids 】中选择 CMainFrame 选项;在 【 Messages 】 栏中选择 OnCommand 。单击对话框右侧的【 Edit Code 】 按钮,系统将会进入 CMainFrame::OnCommand 编辑窗口,输入以下黑体部分代码:BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) {// TODO: Add your specialized code here and/or call the base classif (LOWORD(wParam)==ID_NEW_MENUITEM) MessageBox(" 您选中了新的菜单项 ");return CFrameWnd::OnCommand(wParam, lParam); }此步中完成了对新增菜单项的消息映射功能。步骤六:编译运行并测试此应用程序。

Page 40: 第六章 菜单、工具栏和状态栏

40返回返回

6.2 创建工具栏 工具栏是一系列工具按钮的组合,也是一种常用的命令输入方式。可以说,工具栏是菜单的一种快捷方式。1 . 创建工具栏的方法和步骤创建工具栏资源 在这里,我们将对上一节的例子进行扩充,增加一个工具栏。当用鼠标选择工具栏上的某个按钮时,显示出【个人资料】对话框。具体步骤如下:步骤一:打开上一节创建的 Dialog 例子。步骤二:在工作区窗口中选择【 Resource View 】选项卡,展开【 Dialog Resources 】文件夹,由于我们在用 AppWizard 生成应用程序时,没有选择生成工具栏,因此在【 Dialog Resources 】文件夹中,找不到 Toolbar 文件夹。

Page 41: 第六章 菜单、工具栏和状态栏

41返回返回

步骤三:选择【 Insert 】菜单中的【 Resource 】菜单项,在弹出菜单中选择【 Insert 】菜单项。系统将弹出【 Insert Resource 】对话框,在对话框中选择【 Toolbar 】,单击【 New 】按钮。步骤四:系统将自动在【 Dialog Resounrces 】文件夹中添加一个【 Toolbar 】文件夹,同时在【 Toolbar 】文件夹中添加了一个名为 IDR_TOOLBAR1 的文件。屏幕上同时显示工具栏设计窗口。步骤四:鼠标右键单击【 Resource View 】中【 Toolbar 】文件夹中的 IDR_TOOLBAR1 项目。在弹出菜单中选择【 Properties 】菜单项,系统将弹出工具栏属性对话框。在属性对话框中的【 ID 】框中,我们把 ID 号修改为 IDR_MYTOOLBAR 。

Page 42: 第六章 菜单、工具栏和状态栏

42返回返回

步骤五:添加按钮和制作按钮图标。我们可以利用【 Graphic 】和【 Color 】工具栏上提供的设计工具,根据自己需要制作按钮图标。我们用字母 R 作为按钮的图标。 工具栏按钮的绘制是一个个分开进行的,在画完一个按钮后,该按钮的实际效果立刻显示出来。 在【 Toolbar Button Properties 】工具栏按钮属性对话框中,各项的含义如表 6.5 所示。项目 含义

IDWidthHeightPrompt

用于输入或从下拉列表中选择工具栏按钮的 ID 号用于输入工具栏按钮的宽度,单位是像素用于输入工具栏按钮的高度,单位是像素工具栏按钮文本

Page 43: 第六章 菜单、工具栏和状态栏

43返回返回

注:要使选择工具栏按钮的功能与选择菜单的功能一致时,应将工具栏按钮属性对象框中的 ID 号设置为与某一菜单项的 ID 号相同。 值得一提的是,在创建工具栏按钮的过程中,可以进行有关的操作及方法:( 1 )创建新的工具栏按钮在新建一个工具栏的过程中,在工具栏的右端会有一个空按钮,用鼠标单击该按钮,则该按钮的周围有虚的方框包围,同时在编辑区内显示出该按钮,用户可以在其中绘制图形。( 2 )移动工具栏中的按钮在编辑工具栏的过程中,可以根据用户的需要移动工具栏中的按钮,将某个按钮放置到所需要的位置上。

Page 44: 第六章 菜单、工具栏和状态栏

44返回返回

( 3 )复制工具栏中的按钮在工具栏编辑窗口内,选择待移动的工具栏按钮,在按下 Ctrl 键的同时,将其拖动到所需要的位置。( 4 )删除工具栏中的按钮方法是用鼠标拖动该按钮到工具栏以外的位置。( 5 )在工具栏中的按钮间插入空格 可以根据需要在某个按钮的左边、右边或两边插入一个空格分隔符,方法是:① 如果某按钮左边没有任何空格,拖动该按钮向右移动并当按钮的右边界接触到右边按钮时,释放鼠标键,则可以此按钮的左边插入一个空格,反之,亦然。② 如果某按钮的左边已有空格而右边没有空格,拖动该按钮向左移动并当按钮的左边界接触到左边按钮时,释放鼠标键,则可在此按钮右边插入一个空格。

Page 45: 第六章 菜单、工具栏和状态栏

45返回返回

③如果某按钮的左右两边都有空格,拖动该按钮向右移动并接触到相邻按钮时,则此按钮左边的空格保留,按钮右边的空格消失。反之亦然。 实现工具栏 编码实现工具栏。具体实现步骤如下:步骤一:在工作区中窗口中选中【 Class View 】选项卡,用鼠标右键单击【 CmainFrame 】 , 在弹出的菜单中选择【 Add Member Variable 】菜单项,系统将弹出【 Add Member Variable 】对话框。步骤二:在【 Variable Type 】栏中输入类型名称 CToolBar ,在【 Variable Name 】栏中输入变量名称 m_MyDataToolBar 。单击【 OK 】按钮继续。 此时, Visual C++ 将自动在主框架中的类定义文件MainFrm.h 中添加以下声名: CToolBar m_MyDataToolBar;

Page 46: 第六章 菜单、工具栏和状态栏

46返回返回

步骤三:选择【 View 】菜单中的【 ClassWizard 】菜单项,或者直接按 Ctrl+R 键,弹出【 MFC ClassWizard 】对话框。在【 Class name 】列表框选择 CmainFrame 类;在【 Object Ids 】列表框中选中 CMainFrame ;双击【 Messages 】列表栏中的 WM_CREATE 选项,或者选中 WM_CREATE ,再单击【 Add Function 】按钮。在【 Member Function 】栏中将会出现 OnCreate() 函数。步骤四:单击【 Edit Code 】按钮, ClassWizard 将自动在框架类的实现文件 MainFrm.cpp 中添加成员函数 OnCreate() 。在函数中加入显示工具栏的代码。具体代码如下,其中粗体部分为新添加的代码。

Page 47: 第六章 菜单、工具栏和状态栏

47返回返回

Int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

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

return -1;

// TODO: Add your specialized creation code here

if (!m_MyDataToolBar.Create(this)||

!m_MyDataToolBar.LoadToolBar(IDR_MYTOOLBAR))

{ TRACE0("Failed to created toolbar\n");

return -1;

}

return 0;

}

Page 48: 第六章 菜单、工具栏和状态栏

48返回返回

步骤五:编译并运行该程序。当单击工具栏上的新建按钮 ,窗口中将弹出【个人资料】对话框。此按钮的作用和选择【显示】菜单中的【个人资料】菜单项的效果是一样的。说明:( 1 )在上例创建工具栏的过程中,曾用到了 CToolBar类的对象, CToolBar 类是由 CControlBar 类派生而来的,它用于描述工具栏。其中, Create 函数是其成员函数,该函数的原型为:BOOL Create(Cwnd *pParentWnd, DWORD wStyle=WS_CHILD|WS_VISIBLE|CBRS_TOP, UNIT nID=AFX_IDW_TOOLBAR);其中:参数 pParentWnd 是指向父窗口的指针, dwStyle是工具栏的风格, nID 是子窗口的 ID 号。

Page 49: 第六章 菜单、工具栏和状态栏

49返回返回

取值 风格CBRS_TOP

CBRS_BOTTOM

CBRS_NOALIGN

CBRS_TOOLTIPS

CBRS_SIZE_DYNAMIC

CBRS_SIZE_FIXED

CBRS_FLOATING

CBRS_FLYBY

CBRS_HIDE_INPLACE

在框架窗口的顶部在框架窗口的底部不随父窗口改变尺寸显示按钮提示尺寸可改变控件条固定浮动状态状态栏中显示按钮的信息不显示工具栏

表 6.6 工具栏的部分风格

Page 50: 第六章 菜单、工具栏和状态栏

50返回返回

( 2 ) TRACE宏 TRACE宏提供了类似与 printf 函数的输出格式,用于将某一信息(即字符串)输出到 Dump 的设备环境 DC 中。该宏只在调试状态下工作。 TRACE宏的限制是一次最多输出 512 个字符。如:int i = 1;char sz[] = "one";TRACE( "Integer = %d, String = %s\n", i, sz );此外,还有 TRACE0~TRACE3 这样 4 个独立的宏,分别用于输出纯字符串 ~ 字符串 +3 个参数。它们的原型分别为:TRACE0( exp )TRACE1( exp, param1 ) TRACE2( exp, param1, param2 )TRACE3( exp, param1, param2, param3 )

Page 51: 第六章 菜单、工具栏和状态栏

51返回返回

如:TRACE0( "Start Dump of MyClass members:" );

int i = 1;

TRACE1( "Integer = %d\n", i ); // Output: 'Integer = 1'

int j = 1;

char sz[] = "one";

TRACE2( "Integer = %d, String = %s\n",j, sz ); // Output: 'Integer = 1, String = one'

2. 如何实现工具栏的船坞化 所谓船坞化工具栏就是可以将工具栏拖动到屏幕的任意位置上,还可以用鼠标改变工具栏的大小。下面我们就来实现工具栏的船坞化。

Page 52: 第六章 菜单、工具栏和状态栏

52返回返回

首先要通过调用 CControlBar 的成员函数 EnableDocking() 使工具栏能够船坞化;然后通过调用 CFrameWnd类的成员函数 EnableDocking ()确保边框窗口能够船坞化;最后调用 CFrameWnd 的成员函数 DockControlBar()使工具栏固定在边框窗口上。 所有这些工作都在边框窗口类的成员函数 OnCreate() 中完成。这三个函数的原型为:void CControlBar::EnableDocking( DWORD dwStyle );

void CFrameWnd::EnableDocking( DWORD dwDockStyle );

void CFrameWnd::DockControlBar( CControlBar * pBar, UINT nDockBarID = 0, LPCRECT lpRect = NULL );

其中:参数 dwStyle 和 dwDockStyle 表示工具栏的风格,其取值见表 6.6 , pBar 是指向待船坞化的工具栏的指针。

Page 53: 第六章 菜单、工具栏和状态栏

53返回返回

具体代码如下,其中粗体部分为新添加的代码。int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

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

return -1;

// TODO: Add your specialized creation code here

if (!m_MyDataToolBar.Create(this)||

!m_MyDataToolBar.LoadToolBar(IDR_MYTOOLBAR))

{ TRACE0("Failed to created toolbar\n");

return -1;

}

Page 54: 第六章 菜单、工具栏和状态栏

54返回返回

m_MyDataToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_MyDataToolBar);

return 0;

}

编译并运行该应用程序,将看到工具栏已经船坞化了。可以用鼠标将它拖动到窗口的任意位置。

Page 55: 第六章 菜单、工具栏和状态栏

55返回返回

6.3 创建状态栏 状态栏位于应用程序框架窗口的底部,它可以分割成几个窗格,一般用于显示一些文本信息,比如:工具栏按钮的提示信息、 Caps Lock 键及 Num Lock 键的状态等等。1 . 创建状态栏资源下面,我们在前例的基础上,为应用程序 Dialog 添加一个状态栏,用来显示一个消息区、一个字符串和 Num Lock 键的状态。其具体步骤如下:步骤一:为状态栏的内容建立一个 ID 号。步骤二:在对话框中单击【 New 】按钮,弹出【 New Symbol 】对话框,在【 Name 】栏中填入 ID_STATUSBAR_STR, 在【 Value 】栏中的数字是系统为用户提供的 ID数值。单击【 OK 】按钮继续。

Page 56: 第六章 菜单、工具栏和状态栏

56返回返回

步骤三:新添加的 ID 信息将会出现在【 Resource Symbols 】对话框的列表中。单击【 Close 】按钮关闭【 Resource Symbols 】对话框。此时完成创建 ID 的工作。步骤四:在工作区窗口中选择【 Resource View 】选项卡,双击【 String Table 】文件夹中的【 String Table 】选项,窗口中将显示出串表编辑器。在编辑器中单击鼠标右键,在弹出的菜单中选择【 New String 】菜单项。步骤五:系统弹出【 String Properties 】对话框,在【 ID 】框中选择 ID_STATUSBAR_STR 项,在【 Caption 】框中输入字符串“测试状态栏!”,按【 Enter 】键确认。

Page 57: 第六章 菜单、工具栏和状态栏

57返回返回

2. 实现状态栏实现状态栏的具体步骤如下:步骤一:在工作区窗口中选择【 Class View 】选项卡,用鼠标右键单击【 CMainFrame 】选项,在弹出菜单中选择【 Add Member Variable 】菜单项。弹出【 Add Member Variable 】对话框 , 在【 Variable Type 】栏中输入类型名称 CStatusBar ,在【 Variable Name 】栏中输入类型名称为 m_MyStatusBar 。单击【 OK 】按钮继续。此时, Visual C++ 将自动在主框架的类定义文件 MainFrm.h 中添加以下声明:CStatusBar m_MyStatusBar;

步骤二:在 MainFrm.cpp 文件中加入数组 indicators 的定义,具体代码如下,其中粗体部分为新增加的代码。

Page 58: 第六章 菜单、工具栏和状态栏

58返回返回

// CMainFrameIMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)//{{AFX_MSG_MAP(CMainFrame)ON_WM_CONTEXTMENU()ON_WM_CREATE()//}}AFX_MSG_MAPEND_MESSAGE_MAP()static UINT indicators[]={ ID_SEPARATOR, // 状态行指示器 ID_STATUSBAR_STR, ID_INDICATOR_NUM,};

Page 59: 第六章 菜单、工具栏和状态栏

59返回返回

步骤三:在文件 MainFrm.app 中对函数 OnCreate() 进行修改,增加状态栏的创建代码。具体代码如下,其中粗体部分为新增加的代码。int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)

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

return -1;

// TODO: Add your specialized creation code here

if (!m_MyDataToolBar.Create(this)||

!m_MyDataToolBar.LoadToolBar(IDR_MYTOOLBAR))

{ TRACE0("Failed to created toolbar\n");

return -1;

}

Page 60: 第六章 菜单、工具栏和状态栏

60返回返回

m_MyDataToolBar.EnableDocking(CBRS_ALIGN_ANY);

EnableDocking(CBRS_ALIGN_ANY);

DockControlBar(&m_MyDataToolBar);

if(!m_MyStatusBar.Create(this)||

!m_MyStatusBar.SetIndicators(indicators,

sizeof(indicators)/sizeof(UINT)))

{ TRACE0("Failed to created status bar \n");

return -1; //fail to create

}

return 0;

}

Page 61: 第六章 菜单、工具栏和状态栏

61返回返回

步骤四:编译并运行此应用程序,将会看到在原来程序的基础之上,在窗口的最下端增加了一个状态栏。说明:( 1 )在上例创建状态栏的过程中,曾用到了 CStatusBar 类的对象, CStatusBar 是 Visual C++ 的 MFC 类库中的一个类,它用于描述状态栏, CStatusBar 类是由 CControlBar 类派生而来的。其中, Create 函数是其成员函数,该函数的原型为:BOOL Create( CWnd* pParentWnd,

DWORD dwStyle = WS_CHILD | WS_VISIBLE |CBRS_BOTTOM,

UINT nID = AFX_IDW_STATUS_BAR );

其中: pParentWnd 是指向状态栏父窗口的指针, dwStyle 是状态栏的风格, nID 是子窗口的 ID 号,表 6.7 中列出了决定状态栏风格的几种常用的取值及对应的风格。

Page 62: 第六章 菜单、工具栏和状态栏

62返回返回

表 6.7 dwStyle 的取值及对应的状态栏的风格

( 2)在 MainFrm.cpp文件中加入的数组 indicators 的定义: static UINT indicators[],用于描述状态栏中所包含的内容。如果在利用 AppWizard向导创建 SDI 或 MDI 应用程序框架中的第 4步中,选择了“ Initial status bar”时,则向导会自动在 MainFrm.cpp文件中加入数组 indicators 的定义。向导生成的缺省的 indicator 数组包含了四个元素,它们是 ID_SEPARATOR、 ID_INDICATOR_CAPS、 ID_INDICATOR_NUM和 ID_INDICATOR_SCRL。

取值 风格CBRS_TOP

CBRS_BOTTOM

CBRS_NOALIGN

在框架窗口的顶部在框架窗口的底部当父窗口改变尺寸以后不随之变动

Page 63: 第六章 菜单、工具栏和状态栏

63返回返回

( 3 )要在状态栏的窗格中显示文本信息,可以采用以下三种方法:① 调用 CWnd::SetWindowText 函数更新信息行窗格中的文本。由于状态栏也是一种窗口,所以在程序中可以直接调用该函数。如:若状态栏变量为 m_wndStatusBar ,则 m_wndStatusBar.SetWindowText(“ 新修改的信息” )语句将在信息行窗格中显示“新修改的信息”。② 手动处理状态栏的 ON_UPDATE_COMMAND_UI 更新信息,并在处理函数中调用 CCmdUI::SetText 函数,该函数的原型为:virtual void SetText( LPCTSTR lpszText );

其中:参数 lpszText 是一个指向字符串的指针。

Page 64: 第六章 菜单、工具栏和状态栏

64返回返回

③ 调用函数 CStatusBar::SetPaneText 与 CStatusBar::GetPaneText 可以设置或获得任何窗格(包括信息行窗格)中的文本。此函数的原型为:BOOL SetPaneText( int nIndex, LPCTSTR lpszNewText, BOOL bUpdate = TRUE );

CString GetPaneText( int nIndex ) const;

其中,参数 nIndex 是待设置的窗格位置索引号(第 1 个窗格的位置索引为 0 ), lpszNewText 表示要显示的字符串,若参数 bUpdate 的值为 TRUE ,系统自动更新显示的结果。( 4 )调用 CStatusBar:: CommandToIndex 可以获得指定资源 ID 号所在窗格的位置索引号,该函数的原型为:int CommandToIndex( UINT nIDFind ) const;

其中:参数 nIDFind 是状态栏中某一资源 ID 号。

Page 65: 第六章 菜单、工具栏和状态栏

65返回返回

( 5 )调用函数 CStatusBar::SetPaneInfo 与 CStatusBar::GetPaneInfo 可设置或获得窗格的长度、风格等信息,它们的函数原型为:void SetPaneInfo( int nIndex, UINT nID, UINT nStyle, int cxWidth );

void GetPaneInfo( int nIndex, UINT& nID, UINT& nStyle, int& cxWidth ) const;

其中:参数 nIndex 表示要设置的状态栏窗格的索引号,nID 用来为状态栏窗格指定新的资源 ID 号, cxWidth 表示窗格的像素宽度, nStyle 表示状态栏窗格的风格类型,用来指定窗格的外观,如: SBPS_POPOUT 表示窗格是凸起来的。具体见表 6.8 。

Page 66: 第六章 菜单、工具栏和状态栏

66返回返回

风格取值 风格 SBPS_NOBORDERS

SBPS_POPOUT

SBPS_DISABLED

SBPS_STRETCH

 

SBPS_NOMAL

窗格四周没有 3D 边框反显边框使文字凸起显示禁用窗格,不显示文本拉伸窗格,交填充窗格不用的空白空间。但状态栏中只能有一个窗格具有这种风格普通窗格,没有“拉伸”、“ 3D边框”、“文字凸起显示”等效果

表 6.8 状态栏中各窗格的风格取值及对应风格

Page 67: 第六章 菜单、工具栏和状态栏

67返回返回

( 6 )调用 CStatusBar::SetPaneStyle 与 CStatusBar::GetPaneStyle 可分别用来设置或获得状态栏窗格的风格,二者的原型如下:UINT GetPaneStyle( int nIndex ) const;

void SetPaneStyle( int nIndex, UINT nStyle );

其中:参数 nIndex 是状态栏中某一窗格的位置索引号,nStyle 为状态栏中窗格的风格。3. 进一步完善状态栏现在,我们在刚才添加状态栏例子的基础上进行修改。当用户选择“关于”菜单项时,弹出“字体对话框”,当单击“确定”按钮关闭此对话框后,在状态栏上原来显示文本测试状态栏的空格中显示“您已经查看过字体对话框 !” ,按照下面的方法进行操作。

Page 68: 第六章 菜单、工具栏和状态栏

68返回返回

步骤一:选择【 View 】菜单中的【 ClassWizard 】菜单项。弹出【 MFC ClassWizard 】对话框,在【 Class name 】列表中选择类 CMainFrame ,在【 Object IDs 】列表中选择 ID_APP_ABOUT ;右边的【 Messages 】栏中将出现 COMMAND 和 UPDATE_COMMAND_UI ,双击 COMMAND 选项。将弹出 Add Member Function 对话框。步骤二:接受系统缺省的函数名称 OnAppAbout ,单击【 OK 】按钮,返回 MFC ClassWizard 对话框。这时在MFC ClassWizard 对话框中的【 Member functions 】框中增加了一个函数 OnAppAbout 。步骤三:单击【 Edit Code 】按钮,在代码编辑窗口中打开 OnAppAbout 函数。在编辑此函数之前,首先要在 MainFrm.cpp 文件中添加一个 #include语句。具体代码如下,其中粗体部分为新增加的代码。

Page 69: 第六章 菜单、工具栏和状态栏

69返回返回

// MainFrm.cpp : implementation of the CMainFrame class

//

#include "stdafx.h"

#include "Dialog.h"

#include "MainFrm.h"

#include "MydataDialog.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

Page 70: 第六章 菜单、工具栏和状态栏

70返回返回

步骤四:在代码编辑窗口中,编辑函数 OnAppAbout() 。具体代码如下,其中粗体部分为新增加的代码。void CMainFrame::OnAppAbout() {// TODO: Add your command handler code hereCMydataDialog dlg;if(dlg.DoModal()==IDOK){CClientDC dc(this);SIZE size=dc.GetTextExtent(" 您已经查看过个人资料对话框 !");int ndex=m_MyStatusBar.CommandToIndex(ID_STATUSBAR_STR);m_MyStatusBar.SetPaneInfo(index,ID_STATUSBAR_STR,SBPS_POPOUT,size.cx);m_MyStatusBar.SetPaneText(index,_T(" 您已经查看过个人资料对话框 !"),TRUE); }}

Page 71: 第六章 菜单、工具栏和状态栏

71返回返回

说明:在此函数中,首先生成了一个字体对话框的实例,并且显示为有模式对话框。当用户单击【确定】按钮退出此对话框时,要改变状态栏的字符串显示。首先调用函数 GetTextExtent() 来获得字符串的长度,然后调用 CommandToIndex() 函数获得窗格的索引,再通过调用函数 SetPaneInfo() 来设置窗格的长度、风格等信息。在此例中,我们使用了风格 SBPS_POPOUT ,它使创建的窗格看起来是从状态栏中凸出来的。最后调用函数 SetPaneText() 来显示文本内容。步骤五:编译并运行此应用程序。

Page 72: 第六章 菜单、工具栏和状态栏

72返回返回

本章小结 在应用程序中,要实现菜单的功能,其步骤和方法

是先利用菜单编辑器建立菜单资源,然后编写菜单命令的 WM_COMMAND 消息映射函数及相应代码。在 MFC框架中,菜单命令消息是按照一定的顺序进行传递的。对于一个单文档应用程序,消息传递的顺序为:视图类→文档类→框架类→应用程序类。

Visual C++ 的 MFC 提供的菜单类 Cmenu 的对象可以用来表示各种 Windows 菜单,其中包括顶层菜单项及其相应的弹出式菜单。并且利用该类的成员函数可以在程序运行时处理有关菜单的操作。 工具栏是应用程序中常用操作的快捷方式,创建工

具栏的方法是先创建工具栏资源,然后在主框架窗口类 CMainFrame 中创建响应 WM_CREATE 的消息映射函数,在该函数中,利用 MFC 提供的工具栏类 CToolBar 对象的

Page 73: 第六章 菜单、工具栏和状态栏

73返回返回

Create 成员函数,创建工具栏。 CToolBar 类是由 CControlBar 类派生而来的,它用于描述工具栏。 状态栏中的空间按从左向右的顺序分为信息行窗格

和指示器窗格,处在状态栏最左侧的窗格,其位置序号为 0 ,向右依次类推,它可以分割成几个窗格,用来显示许多信息。其创建方法是先创建状态栏资源,然后在主框架窗口类 CMainFrame 中创建响应 WM_CREATE 的消息映射函数,在该函数中,利用 MFC 提供的工具栏类CStatusBar 对象的 Create 成员函数,创建状态栏。 CStatusBar 类是由 CControlBar 类派生而来的,它用于描述状态栏。状态栏中的窗格的个数及所显示的信息由在 MainFrm.cpp 文件中定义的数组 indicators 的元素的个数和元素的值来决定。

Page 74: 第六章 菜单、工具栏和状态栏

74返回返回

习题6.1 利用 AppWizard 向导建立一个单文档应用程序,并完成以下操作:( 1 )利用资源编辑器向原有菜单栏中增加一个顶层菜单“查看”,并在其下拉菜单(弹出菜单)中添加“显示鼠标坐标”菜单项。( 2 )在主框架窗口类即 CMainFrame 类中,建立响应WM_COMMAND 和 WM_COMMAND_UI 消息映射函数,函数名自定,函数的功能是,当程序运行过程中,用户选择“显示鼠标坐标”菜单项时能在该菜单项的左边显示“√”标记,当再次选择该菜单项时标记消失。( 3 )为“显示鼠标坐标”菜单项建立一个快捷键“ Ctrl+D” 。

Page 75: 第六章 菜单、工具栏和状态栏

75返回返回

( 4 )利用资源编辑器向现有的工具栏的末尾添加一个按钮,按钮的图标自己设计。并进行有关的设定使该按钮的功能同选择“显示鼠标坐标”菜单项的功能相同。( 5 )在现有状态栏的基础上再增加一个信息行窗格,用于显示鼠标移动过程中鼠标的当前 X , Y 坐标。( 6 )利用 ClassWizard 向导在应用程序的视图类中添加响应 WM_MOUSEMOVE 消息的消息处理函数,函数名自定,该函数的功能就是把鼠标在移动过程中的位置 X ,Y 坐标显示到状态栏的新增信息行窗格中。6.2 在 VC环境中,利用 Help 菜单查看和学习 CMenu 类、CToolBar 类、 CStatusBar 类、 CCmdUI 类的内容,即其中的数据成员和成员函数。