第 2章 Windows 窗口命令
Windows应用程序都是基于消息驱动的,应用程序通过消息与用户进行交互。消息分为标准 Windows消息、控件通知消息和命令消息三大类,程序员需要为用户所关心的消息建立消息映射并编写具有特定功能的消息处理函数。
2.1 消息与命令
Windows应用程序都是消息驱动的,消息处理是 Windows
应用程序的核心。消息是操作系统通知应用程序某个事件已经发生的一种方式,例如当用户敲击键盘、点击菜单、
移动鼠标或改变窗口大小时,都会向适当的窗口发送消息
。同样,MFC应用程序也要处理 Windows消息,但是由于 MFC
类库中已经封装了消息和对消息的响应事件,这就使在用
Visual C++开发 Windows应用程序时,对消息的处理更加简单和易于维护。
应用程序在初始化完成后,将调用 CWinApp的成员函数
Run来处理消息循环,消息循环不断检索由各种事件产生的消息,并将消息分发给适当的窗口。窗口接收到消息后,
将调用专门的处理函数来处理各种消息。消息处理函数通常是某个类的成员函数,编写消息处理函数是编写 MFC应用程序的主要任务。
2.1.1 响应消息的实例
2.1.2 消息的种类
1,标准 Windows消息标准 Windows消息主要分为三类 。
( 1) 键盘消息
( 2) 鼠标消息
( 3) 窗口消息
2,控件消息
3,命令消息
( 1)用户界面对象图 2.4说明了用户界面对象的处理过程。
( 2)命令 ID
( 3) 命令目标
( 4) 命令和控件消息的处理函数选择用户界面对象,
如 Clear All菜单项产生命令消息
ID_EDIT_CLEAR_ALL
命令 — 目标消息映射
ON_COMMAND
调用消息处理函数
OnEditClearAll()
图 2.4 用户界面对象处理过程
2.1.3 消息的发送和接收
1.标准 Windows消息和处理函数
2.命令消息的发送
MFC把命令消息发送给命令目标链 (有可能处理该消息的一系列对象 ),其中至少有一个对象含有处理该命令消息的消息处理函数 。 命令目标链中的对象接收到消息后,将检查自己的消息映射,查看是否能处理相应的消息 。 不同对象检查消息映射的时机是不同的,也就是说,消息是按一定优先顺序在命令目标链中传递的 。 通常,每个命令目标类先把命令消息发送给某些其它对象
,给其它对象先行处理该命令消息的机会 。
表 2.3列出了常用目标类的命令发送顺序 。
表 2.3 标准命令的发送顺序接收到命令的命令目标类 查询命令的顺序
MDI主边框窗口 1) 活动的 MDI子窗口2) 主边框窗口
3) 应用程序 ( CWinApp类对象 )
MDI子框架窗口 1) 活动视图
2) 子框架窗口
SDI边框窗口 1) 活动视图2) 框架窗口
3) 应用程序 ( CWinApp类对象 )
视图 1) 视图
2) 与视图相连的文档文档 1) 文档
2) 与文档相连的文档模板对话框 1) 本对话框2) 拥有本对话框的窗口
3) 应用程序 ( CWinApp类对象 )
2.1.4 消息映射的结构消息映射都由一组宏组成,可以参照 【 例 2.1】 的源代码,在 CMousePositionView.cpp文件中,我们可以看到以下代码:
BEGIN_MESSAGE_MAP(CMousePositionView,CView)
//{{AFX_MSG_MAP(CMousePositionView)
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
1.消息映射的继承关系
2.消息映射的结构表 2.4列出了常用的映射宏及其语法格式 。 注意
,映射宏之后不能用分号 。
3,手工添加消息映射表 2.4 常用映射宏及其语法消息类型 宏格式 参 数标准 Windows消息 ON_WM_XXX 无参数命令消息 ON_COMMAND 命令 ID,处理函数名命令更新通知消息 ON_UPDATE_COMMAND_UI 命令 ID,处理函数名控件通知消息 ON_XXX 命令 ID,处理函数名用户自定义消息 ON_MESSAGE 自定义消息 ID,处理函数名已注册 Windows消息 ON_REGISTERED_MESSAGE 消息 ID,处理函数名命令 ID范围 ON_COMMAND_RANGE 起始命令 ID,结束 ID,处理函数名将更新的命令 ID范围 ON_UPDATE_COMMAND_UI_RANGE 起始命令 ID,结束 ID,处理函数名控件 ID范围 ON_CONTROL_RANGE 控件通知码,起始控件 ID,
结束 ID,处理函数
2.2 菜 单 栏
2.2.1 菜单简介为了使 Windows程序更加易于操作,许多程序员在设计菜单时,都遵循下列规范:
若点击菜单项,会弹出对话框,在该菜单项文本后应有,…,标记;
若某项菜单含有子菜单,在该菜单项文本后应有?标记;
若菜单项需要助记符,在英文菜单中,需要将助记字母用下划线标出,在中文菜单中,用括号将带下划线的助记字母括起来;
若为某菜单项设置快捷键,则一般将其列在相应菜单项文本之后 。
1.菜单风格最常用的菜单是下拉式菜单和级联菜单。
2,助记符和快捷键通常要为菜单项命令提供助记符和快捷键,以提供用户通过键盘快速访问菜单命令的功能 。
2.2.2 设计菜单
1.菜单资源编辑器设计菜单,主要是设置菜单的属性。在菜单资源编辑器中,双击菜单项或右击菜单项并从弹出的快捷菜单中选择,Properties”项,将弹出,Menu
Item Properties”对话框,如图 2.5所示,可以通过该对话框编辑设置菜单项的属性。
图 2.5 菜单资源编辑器
2,完成菜单命令的消息映射菜单项作为用户界面对象,被用户操作后能产生
WM_COMMAND命令消息,命令消息能被文档类,应用程序类,视图类,窗口类等多种对象接收,处理,可以使用 ClassWizard为命令消息进行消息映射,如图 2.6所示 。 映射命令消息与映射标准 Windows消息类似,只是在 Object IDs列表中要选择相应的菜单 ID,要将命令消息映射到合适的类中,请在 Class name列表中选择需要进行映射的类 。
图 2.6 使用 ClassWizard映射菜单命令消息
3,菜单命令消息的处理过程用户操作菜单时,将会产生命令消息,MFC把命令消息发送给命令目标链,命令消息在命令目标链中是按照一定的优先顺序进行传递的。这就使不同的类对象优先响应菜单命令消息的机会不同了。对于 SDI应用程序,响应菜单命令的优先顺序为:视图 → 文档 → SDI框架窗口 → 应用程序,对于 MDI应用程序,响应菜单命令的优先顺序为:视图 → 文档 → MDI子框架窗口 → MDI主框架窗口 → 应用程序

4,为菜单添加快捷键在 Windows应用程序中,需要为一些常用的菜单项命令提供快捷键 。 快捷键与助记符是有所区别的,助记符是由操作系统进行解释的,而快捷键是作为 MFC的一种资源而存在的,需要在加速键表中进行定义 。 在 Workspace窗口的
ResourceView 选 项 卡 中,打开 Accelerator,双击
IDR_MAINFRAME,就可以进行快捷键的定义和编辑 。
图 2.7 快捷键编辑器
2.2.3 使用菜单类 Cmenu
1,菜单类的基本操作
( 1) 创建菜单
( 2) 获取菜单项
( 3) 添加和删除菜单项
( 4) 装入菜单
2.实现弹出菜单使用 CMenu类的 TrackPopupMenu函数可以很容易创建弹出菜单,函数原型为:
BOOL TrackPopupMenu( UINT nFlags,int x,int y,
CWnd* pWnd,LPCRECT lpRect = NULL );
其中,nFlags表示菜单在屏幕上显示的位置以及鼠标按钮标志,其取值含义见表 2.7。 pWnd表示拥有弹出菜单的窗口指针,此窗口将收到菜单的 WM_COMMAND命令消息。 x,y表示菜单显示位置。
表 2.7 nFlags参数取值及含义
nFlags值 含 义
TPM_CENTERALIGN 屏幕位置标志,菜单水平中心位置由 x参数决定
TPM_LEFTALIGN 屏幕位置标志,菜单左边位置由 x参数决定
TPM_RIGHTALIGN 屏幕位置标志,菜单右边位置由 x参数决定
TPM_LEFTBUTTON 鼠标按钮标志,用户单击鼠标左键时弹出菜单
TPM_RIGHTBUTTON 鼠标按钮标志,用户单击鼠标右键时弹出菜单
nFlags可以是屏幕位置标志中之一和鼠标按钮标志中之一的组合 。
2.3 工 具 栏
AppWizard生成应用程序时,通常会生成默认的工具栏图标,其资源 ID号为 IDR_MAINFRAME,我们可以以此资源为基础进行编辑修改,也可以创建新的工具栏并在程序中显示 。 AppWizard除了生成默认的工具栏资源外,还在类 CMainFrame 中 定 义 一 个 CToolBar 类 成 员 变 量
m_wndToolBar,并在 CMainFrame类的 OnCreate函数中调用 m_wndToolBar的成员函数 Create创建并显示相应的工具栏 。 如果要创建第二个工具栏,也必须完成如下过程,(
1) 创建新的工具栏资源; ( 2) 在 CMainFrame类中定义
CToolBar 类 型 成 员 变 量 ; ( 3 ) 在 CMainFrame 类的
OnCreate函数中创建并显示工具栏对象 。
2.4 状 态 栏
2.4.1 AppWizard生成的状态栏通常情况下,AppWizard生成应用程序框架时,会生成默认的状态栏 。 状态栏窗格的数量及排列顺序由 MainFrm.cpp
文件中定义的全局静态数组 indicators决定,AppWizard默认生成的数组如下:
static UINT indicators[] =
{
ID_SEPARATOR,// status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
AppWizard在 CMainFrame类中定义了 CStatusBar
类的成员变量 m_wndStatusBar,并在 CMainFrame类的 OnCreate函数中调用 m_wndStatusBar的
SetIndicators成员函数和 Create函数创建并显示状态栏类对象。
AppWizard还生成了“查看”菜单,其菜单项“
状态栏”控制状态栏的显示和隐藏。此外,每个指示器窗格都有更新命令 UI消息控制函数,用来更新指示器窗格的状态。
2.4.2 定制自己的状态栏在程序开发过程中,我们可以定制自己的状态栏,定制工具栏需要完成以下步骤 。
( 1) 定制 indicators数组,要增加信息行窗格,只需将
ID_SEPARATOR标识符放在数组的适当位置即可 。 如果要增加指示器窗格,首先要定义标识符常量,然后在字符串资源编辑器中增加以该常量作为 ID的字符串资源,字符串资源编辑器如图 2.12所示,最后将 ID放在 indicators数组的适当位置 。
在添加字符串资源时,应在 Caption栏中填入初始的字符串值 (可以用空格进行填充 ),因为该字符串的长度决定了相应指示器窗格的宽度 。
图 2.12 字符串资源编辑器
( 2)映射增加的指示器窗格的更新命令消息,以控制该窗格状态的更新。
( 3)在程序的适当地方,通过访问 CMainFrame类的
m_wndStatusBar对象并调用其成员函数定制状态栏的输出和状态,CStatusBar类的主要成员函数有:
int CommandToIndex( UINT nIDFind ) const;
UINT GetItemID( int nIndex ) const;
void SetPaneInfo( int nIndex,UINT nID,UINT nStyle,int
cxWidth );
BOOL SetPaneText( int nIndex,LPCTSTR lpszNewText,
BOOL bUpdate = TRUE );