Download presentation
Presentation is loading. Please wait.
Published by罄秒 山 Modified 8年之前
1
1 第 10 章 在 MFC 中创建应 用程序的资源
2
2 在 Windows 的可执行文件中,资源是独 立于代码的,使用单独的 Resource Compiler 进行编译,并嵌入到可执行文 件中。 在编程过程中,代码是可复用的,资源 也是可复用的,通过资源的 “ 导入 ” 和 “ 导 出 ” 功能来实现资源的可复用。 程序的国际化,也是通过资源来实现的。
3
3 10.1 获取资源的一个样例 查看 Windows ( 98/2000 )系统中自带的纸牌 游戏中的图片资源: c:\Windows\cards.dll 或 c:\WINNT\System32
4
4 10.2 资源的应用
5
5 10.2.1 菜单资源的使用 创建一 个 “ 计算 ” 菜单
6
6 【例 10-1 】创建一个基于单文档结构的应用程 序,在视图中显示一行字符串 “Hello World!” , 通过建立包含 “ 显示 ” 和 “ 颜色选择 ” 两个菜单项 的 “ 操作 ” 菜单来控制字符串,菜单项 “ 显示 ” 用 以控制字符串的显示与否,菜单项 “ 颜色选择 ” 中包含一个级连菜单,内容为 “ 红 ” 、 “ 绿 ” 和 “ 蓝 ” 三个菜单项。 Hello World! ID_OPER_RED ID_OPER_GREEN ID_OPER_BLUE ID_OPER_SHOW
7
7 在 My_ResView.h 中的 class CMy_ResView : public CView 中的 public 处加入如下声明: COLORREF m_nColors[3]; // 用户可选颜色数组 DWORDm_nColorIndex; // 当前所选颜色索引 CStringm_strShow; // 显示的内容 BOOL m_bShow; // 是否显示
8
8 在 CMy_ResView::CMy_ResView() 中初始化成员变量: m_nColors[0] = RGB(255,0,0); m_nColors[1] = RGB(0,255,0); m_nColors[2] = RGB(0,0,255); m_nColorIndex = 0; m_strShow = "Hello World!"; m_bShow = TRUE; 在 void CMy_ResView::OnDraw(CDC* pDC) 中加入如下代码绘制字符串: if(m_bShow) {pDC->SetTextColor(m_nColors[m_nColorIndex]); // 设置输出字符串颜色 pDC->TextOut(100,100,m_strShow); // 输出字符串 }
9
9 若编译运行程序,可看到程序输出一行红色 的字符串,但颜色设置菜单项还没有起作用 下面将介绍如何通过菜单项来控制程序, 在介绍菜单项的响应时,必须先了解几个消 息响应机制: COMMAND 消息的响应 UPDATE_COMMAND_UI 消息的响应 ON_COMMAND_RANGE 对 COMMAND 消息的响应 ON_UPDATE_COMMAND_UI_RANGE 对 UPDATE_COMMAND_UI 消息的响应
10
10 (1) COMMAND 消息的响应 添加了对 COMMAND 消息的响应之后, My_ResView.h 发 生如下变化: // Generated message map functions protected: //{{AFX_MSG(CMy_ResView) afx_msg void OnOperShow(); //}}AFX_MSG
11
11 在 My_ResView.cpp 文件中,读者会看到 ID_OPER_SHOW 对应的 COMMAND 消息的绑定,代码如下 : BEGIN_MESSAGE_MAP(CMy_ResView, CView) //{{AFX_MSG_MAP(CMy_ResView) ON_COMMAND(ID_OPER_SHOW, OnOperShow) //}}AFX_MSG_MAP // Standard printing commands ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview) END_MESSAGE_MAP() 在 My_ResView.cpp 文件的最后加入如下代码: void CMy_ResView::OnOperShow() { m_bShow = !m_bShow; Invalidate();// 强制程序重新窗口 } 重新编译运行程 序,可看到 “ 显示 ” 菜单项工作正常
12
12 (2) UPDATE_COMMAND_UI 消息的响应 UPDATE_COMMAND_UI 消息是在窗口将要绘制菜单项的时 候产生,上例中,仅仅只是使用 “ 显示 ” 菜单项来控制是否显示 似乎还不够,如果 “ 显示 ” 菜单项能够配合主程序体现出当前是 否显示的状态可能会更好一些。就像一个文本编辑软件,菜单 上是 “10 号字 ” 、 “12 号字 ” 的功能,如果不在菜单上标识出来,那 么使用者可能就搞不清当前的字是多大的。 为 ID_OPER_SHOW 添加 UPDATE_COMMAND_UI 消息。在自动生 成消息处理函数中加入如下代码: void CMy_ResView::OnUpdateOperShow(CCmdUI* pCmdUI) { pCmdUI->SetCheck(m_bShow); } 此时可看到随着 m_bShow 的值的改变,显示菜单项的状 态与实际是否显示字符串的状态一致了,通过菜单项前面的 “√” 标记来体现。
13
13 void Enable( BOOL bOn = TRUE ) 禁止或者允许该菜单项 void SetCheck( int nCheck = 1 ) 设置菜单项 / 工具条按钮的 check 状态,显示标志为 “√” void SetRadio( BOOL bOn = TRUE ) 与 SetCheck 功能类似,显示标志为 “·” void SetText( LPCTSTR lpszText ) 设置菜单项的 Caption 属性 CCmdUI 类常 用的方法
14
14 (3) ON_COMMAND_RANGE 对 COMMAND 消息的响应 ON_COMMAND_RANGE 为处理具有连续 Object ID 的菜 单项提供了方便的途径。 前面只响应了三种颜色操作,若有 100 种颜色可供 选择,是否逐个定义其响应函数?显然工作量很大, 我们可以使用 ON_COMMAND_RANGE 。 这涉及到 ID 范围的上下界及当前的 ID ,若 Resource.h 中若干个 ID 不连续,要手工修改为连续的。 由于 ClassWizard 不支持 ON_COMMAND_RANGE 消 息的自动映射,只能手工添加消息的处理。 在 My_ResView.h 中声明消息的处理函数 //{{AFX_MSG(CMy_ResView) afx_msg void OnOperShow(); afx_msg void OnUpdateOperShow(CCmdUI* pCmdUI); afx_msg void OnOperColorChange(WORD nID); //}}AFX_MSG 所处理的菜单项的 ID 。
15
15 在 My_ResView.cpp 的开头部分加入如下斜体标识的代码, 完成消息映射 BEGIN_MESSAGE_MAP(CMy_ResView, CView) //{{…… ON_COMMAND_RANGE( ID_OPER_RED,// ID 范围的最小值 ID_OPER_BLUE,// ID 范围的最大值 OnOperColorChange)// 消息处理函数 END_MESSAGE_MAP() 在 My_ResView.cpp 的最后加入消息处理函数: void CMy_ResView::OnOperColorChange(WORD nID) { m_nColorIndex = nID-ID_OPER_RED; Invalidate(); } 运行程序,可以通过菜单项来改变颜色了
16
16 (4) ON_UPDATE_COMMAND_UI_RANGE ON_UPDATE_COMMAND_UI_RANGE 与 ON_UPDATE_COMMAND_UI 的关系类似和 ON_COMMAND_RANGE 与 ON_COMMAND 的关系 下面仿照手工加入 ON_COMMAND_RANGE 过程加 入 ON_UPDATE_COMMAND_UI_RANGE 宏。 在 My_ResView.h 中加入如下代码: afx_msg void OnUpdateOperColorChange(CCmdUI * pCmdUI);
17
17 在 My_ResView.cpp 中加入如下代码: ON_UPDATE_COMMAND_UI_RANGE(ID_OPER_RED,ID_OP ER_BLUE,OnUpdateOperColorChange) … void CMy_ResView::OnUpdateOperColorChange(CCmdUI * pCmdUI) { pCmdUI->SetRadio(m_nColorIndex== (pCmdUI->m_nID - ID_OPER_RED)); } 由于 CCmdUI 类的成员 m_nID 就是调用 OnUpdateOperColorChange 时当前的菜单项 ID ,因此 OnUpdateOperColorChange 函数没有 nID 这个参数
18
18 10.2.2 快捷菜单的创建及其应用 【例 10-2 】在【例 10-1 】的基础上增加快捷菜 单,实现 “ 操作 ” 菜单的功能 1. 创建菜单资源:在 ResourceView 菜单中右击 Menu , 选择 Insert Menu ,资源命名为 IDR_MENU_POP ID_POP_SHOW
19
19 在 My_ResView.h 中声明快捷菜单中对应的变量。 CMenum_PopMenu;// Pop-up 快捷菜单 CMenu*m_pPop;// Pop-up 快捷子菜单 …… afx_msg void OnRButtonDown(UINT nFlags, CPoint point); 在 My_ResView.cpp 中添加如下代码: ON_COMMAND(ID_POP_SHOW, OnOperShow) // 消息响应 … CMy_ResView::CMy_ResView() { … m_PopMenu.LoadMenu(IDR_MENU_POP); // 创建并加载菜单资源 }
20
20 CMy_ResView::~CMy_ResView() { m_PopMenu.DestroyMenu(); // 释放菜单资源 } void CMy_ResView::OnRButtonDown(UINT nFlags, CPoint point) { m_pPop=m_PopMenu.GetSubMenu(0); // 获得第一个子菜单 UINT nCheck = m_bShow?MF_CHECKED:MF_UNCHECKED; // 更新【 Show 】的 check 状态 m_pPop->CheckMenuItem(ID_POP_SHOW,MF_BYCOMMAND|nCheck); ClientToScreen(&point); // 将坐标由客户坐标转化为屏幕坐标 m_pPop->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this); // 显示 Pop-up 菜单 CView::OnRButtonDown(nFlags, point); }
21
21 10.2.3 加速键资源的创建及其使用 【例 10-3 】在【例 10-2 】的基础上添加 Ctrl+W 来触 发 “ 显示 ” 菜单项的功能。 打开 ResourceView Accelerator IDR_MAINFRAME ,会看到一张 加速键列表,在列表的最后高亮区域双击,会弹出 Accel Properties 对话框。 ID 选择 ID_OPER_SHOW (或直接填写)。然 后单击 Next Key Typed 按钮,会弹出一个对话框,提示按下对应 的加速键,这里按下 Ctrl+W ,则 VC IDE 会自动为你设置好 Key 、 Modifiers 和 Type 三个属性。
22
22 10.2.4 工具条资源的创建及其使用 在 Windows 应用程序中,工具条可以看作是 图形化的菜单,是一种更快捷、更有效、更 直观的人机交互方式。 1 工具条类的层次位置及其常用方法 工具条由 CWnd 类 派生的,它们都连 接到一个 Windows 应用程序窗口。因 此, CWnd 的所有 功能如创建、移动、 显示和隐藏窗口等 在用控制条工作时 都是可用的。
23
23 Create() :创建一个工具条并把它附加到 CToolBar 对象上 CreateEx() :创建一个定义了边界的工具条并附加到 CToolBar 对象上 SetSizes() :设置按钮及位图大小 SetHeight() :设置工具条的高度 LoadToolBar() :装载工具条资源 LoadBitmap() :装载包含工具按钮图像的位图 SetBitmap() :设置位图图像 SetButtons() :设置按钮并使每个按钮与位图图像相关 CToolBar 的构造方法
24
24 (1) 增加工具条资源 Insert Resource Toolbar New 插入新的工 具条资源。 (2) 将工具条添加到窗口中 添加后,需把工具条的对象加入到应用程序框架 窗口中 (CMainFrame) 。在应用程序的 CMainFrame 类中加入工具条对象 m_wndToolBar protected: CToolBar m_wndToolBar;// 自己定义的工具条 2 加入用户自定义的工具条
25
25 在框架窗口类的 OnCreate() 函数中调用工具条类 的 Create() 或 CreateEx() 成员函数创建该工具条, 并调用 LoadToolBar() 成员函数将工具条对象和 前面创建的工具条资源连接在一起。 if(!m_wndToolBar.Create(this , WS_VISIBLE|CBRS_TOP) ||!m_wndToolBar.LoadToolBar(IDR_TOOLBAR)) // 引入资源 IDR_TOOLBAR { TRACE0("Failed to create toolbar\n"); return -1; // fail to create }
26
26 3 对工具条进行操作 创建完成工具条后,可调用工具条类中的成员函 数对工具条进行操作,例如设定工具条风格,在窗口 中移动工具条,控制工具条的显隐等。 当鼠标光标在按钮上暂停时,显示工具提示和命 令描述,并设定工具条的大小是可变的。 m_wndToolBar.SetBarStyle(CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC); 可在程序中设置允许用户在程序运行中在框架窗口内 移动工具条。这是通过调用 CToolBar::EnableDocking 和 CFrame::EnableDocking 来实现的。二函数原型均如下: void EnableDocking( DWORD dwStyle )
27
27 【例 10-4 】在【例 10-3 】中添加工具条,工具条中包含 四个按钮,分别对应菜单的 “ 显示 ” 、 “ 红色 ” 、 “ 绿色 ” 和 “ 蓝色 ” 菜单项。该工具条可以在窗口中任意位置停靠, 当鼠标停留在工具条按钮上时,将显示该按钮的功能。
28
28 在 ResourceView 中加入工具条资源 IDR_TOOLBAR_NEW 绘制四个按钮并设置相应 ID 。 在 MainFrm.h 中添加如下代码,声明一个 CToolBar 变量 CToolBar m_wndToolBarNew; 在 MainFrm.cpp 文件的 Int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) 函数中添加如下代码: if (!m_wndToolBarNew.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBarNew.LoadToolBar(IDR_TOOLBAR_NEW)) {TRACE0("Failed to create toolbar\n"); return -1; // fail to create }
29
29 为了使新增的工具条可以在窗口中自由停靠,在 OnCreate 函数中,还要增加如下代码: m_wndToolBarNew.EnableDocking(CBRS_ALIGN_ANY); // 工具条可以在父窗口内任何一边停靠 EnableDocking(CBRS_ALIGN_ANY); // 父窗口允许子工具条窗口在任何一边停靠 DockControlBar(&m_wndToolBarNew); // 父窗口内按照前面指定的风格停靠该工具条
30
30 10.2.5 图标资源的创建及其使用 每个 Windows 应用程序在资源管理器中都有自 己的图标,这个图标就是 ICON 资源。 【例 10-5 】在【例 10-4 】的基础上通过修改光标 资源,使得执行程序的图标变为如图所示的 样子。
31
31 ResourceView Icon IDR_MAINFRAME ,就会看到 图标编辑器,在这里可以选择图标的尺寸,默认的是 16×16 和 32×32 。 16×16 的图标用于程序运行时左上角图标、任务条图标、 资源管理器的列表和详细信息模式; 32×32 的图标用于程序运行时默认对话框图标、资源管 理器图标模式; 48×48 的图标用于资源管理器的平铺和缩略图模式。
32
32 单击 New Device Image 按钮对光标资源进行修改
33
33 10.2.6 字符串资源的使用 字符串资源最主要的用途就是用于程序的多语 言版本。如果要想动态切换界面语言,使用字符串 资源是很好的选择。 在 MFC 中,可以通过 CString 类的 LoadString 方法 来从资源载入字符串。 具体操作是打开 ResourceView String Table ,在表 中的空白高亮处双击,在弹出的 String Properties 对 话框中的 ID 编辑框中输入 IDS_STRING_HELLO , Caption 编辑框中输入 “Hello VC!” 。
34
34 在 My_ResView.cpp 文件的构造函数中,将原来的 m_strShow = "Hello World!"; 改为: m_strShow.LoadString(IDS_STRING_HELLO); 这样我们的程序的输出就变为 “Hello VC!” 了 使用字符串资源的好处就是不需 要在整个程序中去寻找某个字符 串,如果某些字符串可能在将来 会发生变更,那么最好将它写在 字符串资源中。
35
35 10.2.7 对话框资源的创建及其应用 【例 10-6 】在上例的基础上编写一个对话框用 于接收用户输入,然后用这个输入来替换主 程序原来显示的字符串
36
36 在创建完对话框资源之后,需要生成一个相关的对话 框类。 View ClassWizard Create a New Class OK , 在 Name 中填入 “CInputDlg” 即可。
37
37 将对话框上的 IDC_EDIT_INPUT 控件与一个 CString 类型的 m_strInput 变量绑定,建立一种映射关系。 上面的操作使 MFC 在幕后作了些什么 ? 在 InputDlg.h 文件中, MFC 加入了如下代码: // Dialog Data //{{AFX_DATA(CInputDlg) enum { IDD = IDD_DIALOG_NEW }; CStringm_strInput; //}}AFX_DATA
38
38 在 InputDlg.cpp 的构造函数中, MFC 加入了如下代码: //{{AFX_DATA_INIT(CInputDlg) m_strInput = _T(""); //}}AFX_DATA_INIT 在 InputDlg.cpp 文件的 DoDataExchange 函数中, MFC 加 入了如下代码: //{{AFX_DATA_MAP(CInputDlg) DDX_Text(pDX, IDC_EDIT_INPUT, m_strInput); //}}AFX_DATA_MAP 在函数 DDX_Text 调用中,完成了控件与变量之间 的数据交换。 对 m_strInput 的初始化
39
39 下面要在 CMy_ResView 中使用新创建的对话框 首先为 “ 操作 ” 菜单增加菜单项 “ 修改字符串 ” ,其 ID 为 ID_OPER_STRING 。在 CMy_ResView 中增加 COMMAND 消 息响应函数 OnOperString 。然后在 My_ResView.cpp 文件 头部 include 部分最后加入: #include "InputDlg.h" 在 OnOperString 中加入如下代码: void CMy_ResView::OnOperString() { CInputDlg dlgInput; // 声明对话框变量 if(dlgInput.DoModal() == IDOK) // 如果用户点击 OK 按钮 { m_strShow = dlgInput.m_strInput;// 更改字符串 Invalidate(); // 强制重绘 }
40
40 10.2.8 位图资源的创建及其应用 标准控件比较单调,若能通过一些精美的 图片来点缀,就活泼了,这个问题,可以选择 位图资源来实现。 位图是一种数字化的图形表示形式,基本 数据结构是像素,一个像素表示一个离散点的 颜色值。 常见位图有 2 色、 4 色、 16 色、 256 色、 16 位、 24 位。其中 VC 6 的资源编辑器只支持 256 色以 下(包括 256 色)的位图的编辑,而最新的 VC7 已经支持 24 位真彩位图的编辑了。保存在 文件中的位图可以看作是设备无关的,文件本 身的数据用来描述位图的内容。
41
41 【例 10-7 】在【例 10-6 】的基础上显示两幅图片, 一幅是 256 色 (IDB_BITMAP_256) ,另一幅是 24 位真 彩 (IDB_BITMAP_24bit) ,两幅图片都是通过资源来 显示
42
42 在 CMy_ResView.cpp 的 OnDraw 函数中加入如下代码: CDC dcMemory; // 创建内存缓冲 DC dcMemory.CreateCompatibleDC(pDC); CBitmap bmp1; // 加载 256 位图 bmp1.LoadBitmap(IDB_BITMAP_256); BITMAP bmpInfo1; bmp1.GetBitmap(&bmpInfo1); // 获得位图的尺寸 CBitmap* pOldBitmap = dcMemory.SelectObject(&bmp1); // 选择位图到内存缓冲设备中 pDC->BitBlt(200,10,bmpInfo1.bmWidth,bmpInfo1.bmHeight, &dcMemory,0,0,SRCCOPY); // 绘制到屏幕
43
43 CBitmap bmp2; bmp2.LoadBitmap(IDB_BITMAP_24bit); // 加载 24 位位图 BITMAP bmpInfo2; bmp2.GetBitmap(&bmpInfo2); dcMemory.SelectObject(&bmp2); pDC->BitBlt(400,10,bmpInfo2.bmWidth, bmpInfo2.bmHeight, &dcMemory,0,0,SRCCOPY); dcMemory.SelectObject(pOldBitmap); // 恢复设备中原来的位图
Similar presentations