上一页 下一页 返回

3.6 使用菜单

  现在我们要在主窗口中加入自己的菜单。菜单编程一般分三步:

1.编辑菜单资源,设置菜单属性(包括菜单名和ID);
2.用ClassWizard自动映射菜单消息和成员函数;
3.手工编辑成员函数,加入菜单消息处理代码。

3.6.1 编辑菜单资源

  仍然使用我们前面生成的Hello程序,编辑由AppWizard自动生成的菜单资源。要编辑菜单资源:

(1) 选择项目工作区的ResourceView标签,切换到资源视图。
(2) 选择菜单资源类型。
(3) 选定菜单资源IDR_MAINFRAME,双击该项或单击鼠标右键然后在弹出菜单中选择Open选项。Visual Studio将弹出菜单编辑窗口,显示菜单资源IDR_MAINFRAME,其中IDR_MAINFRAME是由AppWizard在创建该程序时自动生成的。
(4) 编辑当前菜单

  要删除某个菜单项或弹出菜单,可用鼠标单击该菜单或用上下光标键来回选择,然后按Del键删除;要插入新菜单项,可选定窗口中的空白菜单框后按回车(或直接用鼠标双击该空白框),Visual Studio弹出Properties(属性)对话框,如图3-11所示。属性对话框用于输入菜单项的标题、标识符、菜单项在状态栏上显示的提示(Prompt),并为该菜单提供属性调整。也可以在选择一个已有的菜单项时按Ins键,以在该菜单项上方插入一个空白菜单项,然后双击该菜单项进行编辑。要插入一个分隔线,只需将菜单项的Seperator属性打开即可。
  Visual Studio支持鼠标拖曳调整菜单项位置。要调整菜单项位置,只需要选中某菜单项并将其拖至适当位置即可。

T3_11.tif (250480 bytes)

3.11 菜单编辑器和属性对话框

  如上图,我们首先在Edit和View之间加入一个弹出菜单:用鼠标单击View菜单,按Ins键插入一个空白菜单项,双击该空白框弹出其属性对话框。在菜单属性栏输入“&Test”字样。然后在Test弹出菜单下加入以下四个菜单项,并在&Say Hello菜单下加入一个分隔符。菜单项属性设置如下表:

菜单名 菜单ID 菜单提示(Prompt)
Say &Hello

ID_SAY_HELLO

Say hello to you!
&Red ID_SELECT_RED The color is red.
&Blue ID_SELECT_BLUE The color is blue.
&Yellow ID_SELECT_YELLOW The color is yellow.

 

提示:如果菜单中要使用中文,则除了在菜单名一项中输入中文外,还要将菜单资源的语言属性设置为中文。方法是:鼠标右键单击资源视图的菜单资源IDR_MAINFRAME,弹出快捷菜单,选择Properties,弹出整个菜单资源的属性对话框,如图3-12所示。在Languages下拉列表框中选择Chinese (P.R.C.)。这样以后菜单就可以正确使用和显示中文了。如果其他资源如对话框或字符串要使用中文,也要将该资源的语言属性改为Chinese(P.R.C)。

 

T3_12.tif (107259 bytes)

3.12 设置菜单语言属性

  现在关闭菜单编辑器窗口。我们要为Say Hello菜单增加一个加速键CTRL+H。要编辑加速键,选择Accelerator资源类型,双击打开IDR_MAINFRAME加速键资源。要删除加速键,可以直接按Del键。要增加加速键,可以按Ins键,弹出加速键属性对话框。在ID下拉列表框中选择ID_SAY_HELLO,在Key一栏中输入H,完成加速键设置。关闭加速键编辑窗口。

3.6.2 用ClassWizard自动映射菜单消息和成员函数

  现在我们用ClassWizard为上面创建的几个菜单生成和映射消息处理成员函数。在此之前我们首先介绍一下ClassWizard的用法。

用ClassWizard管理类和Windows消息

  ClassWizard有助于创建Windows消息和命令处理函数、创建和管理类、创建类成员变量、创建OLE Automation的方法和属性、创建数据库类以及其他一些工作。
  ClassWizard也有助于覆盖MFC类中的虚函数。先选类,再选择需要覆盖的虚函数。该过程的其余部分与消息处理是类似的。

启动ClassWizard应用程序

  从View菜单或源程序编辑窗口右键菜单中选择ClassWizard(快捷键:Ctrl +W),Developer Studio将弹出MFC ClassWizard对话框。该对话框包含几个标签页,提供以下选项:

Message Maps:它管理消息和成员函数之间的映射关系。

Member Variables:它可以让用户加进一些数据成员,以便和各种控制进行数据交换。

Automations:它提供了各种特性支持OLE2.0,包括为OLE Automation增加属性、方法以及处理事件。

ActiveX Events:为ActiveX控件增加属性、方法以及为ActiveX控件事件增加处理函数。

Class Info:它可以让用户创建新类,以便支持对话框和各种可视类(包括控制、窗口等)。还可以从类库文件导入类到当前工程中。

  在这一章里,我们只用到Message Maps这一页,因此我们在这里只介绍Message Maps的使用。

Message Maps选项

  可以让用户加入成员函数来处理消息,删除成员函数以及对成员函数进行编辑。

Message Maps页包括如下控制选项:

 

Projects组合框:允许用户选择当前工作区中包含的工程。

Class Name组合框:允许用户选择当前工程中的类。

Objects IDs列表框:列出当前选中的类名及相关的ID。对窗口和视来说,这些ID为菜单标识符;对对话框来说,这些ID为控制框的ID。

Messages列表框:列出当前所选类的可重载的虚方法以及可接收到的消息。

Member Functions列表框:列出ClassName组合框中当前所选的项中所包含的所有成员函数。用户可以增加、删除成员函数,也可以对成员函数进行编辑。

Add Class...按钮:它允许用户往工程里添加新类。在按钮右边有一个向下的小箭头,表明按此按钮将弹出一个菜单。菜单包含两项:New...可以新建一个类;From a type Lib用于从一个类库中导入类。

Add Function按钮:它允许用户往Member Functions列表框中加进一个新的消息处理成员函数,该新增成员函数被用来响应Message Maps列表中当前所选中的消息。

Delete Function按钮:用于删除Member Functions列表框中所选中的项。

Edit Code按钮:它允许用户对Member Functions中所选中的项进行编辑,此时Visual Studio 将关闭MFC ClassWizard对话框,并打开相应文件,并将光标定位在函数定义的开头处。

T3_13.tif (369325 bytes)

3-13 ClassWizard增加菜单消息成员函数映射

  现在我们就利用ClassWizard为Hello程序增加菜单消息和成员函数的映射。在View菜单下选择ClassWizard,弹出MFC ClassWizard对话框。选择Message Maps页,在Class Name下拉列表中选择CMainFrame类。在Object IDs中选择ID_SAY_HELLO,在Messages栏中双击COMMAND,弹出Add Member Function对话框。对话框中给出缺省的成员函数OnSayHello,按OK接收缺省的成员函数名。此时OnSayHello 成员函数就出现在Member Functions列表框中,后面跟所映射的消息,如图3-13所示。列表框中开头的字母W表示窗口消息,V表示可重载的虚方法(Virtual Method)。如此,依次为ID_SELECT_BLUE、ID_SELECT_RED、ID_SELECT_YELLOW增加消息处理成员函数OnSelectBlue、OnSelectRed、OnSelectYellow。然后双击Member Functions列表中的OnSayHello,编辑OnSayHello成员函数。

3.6.3 手工添加代码

在OnSayHello成员函数体中加入语句。

void CMainFrame::OnSayHello()

{

 

AfxMessageBox(“Hello!”);

}

消息框函数

AfxMessageBox用来弹出一个消息框,它的函数原型有两种版本:

int AfxMessageBox( LPCTSTR lpszText, UINT nType = MB_OK, UINT nIDHelp = 0 );

 

int AFXAPI AfxMessageBox( UINT nIDPrompt, UINT nType = MB_OK, UINT nIDHelp = (UINT) –1 );

  在第一种形式中,lpszText表示在消息框内部显示的文本,消息框的标题为应用程序的可执行文件名(如Hello)。在第二种形式中,nIDPrompt为要显示的文本字符串在字符串表中的ID。函数调用时会自动从字符串表中载入字符串并显示在消息框中。nType为消息框中显示的按钮风格和图标风格的组合,可以采用|(或)操作符组合各种风格。

按钮风格

MB_ABORTRETRYIGNORE 消息框中显示Abort、Retry、Ignore按钮

MB_OK 显示OK按钮

MB_OKCANCEL 显示OK、Cancel按钮

MB_RETRYCANCEL 显示Retry、Cancel按钮

MB_YESNO 显示Yes、No按钮

MB_YESNOCANCEL 显示Yes、No、Cancel按钮

图标风格

MB_ICONINFORMATION 显示一个i图标,表示提示

MB_ICONEXCLAMATION 显示一个惊叹号,表示警告

MB_ICONSTOP 显示手形图标,表示警告或严重错误

MB_ICONQUESTION 显示问号图标,表示疑问

  比如,要在消息框中显示一个问号、一个“Yes”按钮、一个“No”按钮,可以以下面的方式调用AfxMessageBox。

AfxMessageBox(“Are you sure?”,MB_YESNO|MB_ICONQUESTION);

还有一个与AfxMessageBox类似的函数MessageBox,它是CWnd的类成员函数:

int MessageBox( LPCTSTR lpszText,LPCTSTR lpszCaption = NULL,

UINT nType = MB_OK );

 

  与AfxMessageBox不同的是,它多了一个lpszCaption参数,从名字上就可以推断出它表示消息框的标题,这样就可以设置消息框的标题,而不必采用可执行文件名作为标题了。
  两个函数的区别:AfxMessageBox比MessageBox简单一些,因为它是一个全局函数所以不需要对应的一个窗口类,但是不能控制消息框标题,常用于调试程序时的内部数据输出或警告;MessageBox比较正式,常用在要提交的应用程序版本中,可以控制标题内容而不必采用含义不明的可执行文件名为标题。
  现在再来编写OnSelectRed、OnSelectBlue、OnSelectYellow三个函数。首先我们双击CMainFrame类名,在MainFrm.h中加入数据成员,如下所示:

class CMainFrame:public CFrameWnd{

...

// Attributes

public:

 

int m_nColor;

enum{RED=0,BLUE=1,YELLOW=2};

...

}

  注意我们这里使用了匈牙利命名法,建议读者也采用这种命名方法,以便提高程序可读性。加入数据成员后,还要对它进行初始化,初始化工作在CMainFrame()构造函数中完成。

CMainFrame::CMainFrame()

{

 

m_nColor=RED;

}

OnSelectRed、OnSelectBlue、OnSelectYellow三个函数修改后如清单3.4:

 

清单3.4

void CMainFrame()::OnSelectRed()

{

 

m_nColor=RED;

SayColor();

}

void CMainFrame()::OnSelectBlue()

{

 

m_nColor=BLUE;

SayColor();

}

 

void CMainFrame()::OnSelectYellow()

{

 

m_nColor=YELLOW;

SayColor();

}

 

然后在MainFrm.h中加入SayColor()函数的声明:

//Operations

public:

 

void SayColor();

在MainFrm.cpp中,在OnSelectYellow()成员函数后面,手工加入SayColor()函数的定义。

void CMainFrame::SayColor()

{

switch(m_nColor)

{

case RED:

AfxMessageBox(“Color is red!”);

break;

case BLUE:

AfxMessageBox(“Color is blue!”);

break;

case YELLOW:

AfxMessageBox(“Color is yellow!”);

break;

}

}

  这样,当我们选择颜色时,就会显示不同的消息框显示当前选择的颜色。但是用消息框显示当前选中的颜色似乎太繁琐了一些。我们在使用WORD编写文档时,注意到在选择不同的视图时,在视图菜单名前显示一个点,表明这是当前选择的视图。我们是否也可以这么做?回答是肯定的。要实现这一功能,就要使用MFC框架的更新命令用户接口消息机制。