好文档就是一把金锄头!
欢迎来到金锄头文库![会员中心]
电子文档交易市场
安卓APP | ios版本
电子文档交易市场
安卓APP | ios版本

可视化程序设计310.ppt

428页
  • 卖家[上传人]:hs****ma
  • 文档编号:584728271
  • 上传时间:2024-08-31
  • 文档格式:PPT
  • 文档大小:5.12MB
  • / 428 举报 版权申诉 马上下载
  • 文本预览
  • 下载提示
  • 常见问题
    • 可视化程序设计第一部分 API编程(第3章~第7章)第二部分 MFC编程(第8章~第14章)Visual C++面向对象与可视化程序设计习题解析与编程实例(第2版) 第3章 Windows应用程序3.1 Windows3.1 Windows编程基础知识编程基础知识3.2 Windows3.2 Windows应用程序常用消息应用程序常用消息3.3 Windows3.3 Windows中的事件驱动程序设计中的事件驱动程序设计3.4 Windows3.4 Windows应用程序的基本结构应用程序的基本结构 可视化集成开发环境(IDE)可视化集成开发环境Visual C++Visual BasicVisual JavaC++BuilderDelphiJBuilder√ 可视化l程序在设计期、运行期都是可视的. 集成IDE源程序编辑器和编译器Debug系统函数库和系统函数开发工具资源管理器和资源编辑器可供选择的例程库(MFC AppWizard)联机帮助(MSDN Library)应用程序发布和安装工具 Windows程序l面向对象的程序 = 对象1 + 对象2 + …lWindows程序的规范部件(窗口、菜单、对话框、按钮、程序模块等)是对象,编程时相当一部份工作是创建对象和为对象属性赋值.对象之间通过消息互相通信 Visual C++编程方法1.传统方法(API)lWindows系统是一个很大的服务中心,调用它的各种服务(上千个API函数),可以帮助应用程序达到管理窗口、描绘图形、使用周边设备等目的.l由于这些服务针对的对象是应用程序,所以称之为应用编程接口(API).2.交互式方法(MFC)lMFC类库将API函数封装成一百多个类,程序员利用已定义好的类或自定义的类,来创建各类对象并确定对象的属性,从而搭建起应用程序的“框架”.l进一步编写必要的细节代码,最后构成完整的应用程序. Windows APIAPI为应用程序提供各种函数和数据结构的定义应用程序可以利用标准API函数调用系统的功能是Windows系统与应用程序间的标准程序接口lAPI函数按功能分类1.窗口管理函数: 实现窗口的创建、移动和修改功能.2.图形操作函数: 实现与设备无关的图形操作功能.3.系统服务函数: 实现与操作系统有关的多种功能. Windows编程的重要概念l窗口l事件驱动l句柄l消息 窗口(Window)l窗口是Windows应用程序的基本操作单元,是应用程序与用户交互的接口环境,也是系统管理应用程序的基本单位.l编写Windows应用程序首先应创建一个或多个窗口.程序的运行过程也就是在窗口内部、窗口与窗口之间、窗口与系统之间进行数据处理与数据交换的过程.客户区 事件驱动(Event Driven)u传统的面向过程程序的流程遵从于程序员预先规定的路径,而Windows应用程序的执行顺序取决于事件的发生顺序(事件驱动)l事件: 对象可以识别的一个动作.例如,按下鼠标,按下/释放键盘键等.u当一个事件发生时,系统会产生一条特定的消息,以标识该事件的发生.l消息: 传递信息或请求的数据包.例如,在窗口客户区按下鼠标左键时,将产生一条WM_LBUTTONDOWN消息.该消息包含虚键是否按下、光标坐标等信息.u并非所有的消息都是由事件产生.有些消息是由系统发出的,有些消息是由函数调用产生的.lWM_PAINT消息是由系统发出的.l调用PostQuitMessage()会产生一条WM_QUIT消息.uWindows程序的设计重点是编写消息处理代码. 事件、消息、消息处理?l事件: 爸爸打儿子l消息: 儿子喊叫l消息处理: 妈妈收到消息后的某种反应l事件: 单击按钮l消息: BN_CLICKEDl消息处理: 编码实现在编辑框内显示“Hello World!” 句柄(Handle)lA variable that identifies an object; an indirect reference to an operating system resource. l句柄是一个用于标识对象的变量,具有4个字节的长度,用于标识应用程序中不同的对象或同类对象中不同的实例.l应用程序通过句柄来访问它所标识的对象,并进行相应的操作.窗口按钮图标滚动条输出设备控制文件表3-1 常用句柄类型及其说明句柄类型说明句柄类型说明HWND窗口句柄HDC设备环境句柄HINSTANCE应用实例句柄HBITMAP位图句柄HCURSOR光标句柄HICON图标句柄HFONT字体句柄HMENU菜单句柄HPEN画笔句柄HFILE文件句柄HBRUSH画刷句柄HGDIOBJ GDI对象lWin32 API共有39种句柄类型.l例3-1代码片断: HWND hwnd; …; hwnd=CreateWindow(…); 消息(Message)l传递信息或请求的数据包.lMessages can be passed between the operating system and an application, different applications, threads within an application, and windows within an application. 消息队列(Message Queue)l队列是一种先进先出(First In First Out)的线性表,它允许在表的一端进行插入,而在另一端删除元素.l消息队列: An operating system-defined memory object that holds an ordered list of messages awaiting processing.1.The system message queue holds mouse and keyboard input waiting to be passed to a thread's message queue.2.A thread's message queue holds messages waiting to be retrieved by a thread's message loop. 消息队列l对每一个单线程Windows应用程序,系统都会为它创建一个相应的线程消息队列(有时也称为应用消息队列).当事件发生时,相应的消息将“发送”至消息队列.l应用程序利用消息循环(message loop)从线程消息队列中取回消息,并对消息作出响应.l有些消息并不入队,而是由系统直接发送至窗口处理程序.例如,WM_CREATE、WM_PAINT消息.TMQ2app1app2SMQTMQ1 消息结构MSGtypedef struct tagMSG {HWND hwnd; // 接收消息的窗口句柄UINT message; // 消息号,unsigned int,每种消息都有相应的消息号WPARAM wParam; // 32位附加信息,取决于消息号LPARAM lParam; // 32位附加信息,取决于消息号DWORD time; // 消息发送时间,32位unsignedPOINT pt; // 消息发送时光标的屏幕位置} MSG; typedef struct tagPOINT { LONG x; LONG y;} POINT;l例3-1代码片断: MSG Msg; …; while(…) {…}; 消息的分类1.system-defined messagesl每一个系统消息都有一个唯一的标识(消息号),不同类别的系统消息带有不同的前缀.lWM消息涉及各种信息和请求,包括鼠标输入、键盘输入,菜单、对话框输入,窗口的创建和管理,动态数据交换(DDE).2.application-defined messagesl如果一个应用定义了自己的消息,则接收窗口的消息处理过程必须对消息进行解释并提供适当的处理.前缀类别前缀类别BM按钮控件CB组合框控件DM下压式按钮控件EM编辑控件LB列表框控件SBM滚动条控件WM窗口共23类 第3章 Windows 应用程序3.1 Windows3.1 Windows编程基础知识编程基础知识3.2 Windows3.2 Windows应用程序常用消息应用程序常用消息3.3 Windows3.3 Windows中的事件驱动程序设计中的事件驱动程序设计3.4 Windows3.4 Windows应用程序的基本结构应用程序的基本结构 常用的窗口消息(WM消息)消息号(正整数)说明WM_LBUTTONDOWN 在窗口客户区按下鼠标左键时产生WM_LBUTTONUP 在窗口客户区释放鼠标左键时产生WM_RBUTTONDOWN 在窗口客户区按下鼠标右键时产生WM_RBUTTONUP 在窗口客户区释放鼠标右键时产生WM_LBUTTONDBLCLK在窗口客户区双击鼠标左键时产生WM_RBUTTONDBLCLK在窗口客户区双击鼠标右键时产生WM_KEYDOWNWM_KEYUP 按下非系统键时产生(按键消息)释放非系统键时产生(按键消息)WM_CHAR字符消息(按键消息转换后产生)WM_CREATE创建窗口时产生WM_CLOSE关闭窗口时产生(窗口关闭前). The WM_CLOSE message is sent as a signal that a window or an application should terminate.WM_DESTROY关闭窗口时产生(窗口关闭中). The WM_DESTROY message is sent when a window is being destroyed.WM_QUIT调用PostQuitMessage函数时产生,从而导致应用终止. The WM_QUIT message indicates a request to terminate an application and is generated when the application calls the PostQuitMessage function.WM_PAINT请求绘画窗口时产生共二百多种 关闭窗口时发生了什么?按关闭按钮1.产生WM_CLOSE消息2.产生WM_DESTROY消息3.产生WM_QUIT消息调用PostQuitMessage函数4.终止应用 第3章 Windows 应用程序3.1 Windows3.1 Windows编程基础知识编程基础知识3.2 Windows3.2 Windows应用程序常用消息应用程序常用消息3.3 Windows3.3 Windows中的事件驱动程序设计中的事件驱动程序设计过程驱动过程驱动( (图图3-2) & 3-2) & 事件驱动事件驱动( (图图3-3)3-3)3.4 Windows3.4 Windows应用程序的基本结构应用程序的基本结构 Windows应用程序的基本结构Windows程序入口函数WinMain窗口处理函数(过程)WndProc完成一系列定义和初始化工作,并产生消息循环定义应用程序接收消息后如何进行响应 WinMain函数int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow ){① 定义并注册窗口类;② 创建并显示窗口;③ 产生消息循环;}指定函数调用规则: 参数传递次序从右至左,由被调函数取回栈中参数一个应用可能运行多个实例指明当前实例句柄和前一个实例句柄指向命令行参数的字符指针窗口的显示状态,系统将为该参数分配一个值演示应用的多个实例和命令行参数 函数调用时参数传递次序问题#includevoid f(int x, int y){cout< // 数据类型、数据结构、API函数的定义LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // 函数声明int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow){① 定义并注册窗口类;② 创建并显示窗口;③ 产生消息循环;return Msg.wParam; // 只要返回1个整数就可以}LRESULT CALLBACK WndProc(HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam){switch(message){//case 其他消息: …; break;case WM_DESTROY:PostQuitMessage(0);default:return DefWindowProc(hwnd, message, wParam, lParam);}return (0);} 第第4 4章章 Windows Windows 的图形设备接口及的图形设备接口及Windows Windows 绘图绘图4.1 4.1 图形设备接口图形设备接口4.2 4.2 绘图工具与颜色绘图工具与颜色4.3 4.3 常用绘图函数常用绘图函数4.4 4.4 应用实例应用实例4.5 4.5 小结小结 图形设备接口(GDI)u对于涉及图形输出的Windows应用,如果让应用程序直接与硬件设备打交道,则程序员必须了解各种输出设备的细节.uGDI是应用程序与输出设备之间的中介l一方面,GDI向应用程序提供了一个与设备无关的编程环境.l另一方面,GDI通过设备驱动程序实现图形输出.应用程序GDI屏蔽了硬件设备的差异性,使应用程序与设备无关驱动程序 绘图操作过程应用程序×Windows系统不允许应用程序直接访问外部设备应用程序DCGDI驱动程序外设Windows系统提供了一个统一的设备环境,通过它使应用程序与外设相连DC应用程序的每一次图形操作均参照DC的属性执行,并可通过HDC更改它的属性 设备描述表(Device Context)u设备描述表(设备环境,设备上下文,DC)是一组属性的集合(结构体类型),属性集包括:l一组图形对象l各图形对象的相关属性l影响输出的图形模式l物理输出设备的信息(设备名、驱动程序等)u图形输出的主要任务是创建和维护一个设备描述表. 图形对象及其属性图形对象属性位图字节数、尺寸(像素)、颜色格式、压缩方案等画刷样式、颜色、填充图案、起始点调色板颜色、颜色号字体字体名、宽度、高度、磅值、字符集等画笔样式、宽度、颜色区域位置、尺寸When an application creates a device context, the system automatically stores a set of default objects in it. An application can examine the attributes of the default objects by calling the GetCurrentObject and GetObject functions. The application can change these defaults by creating a new object and selecting it into the device context. An object is selected into a device context by calling the SelectObject function. 图形模式l表4-2中能否发现上述5种图形模式? 设备描述表类型 窗口管理u在窗口中绘画、绘图、写文本是Windows应用常见的数据输出方式.u多任务操作系统意味着可能有多个应用同时在运行,导致屏幕中出现多个窗口.u为了确保程序的平滑运行以及应用之间的相互协调,系统要对屏幕中的各种输出统一管理.l窗口是应用程序(对显示类型而言)的主要输出设备.l对每一个窗口,系统都提供一个唯一的DC.l利用DC,应用程序将它的输出引导至相应的窗口中.窗口DC 窗口刷新u下列情况要对窗口进行刷新:l首次创建窗口l改变窗口大小l移动窗口l将窗口从下层移至顶层l对象穿越窗口l最小化窗口l最大化窗口l显示文件中的数据l滚动数据l改变数据l选中数据 如果不刷新需要恢复的区域底层窗口被顶层窗口覆盖当底层窗口置于顶层时,需要恢复被覆盖区域的颜色和形状 刷新请求u下列事件发生时,窗口客户区内容需要被刷新1.窗口移动: 窗口移动或显示,改变窗口大小,滚动窗口.2.去除覆盖: 关闭下拉式菜单,消除对话框或消息框等对象.3.对象穿越: 光标穿过用户区,图标拖过用户区.u针对刷新请求,如果线程消息队列为空,系统直接发送WM_PAINT消息至窗口处理过程,以通知窗口函数执行刷新处理.l刷新请求的优先级别低.lWM_PAINT消息是不入队消息(不进入线程消息队列).l教材P84第3段叙述有错误.注意: WM_PAINT消息是由系统产生,要等应用程序的消息队列(线程消息队列)为空时才发送WM_PAINT消息. 系统对刷新请求的响应1.窗口移动后的刷新2.被覆盖区域的刷新3.对象穿越后的刷新(系统自动完成)标记待刷新的区域当消息队列为空时,系统直接发送WM_PAINT消息至窗口处理过程执行刷新(默认处理)DefWindowProc() 有些刷新要由应用自己维护l有些刷新是由应用程序自已管理的.例如,显示文件、选择数据等,对这些刷新请求有2种处理方式:标记待刷新的区域发送WM_PAINT消息至窗口处理过程处理WM_PAINT消息发送其他消息入列从队列中取回消息并发送至窗口处理过程处理消息l只有在队列中没有其他消息的情况下,系统才会发送WM_PAINT消息,导致第1种方式可能会存在一些延时,此时可考虑第2种方式.l如果想在窗口中绘图,最好采用第1种方式.12 例4-1 例4-1l对WM_PAINT消息的处理case WM_PAINT: hDC=BeginPaint(hWnd, &PtStr); //获得DC句柄 SetMapMode(hDC, MM_ANISOTROPIC); //设置各向异性映射模式 hPen=(HPEN)GetStockObject(BLACK_PEN); //画笔,多余! hBrush=(HBRUSH)GetStockObject(DKGRAY_BRUSH); //画刷 SelectObject(hDC,hBrush); //选择画刷 SelectObject(hDC,hPen); //选择画笔,多余! RoundRect(hDC, 50,120,100,200,15,15); //圆角矩形 hBrush=(HBRUSH)GetStockObject(LTGRAY_BRUSH); //画刷 SelectObject(hDC,hBrush); //选择画刷 Ellipse(hDC, 150,50, 200, 150); //椭圆 hBrush=(HBRUSH)GetStockObject(HOLLOW_BRUSH); //画刷 SelectObject(hDC, hBrush); //选择画刷 Pie(hDC, 259, 50, 300, 100, 250, 50, 300, 50); //饼形 EndPaint(hWnd, &PtStr); //释放DC return 0; 例4-1中的WM_PAINT消息l新建窗口后更新窗口客户区,系统会发送WM_PAINT消息.hWnd = CreateWindow(...);if(!hWnd) return FALSE;ShowWindow(hWnd, nCmdShow);UpdateWindow(hWnd);l当窗口内容发生改变时,系统也会发送WM_PAINT消息. 修改后的例4-1l不处理WM_PAINT消息l对WM_LBUTTONDOWN消息的处理代码如下:case WM_LBUTTONDOWN: hDC=GetDC(hWnd); SetMapMode(hDC, MM_ANISOTROPIC); hBrush=(HBRUSH)GetStockObject(DKGRAY_BRUSH); SelectObject(hDC,hBrush); RoundRect(hDC, 50,120,100,200,15,15); hBrush=(HBRUSH)GetStockObject(LTGRAY_BRUSH); SelectObject(hDC,hBrush); Ellipse(hDC, 150,50, 200, 150); hBrush=(HBRUSH)GetStockObject(HOLLOW_BRUSH); SelectObject(hDC, hBrush); Pie(hDC, 259, 50, 300, 100, 250, 50, 300, 50); ReleaseDC(hWnd, hDC); return 0; 修改后的例4-1运行情况程序运行后并没有立即绘图鼠标左击时绘图,但图形不能自动刷新 刷新常用的方法1.保存副本l刷新时将副本拷贝到相应的窗口中,适合于刷新复杂图形.2.记录事件l刷新时重新执行这个事件.3.重新绘制l如果绘制的图形比较简单,可以将绘图代码放在WM_PAINT消息的响应模块中,一旦需要刷新,系统将发送WM_PAINT消息. 用最小矩形标记待刷新区域交集 用最小矩形标记待刷新区域 用最小矩形标记待刷新区域最小矩形 获取设备环境的三种方法1.调用BeginPaint函数2.调用GetDC函数3.调用GetDCEx函数 BeginPaint函数HDC BeginPaint(HWND hwnd, //窗口句柄LPPAINTSTRUCT lpPaint //PAINTSTRUCT类型指针);l通知指定的窗口准备进行绘画,并填写一个带有裁剪区(最小矩形)信息的PAINTSTRUCT结构.l函数调用成功,返回一个显示型DC句柄;函数调用失败,返回NULL,表示无可用的DC.l该函数只能出现在WM_PAINT消息的处理模块中.l绘图完成后,需要调用EndPaint函数释放获取的设备环境.BOOL EndPaint( HWND hWnd, PAINTSTRUCT *lpPaint); 设备环境窗口PAINTSTRUCT结构 PAINTSTRUCT结构l矩形结构(P75)typedef struct _RECT {LONG left; //左上角x坐标LONG top; //左上角y坐标LONG right; //右下角x坐标LONG bottom; //右下角y坐标} RECT;lPAINTSTRUCT结构typedef struct tagPAINTSTRUCT {HDC hdc; //显示型DC句柄BOOL fErase; //是否擦除背景,真表示擦除RECT rcPaint; //裁剪区域(限制输出只能在裁剪区内)BOOL fRestore; //系统保留BOOL fIncUpdate; //系统保留BYTE rgbReserved[32]; //系统保留} PAINTSTRUCT; GetDC/GetDCEx函数HDC GetDC(HWND hWnd //窗口句柄); u没有限定函数调用位置,可以在非WM_PAINT消息的响应模块中使用.u释放DClint ReleaseDC(HWND hWnd, HDC hDC );HDC GetDCEx(HWND hWnd, //窗口句柄HRGN hrgnClip, //裁剪区句柄DWORD flags //unsigned int,指定DC创建方式); 缩放平移旋转切变反射映射模式(Mapping mode)l程序员绘图是在一个统一的逻辑坐标系中进行的,而实际图形输出依赖于设备坐标系,两者间存在坐标系的转换问题.l映射模式定义了基于逻辑坐标系的图形与实际输出效果之间的关系. 映射模式(续)l窗口: 对应逻辑坐标系上程序员设定的区域.l视口: 对应实际输出设备上程序员设定的区域.l窗口、视口可以调用相关函数进行设置.l窗口、视口只有在MM_ANISOTROPIC(各向异性)映射模式和MM_ISOTROPIC(各向同性)映射模式下才有意义.MM_ANISOTROPIC不改变视口尺寸,导致窗口中画的图形在视口中发生了变化MM_ISOTROPIC强制改变视口尺寸,从而窗口中画的图形在视口中进行了等比例的缩放窗口视口程序员设定的视口实际视口 与映射模式有关的函数l设置映射模式int SetMapMode(HDC hdc, //DC句柄int fnMapMode //映射模式(表4-4));函数调用成功,返回前一次的映射模式;否则返回0.l获取当前的映射模式int GetMapMode(HDC hdc //DC句柄); 设置窗口、视口区域l设置窗口区域BOOL SetWindowExtEx(HDC hdc, //DC句柄int nXExtent, //窗口宽度int nYExtent, //窗口高度LPSIZE lpSize //原窗口尺寸(SIZE类型指针)); l设置视口区域BOOL SetViewportExtEx(HDC hdc,int nXExtent,int nYExtent,LPSIZE lpSize); typedef struct tagSIZE{ LONG cx; LONG cy;} SIZE; 设置窗口、视口原点l设置窗口原点BOOL SetWindowOrgEx(HDC hdc,int X, //新原点x坐标int Y, //新原点y坐标LPPOINT lpPoint //Point类型指针,保存原原点坐标);l设置视口原点BOOL SetViewportOrgEx(HDC hdc,int X,int Y,LPPOINT lpPoint); typedef struct tagPOINT { LONG x; LONG y;} POINT; 第第4 4章章 Windows Windows 的图形设备接口及的图形设备接口及Windows Windows 绘图绘图4.1 4.1 图形设备接口图形设备接口4.2 4.2 绘图工具与颜色绘图工具与颜色4.3 4.3 常用绘图函数常用绘图函数4.4 4.4 应用实例应用实例4.5 4.5 小结小结 画笔l获取系统提供的画笔HPEN hP; //画笔句柄hP = (HPEN)GetStockObject(BLACK_PEN);l创建自定义画笔HPEN hP;hP = CreatePen(...);l将画笔选入DCHGDIOBJ SelectObject(HDC hdc,HGDIOBJ hgdiobj //已创建的对象句柄);l删除画笔BOOL DeleteObject(HGDIOBJ hObject //图形对象句柄);WHITE_PENDC_PENHPEN CreatePen(int fnPenStyle, //样式(表4-5)int nWidth, //线型COLORREF crColor //颜色); 画刷l获取系统提供的画刷HBRUSH hBr;hBr = (HBRUSH)GetStockObject(BLACK_BRUSH);l创建自定义画刷HBRUSH hBr;hBr = CreateSolidBrush(...); //单色画刷hBr = CreateHatchBrush(...); //带阴影图案画刷表4-6HBRUSH CreateSolidBrush(COLORREF crColor //画刷颜色); HBRUSH CreateHatchBrush(int fnStyle, //阴影样式(表4-7)COLORREF clrref //画刷颜色);l将画刷选入DCl删除画刷 颜色lWindows用32位无符号整数值表示一种颜色.lWindows使用宏RGB定义颜色.COLORREF RGB(BYTE bRed, //红色值BYTE bGreen, //绿色值BYTE bBlue //蓝色值);返回一种用32位表示的颜色.00~2550~2550~25532位 第第4 4章章 Windows Windows 的图形设备接口及的图形设备接口及Windows Windows 绘图绘图4.1 4.1 图形设备接口图形设备接口4.2 4.2 绘图工具与颜色绘图工具与颜色4.3 4.3 常用绘图函数常用绘图函数4.4 4.4 应用实例应用实例4.5 4.5 小结小结 设置画笔当前位置BOOL MoveToEx(HDC hdc, //DC句柄int X, //新位置x坐标int Y, //新位置y坐标LPPOINT lpPoint //Point类型指针,用于保存前一次的位置); 直线l从当前位置到目标位置的直线BOOL LineTo( //教材P91函数名有错误HDC hdc, //DC句柄int nXEnd, //目标点x坐标int nYEnd //目标点y坐标); l依次连接POINT数组中的各点(画一组直线)BOOL Polyline(HDC hdc, //DC句柄 CONST POINT *lppt, //POINT指针,指向POINT数组 //每个数组元素表示一个点int cPoints //数组中的点数(>=2)); 五角星示例long WINAPI WndProc(...){ PAINTSTRUCT ps; HDC hdc; POINT aptStar[6] = {{50,2}, {2,98}, {98,33}, {2,33}, {98,98}, {50,2}}; switch(iMessage) { case WM_PAINT: hdc = BeginPaint(hWnd, &ps); Polyline(hdc, aptStar, 6); EndPaint(hWnd, &ps); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; default: return (DefWindowProc(hWnd, iMessage, wParam, lParam)); }} 椭圆弧BOOL Arc(HDC hdc, //DC句柄int x1, int y1, //左上角坐标int x2, int y2, //右下角坐标int x3, int y3, //用于确定弧的起始点int x4, int y4 //用于确定弧的终止点); (x1,y1)(x2,y2)(x3,y3)(x4,y4) 饼图(椭圆扇面,被填充)BOOL Pie(HDC hdc, //DC句柄int x1, int y1, //左上角坐标int x2, int y2, //右下角坐标int x3, int y3, //用于确定弧的起始点int x4, int y4 //用于确定弧的终止点); (x1,y1)(x2,y2)(x3,y3)(x4,y4) 矩形、圆角矩形(被填充)lBOOL Rectangle(HDC hdc,int x1, int y1, //左上角坐标int x2, int y2 //右下角坐标);lBOOL RoundRect(HDC hdc,int x1, int y1, //左上角坐标int x2, int y2, //右下角坐标int nWidth, //圆角宽度int nHeight //圆角高度); 椭圆(被填充)BOOL Ellipse(HDC hdc,int x1, int y1,int x2, int y2); 多边形(被填充)BOOL Polygon(HDC hdc,CONST POINT *lpPoints, //指向顶点数组int nCount //顶点数, >=2); 第第4 4章章 Windows Windows 的图形设备接口及的图形设备接口及Windows Windows 绘图绘图4.1 4.1 图形设备接口图形设备接口4.2 4.2 绘图工具与颜色绘图工具与颜色4.3 4.3 常用绘图函数常用绘图函数4.4 4.4 应用实例应用实例例4-1、例4-3程序结构相同,均是响应WM_PAINT消息例4-2除了响应WM_PAINT消息外,还用到了鼠标左击与右击4.5 4.5 小结小结 例4-2Ø初始映射模式为MM_TEXT,鼠标左击更改为MM_ISOTROPIC,同时刷新用户区;鼠标右击为MM_ANSIOTROPIC,同时刷新用户区.l指定刷新区域BOOL InvalidateRect(HWND hWnd, //窗口句柄CONST RECT *lpRect, //RECT结构指针,指定哪块区域 //要被刷新,NULL为整个客户区BOOL bErase //TRUE表示刷新时擦除背景);Ø调用BeginPaint函数时,系统填写一个带有裁剪区信息的PAINTSTRUCT结构.调用InvalidateRect函数又指定了一块刷新区域,这些区域将合并成新的刷新区域.Ø调用InvalidateRect函数后将触发WM_PAINT消息. 例4-2int nMode = MM_TEXT; //全局变量存放映射模式LRESULT CALLBACK WndProc(...){ HDC hdc; PAINTSTRUCT ps; HBRUSH hB1, hB2; switch(message) { case WM_LBUTTONDOWN: nMode=MM_ISOTROPIC; InvalidateRect(hwnd, NULL, 1); break; case WM_RBUTTONDOWN: nMode=MM_ANISOTROPIC; InvalidateRect(hwnd, NULL, 1); break; case WM_PAINT: hdc=BeginPaint(hwnd, &ps); SetMapMode(hdc, nMode); ...... break; ... }} 例4-2运行情况MM_TEXT模式MM_ISOTROPIC模式MM_ANSIOTROPIC模式 习题4-9Ø在窗口中使用定时器,每隔1秒,交替地用红色、绿色和蓝色的画刷来填充整个窗口客户区.l设置定时器(定时触发WM_TIMER消息)UINT SetTimer(HWND hWnd, //窗口句柄,指定定时器与窗口关联UINT nIDEvent, //定时器标识, 非0整数UINT uElapse, //时间间隔,单位毫秒TIMERPROC lpTimerFunc //指向WM_TIMER消息处理过程 //若为NULL,则消息入队); 函数调用成功,返回定时器标识,否则返回0.l释放定时器BOOL KillTimer(HWND hWnd, //与定时器相关联的窗口句柄UINT uIDEvent //定时器标识,指明释放哪个定时器); 源代码 如何显示动画效果?SetTimer()WM_TIMER消息WM_PAINT消息InvalidateRect()画图①②③④⑤ 例:正方形沿客户区边框顺时针方向移动左击时移动,右击时停止 源代码static UINT TimerID;HDC hdc;PAINTSTRUCT ps;static RECT rc;static LONG x1,x2,y1,y2, step;switch(message){ case WM_CREATE:GetClientRect(hWnd, &rc);x1 = 0; y1 = 0; x2 = 40; y2 = 40;step = (rc.right-rc.left)/200; break; case WM_LBUTTONDOWN:TimerID = SetTimer(hWnd, 1, 5, NULL); break; case WM_RBUTTONDOWN:KillTimer(hWnd,TimerID); break; case WM_TIMER:InvalidateRect(hWnd, NULL, true); break; case WM_PAINT:hdc = BeginPaint(hWnd, &ps);Rectangle(hdc, x1, y1, x2, y2);if(x2=rc.right && y2=rc.bottom) //下边界{ x1 = x1 - step; x2 = x2 - step; }if(x1<=rc.left) //左边界{ y1 = y1 -step; y2 = y2 - step; }EndPaint(hWnd, &ps); break; …… 第5章 文本的输出方法与字体的设置5.1 5.1 设置文本的设备环境设置文本的设备环境5.2 5.2 文本的输出过程文本的输出过程5.3 5.3 文本操作实例文本操作实例5.4 5.4 小结小结 文本输出l文本与图形没有明显的界限,某种意义上任何内容都可看成是图形实体.因此,可以使用GDI进行文本输出.l文本输出的关键问题1.字体的选择(系统提供的字体或用户自定义的字体)2.格式化文本3.将文本在窗口客户区画出来 字体l字体: 字符、符号构成的集合.l字体是一种图形对象.l同一种字体具有相同的设计风格.l不同的字体在大小、形态上有所不同.字体字体36号黑体36号楷体 获取字体l定义字体句柄HFONT hF;l获得字体句柄hF = (HFONT)GetStockObject(字体);字体说明ANSI_FIXED_FONT ANSI等宽字体ANSI_VAR_FONT ANSI变宽字体DEVICE_DEFAULT_FONT 与设备相关的字体DEFAULT_GUI_FONT 默认GUI字体OEM_FIXED_FONT OEM(原始设备制造商)提供的等宽字体SYSTEM_FONT系统字体,DC的默认值SYSTEM_FIXED_FONT系统等宽字体l除了系统提供的字体外,用户还能创建自定义字体.hF = CreateFont(...); 创建逻辑字体HFONT CreateFont(int nHeight, //字体高度int nWidth, //平均字符宽度int nEscapement, //行角度int nOrientation, //字符角度int fnWeight, //字体粗细DWORD fdwItalic, //是否倾斜DWORD fdwUnderline, //下划线标志DWORD fdwStrikeOut, //删除线标志 DWORD fdwCharSet, //字符集 DWORD fdwOutputPrecision, //输出精度DWORD fdwClipPrecision, //裁剪精度 DWORD fdwQuality, //输出质量DWORD fdwPitchAndFamily, //间距与字体系列 LPCTSTR lpszFace //指向字体名); 将字体选入设备环境HDC hdc;...SelectObject(hdc, hF);l系统提供的DC具有默认的SYSTEM_FONT,只有更改为其他字体或用户自定义的字体后,才应该将这种字体选入DC.l文本输出完成后,应该删除字体.DeleteObject(hF); 文本颜色、背景颜色l设置文本颜色COLORREF SetTextColor(HDC hdc,COLORREF crColor //文本颜色); l设置背景颜色COLORREF SetBkColor(HDC hdc,COLORREF crColor //背景颜色); 格式化文本 第5章 文本的输出方法与字体的设置5.1 5.1 设置文本的设备环境设置文本的设备环境5.2 5.2 文本的输出过程文本的输出过程5.3 5.3 文本操作实例文本操作实例5.4 5.4 小结小结 获取字体信息l正式输出文本之前,程序员可以获取当前正在使用的字体的信息,为后续工作做准备.l系统定义了一个TEXTMETRIC(文本度量,简称TM)结构,用于保存字体的基本信息.typedef struct tagTEXTMETRIC { //P106...} TEXTMETRIC;l获取字体信息BOOL GetTextMetrics(HDC hdc, //DC句柄LPTEXTMETRIC lptm //TEXTMETRIC类型指针); 将DC中的字体对象的信息填充到TEXTMETRIC中 TEXTMETRIC结构typedef struct tagTEXTMETRIC {LONG tmHeight; //字符高度LONG tmAscent;LONG tmDescent;LONG tmInternalLeading;LONG tmExternalLeading; //行距LONG tmAveCharWidth; //平均字符宽度LONG tmMaxCharWidth;LONG tmWeight;LONG tmOverhang;LONG tmDigitizedAspectX;LONG tmDigitizedAspectY;BCHAR tmFirstChar;BCHAR tmLastChar;BCHAR tmDefaultChar;BCHAR tmBreakChar;BYTE tmItalic;BYTE tmUnderlined;BYTE tmStruckOut;BYTE tmPitchAndFamily;BYTE tmCharSet;} TEXTMETRIC; 格式化文本l格式化文本包括对齐方式、字符间距、行距、字体颜色、背景颜色等.l进行文本输出时,程序员还需考虑待输出字符串的起始位置.而起始位置的计算可能与当前正在使用的字体信息以及与前次输出的字符串宽度、高度有关.l计算字符串的宽度和高度BOOL GetTextExtentPoint32(HDC hdc,LPCTSTR lpString, //字符指针,指向字符串int cbString, //选定的字符数LPSIZE lpSize //SIZE类型指针,计算的字符串宽度 //和高度存放在一个SIZE结构中); typedef struct tagSIZE {LONG cx;LONG cy;} SIZE; 文本输出l在指定位置输出字符串BOOL TextOut(HDC hdc,int nXStart, //起始x坐标 int nYStart, //起始y坐标LPCTSTR lpString, //字符指针,指向待输出的字符串int cbString //指定输出字符数 //输出整个串: lstrlen(lpString)); 例HDC hdc;PAINTSTRUCT ps;char* str1 = "这是我的第一个字符串";char* str2 = "第二个字符串";char* str3 = "这是我的第三个字符串";int x = 0, y = 0;TEXTMETRIC tm; //存放字体信息SIZE size; //存放字符串的宽度与高度switch(message){ case WM_PAINT: hdc = BeginPaint(hwnd, &ps); TextOut(hdc, x, y, str1, strlen(str1)); //输出第一个字符串 GetTextMetrics(hdc, &tm); //获取当前字体信息 y = y + tm.tmHeight + tm.tmExternalLeading; //字符高度+行距 TextOut(hdc, x, y, str2, strlen(str2)); //输出第二个字符串 //计算第二个串的宽度与高度 GetTextExtentPoint32(hdc, str2, strlen(str2), &size); x = x + size.cx + tm.tmAveCharWidth; TextOut(hdc, x, y, str3, strlen(str3)); //输出第三个字符串 EndPaint(hwnd, &ps); break; ... 第5章 文本的输出方法与字体的设置5.1 5.1 设置文本的设备环境设置文本的设备环境5.2 5.2 文本的输出过程文本的输出过程5.3 5.3 文本操作实例文本操作实例5.4 5.4 小结小结 例5-1字符高度+行距平均字符宽度TEXTMETRIC 例5-1源代码static long nXChar, nYChar;HDC hDC;short x;TEXTMETRIC tm; //存放字体信息short LnCount = 6;PAINTSTRUCT PtStr;static char* textbuf[] = {...};switch(message){ case WM_CREATE: hDC = GetDC(hWnd); GetTextMetrics(hDC, &tm); nXChar = tm.tmAveCharWidth; nYChar = tm.tmHeight + tm.tmExternalLeading; ReleaseDC(hWnd, hDC); break; case WM_PAINT: hDC = BeginPaint(hWnd, &PtStr); for(x=0; x= BufSize) //字符数>=数组长度 { MessageBox(...); break; } for(x = nNumChar; x > nArrayPos; x--) //空出脱字符位置准备插入新字符 cCharBuf[x] = cCharBuf[x-1]; cCharBuf[nArrayPos] = (unsigned char)wParam; //插入字符 nArrayPos++; //脱字符后移 nNumChar++; //字符数+1 InvalidateRect(hWnd, NULL, TRUE); } break;}待删除字符待插入位置 例6-1(续)case WM_CREATE: hDC = GetDC(hWnd); GetTextMetrics(hDC, &tm); nLnHeight = tm.tmHeight+tm.tmExternalLeading; nCharWidth = tm.tmAveCharWidth; ReleaseDC(hWnd, hDC); break; 例6-1(续)case WM_KEYDOWN:{ switch(wParam) { case VK_END: nArrayPos = nNumChar; break; case VK_HOME: nArrayPos = 0; break; case VK_DELETE: //向后删除,删除脱字符对应的字符 if(nArrayPos == nNumChar) //脱字符在串尾 MessageBox(...); else { for(x = nArrayPos; x < nNumChar; x++) cCharBuf[x] = cCharBuf[x+1]; nNumChar--; //字符数减1 InvalidateRect(hWnd, NULL, TRUE); } break; case VK_LEFT: //左移 if(nArrayPos>0) nArrayPos--; else MessageBox(...); break; case VK_RIGHT: //右移 if(nArrayPos < nNumChar) nArrayPos++; else MessageBox(...); break; }}break;待删除字符 例6-1(续)case WM_PAINT: hDC = BeginPaint(hWnd, &PtStr); TextOut(hDC, nCharWidth, nLnHeight, cCharBuf, nNumChar); EndPaint(hWnd, &PtStr); break;l例6-1是文本编辑器的简化版本,还需进一步完美.l一个稍完整的文本编辑器. 第第6 6章章 WindowsWindows应用程序对键盘与鼠标的响应应用程序对键盘与鼠标的响应6.1 6.1 键盘在应用程序中的应用键盘在应用程序中的应用6.2 6.2 键盘操作应用举例键盘操作应用举例6.3 6.3 鼠标在应用程序中的应用鼠标在应用程序中的应用6.4 6.4 鼠标应用程序实例鼠标应用程序实例6.5 6.5 小结小结 鼠标u鼠标是一种定位输入设备,通过鼠标单击、双击和拖动,方便用户操作.l单击: 按下并释放l双击: 短时间内的两次单击l拖动: 按下并移动u光标用来指示当前鼠标的位置,系统已预定义了一些光标(表6-4).lHCURSOR LoadCursor(HINSTANCE hInstance,LPCTSTR lpCursorName);l用户还可以通过图形编辑器自定义光标. 客户区(Client Area)鼠标消息(表6-5)消息说明WM_LBUTTONDOWN客户区内按下左键WM_LBUTTONUP客户区内释放左键WM_LBUTTONDBLCLK客户区内双击左键WM_MBUTTONDOWN客户区内按下中键WM_MBUTTONUP客户区内释放中键WM_MBUTTONDBLCLK客户区内双击中键WM_RBUTTONDOWN客户区内按下右键WM_RBUTTONUP客户区内释放右键WM_RBUTTONDBLCLK客户区内双击右键WM_MOUSEMOVE客户区内移动鼠标WM_MOUSEWHEEL鼠标滚轮转动WM_MOUSEACTIVATE在非活动窗口中按下鼠标WM_MOUSEHOVERMSDN Library没有这条消息!鼠标单击不一定是客户区 鼠标消息中的附加信息参数1.鼠标消息中的lParam参数坐标原点为窗口客户区的左上角.2.鼠标消息中的wParm: 各种虚键的状态信息.处理鼠标消息有时还要监控虚键是否被按下,从而扩充鼠标消息.MK_CONTROL : Ctrl键按下MK_LBUTTON : 鼠标左键按下MK_MBUTTON : 鼠标中键按下MK_RBUTTON : 鼠标右键按下MK_SHIFT : Shift键按下31~1615~0光标x坐标值光标y坐标值lWindows程序经常把鼠标键与Ctrl或Shift组合起来使用.l不同的鼠标消息,其wParm参数所包含的信息可能会不同.用法:x = LOWORD(lParam);y = HIWORD(lParam); 对鼠标消息的处理l监视Ctrl键和Shift键l不监视Ctrl键和Shift键case WM_LBUTTONDOWN: if( (wParam & MK_CONTROL) && (wParam & MK_Shift) ) ... break;case ...000100100...wParam000100000...MK_CONTROL000000100...MK_SHIFTcase WM_LBUTTONDOWN: ... break;case ... 鼠标左键按下并移动时绘图HDC hdc;POINT p;//调用MoveToEx函数会将原画笔位置存于该结构体变量中static int startX, startY, endX, endY;switch(message){ case WM_LBUTTONDOWN: startX = LOWORD(lParam); startY = HIWORD(lParam); break; case WM_MOUSEMOVE: if(wParam & MK_LBUTTON) //同时监视左键是否按下 { hdc = GetDC(hWnd); MoveToEx(hdc, startX, startY, &p); //设置画笔当前位置 endX = LOWORD(lParam); endY = HIWORD(lParam); LineTo(hdc, endX, endY); //画线 startX = endX; startY = endY; } break; …}画笔初始位置 关于鼠标双击lWindows系统默认的双击时间间隔为0.5秒.l可以调用SetDoubleClickTime()重新设置双击的时间间隔.BOOL SetDoubleClickTime(UINT uInterval //毫秒); l如果想要窗口处理函数能处理鼠标双击消息,必须在设计窗口类时使窗口类样式具有CS_DBLCLKS属性,否则系统将把双击视为两次单击.WNDCLASS wndclass;wndclass.style = CS_DBLCLKS | 其他属性; 非用户区鼠标消息用户区以外发生的鼠标事件(菜单、滚动条、工具栏、标题栏等)非用户区鼠标消息一般不由用户自己处理,而是由DefWindowProc处 理 鼠标捕获l鼠标并非为某个窗口专用,而是被屏幕和所有的窗口所共享.如果想要鼠标为某个窗口专用(这样无论鼠标在什么位置,鼠标消息都是针对该窗口的),则必须对鼠标加以捕获.HWND SetCapture(HWND hWnd // 即将捕获鼠标的窗口句柄);返回前一次鼠标捕获的窗口句柄.如果前面没有窗口捕获鼠标,返回NULL.l捕获的鼠标可以调用ReleaseCapture()来释放. 第第6 6章章 WindowsWindows应用程序对键盘与鼠标的响应应用程序对键盘与鼠标的响应6.1 6.1 键盘在应用程序中的应用键盘在应用程序中的应用6.2 6.2 键盘操作应用举例键盘操作应用举例6.3 6.3 鼠标在应用程序中的应用鼠标在应用程序中的应用6.4 6.4 鼠标应用程序实例鼠标应用程序实例6.5 6.5 小结小结 十字光标I字光标东西向箭头光标十字箭头光标沙漏光标西北-东南箭头光标西南-东北箭头光标向上箭头光标南北向箭头光标例6-2(0,0)case WM_MOUSEMOVE: x=LOWORD(lParam) y=HIWORD(lParam) if 鼠标移到大矩形区域内 {对不同的小区域设置不同的光标 } else {设置普通光标 } 例6-3LRESULT CALLBACK WndProc(...){ POINT pt; int i; char str[9] = "Hello VC"; static int x[8], y[8], color[8]; //字符位置和颜色 HDC hDC; PAINTSTRUCT ps; switch(iMessage) { case WM_CREATE: SetTimer(hWnd, 1, 40, NULL); //40ms触发一次WM_TIMER消息 for(i=0; i<8; i++) color[i]= 30*(i+1); break; case WM_TIMER: InvalidateRect(hWnd, NULL, TRUE); break; case WM_PAINT: hDC = BeginPaint(hWnd, &ps); GetCursorPos(&pt); //获得光标位置 x[0] = pt.x; y[0] = pt.y; for(i=1; i<8; i++) { x[i] = x[i-1] +50; y[i] = y[i-1]; } for(i=0; i<8; i++) { SetTextColor(hDC, RGB(255-color[i], color[i], 255)); TextOut(hDC, x[i], y[i], &str[i], 1); } color[0] = color[7]; for(i=7; i>0; i--) color[i] = color[i-1]; EndPaint(hWnd, &ps); return 0;使用定时器!获取光标位置(屏幕坐标系)BOOL GetCursorPos(LPPOINT lpPoint //Point类型指针); 例6-3改进LRESULT CALLBACK WndProc(...){ int i; char str[9] = "Hello VC"; static int x[8], y[8], color[8]; HDC hDC; PAINTSTRUCT ps; switch(iMessage) { case WM_CREATE: for(i=0; i<8; i++) color[i]= 30*(i+1); break; case WM_MOUSEMOVE: x[0] = LOWORD(lParam)+20; y[0] = HIWORD(lParam)+20; for(i=1; i<8; i++) { x[i] = x[i-1]+50; y[i] = y[i-1]; } InvalidateRect(hWnd, NULL, TRUE); case WM_PAINT: hDC = BeginPaint(hWnd, &ps); for(i=0; i<8; i++) { SetTextColor(hDC, RGB(255-color[i], color[i], 255)); TextOut(hDC, x[i], y[i], &str[i], 1); } color[0] = color[7]; for(i=7; i>0; i--) color[i] = color[i-1]; EndPaint(hWnd, &ps); return 0;不使用定时器! 第第7 7章章 资源在资源在WindowsWindows编程中的应用编程中的应用7.1 7.1 菜单和加速键资源及其应用菜单和加速键资源及其应用7.2 7.2 位图资源及其应用位图资源及其应用7.3 7.3 对话框资源及其应用对话框资源及其应用7.4 7.4 图标资源的应用图标资源的应用7.5 7.5 小结小结加速键√位图√图标√对话框√工具条字符串菜单√......资源 菜单分类1.系统菜单(控制菜单)l左击应用图标或右击标题栏.l由操作系统定义和管理.2.主菜单√3.快捷菜单菜单项命令菜单项打开子菜单的菜单项热键加速键分隔线选中标志 定义主菜单资源u菜单在资源描述文件(扩展名rc)中定义.menuID MENU [载入特性选项]{菜单定义...}lmenuID: 标识主菜单(栏)资源,可以是一个字符串,也可以是一个16-bit无符号整数值.l载入特性选项: 指明菜单资源的载入特性(表7-1).l菜单: 用POPUP关键字定义弹出式菜单.l注意: 1个菜单栏包含1个或多个菜单.BRGINEND 定义弹出式菜单POPUP “菜单名[(&字母)]” [,选项]{菜单项定义. . .} u(&字母)l定义菜单访问键(热键).u常用的选项lINACTIVE: 菜单处于非活动状态.lGRAYED: 菜单处于非活动状态,灰色显示.u用MENUITEM关键字定义菜单项.BRGINEND 定义菜单项、分隔线Ø定义菜单项MENUITEM “菜单项名[(&字母)]”, 菜单项ID [,选项]u(&字母)l定义菜单项的访问键(热键)u菜单项IDl符号常量(整数值).如果用户选择某个菜单项,一个整数将被送往菜单的属主(窗口).u常用的选项lCHECKED: 选中标志.lGRAYED: 菜单项处于非活动状态,灰色显示.lINACTIVE: 菜单项处于非活动状态.Ø定义分隔线MENUITEM SEPARATOR 习题7-7文件(F)打开(O)保存(S)另存为(A)—————退出(E)计算(S)计算总和(S)计算方差(D)计算均方差(T)帮助(H)计算总和帮助(S)计算方差帮助(D)计算均方差帮助(T)—————关于(A) 准备将它作为menuIDStep 1l实现例3-1l修改代码:wndclass.lpszMenuName = "My_Menu"; l新建资源脚本文件.Step 2 查看工程目录将发现多了2个文件 l在resource.h中定义菜单项ID.Step 3注意书写位置 l用记事本程序打开工程目录下的资源文件(.rc),定义菜单.Step 4定义菜单 Step 5 运行 加载并显示菜单的方法1.在窗口类中加载并显示菜单.2.在创建窗口时加载并显示菜单.3.动态加载并显示菜单.WNDCLASS wndclass;wndclass.lpszMenuName = “My_Menu”;HWND hwnd;HMENU hmenu;hmenu = LoadMenu(hInstance, “My_Menu”);hwnd = CreateWindow( , , , , , , , , hmenu, , );HWND hwnd;HMENU hmenu;hmenu = LoadMenu(hInstance, “My_Menu”);SetMenu(hwnd, hmenu);菜单(栏)资源标识 动态加载菜单示例l修改习题7-7,当鼠标左击窗口客户区时加载菜单.HMENU hmenu; //全局变量int WINAPI WinMain(...){ wndclass.lpszMenuName = NULL; ... hmenu = LoadMenu(hInstance, “My_Menu”); //消息循环前 ...}LRESULT CALLBACK WndProc(...){ switch(message) { case WM_LBUTTONDOWN: SetMenu(hwnd, hmenu); break; ...} 对菜单项的操作l定义菜单时可以在资源描述文件中设置某个菜单项的初始状态.MENUITEM “菜单名[(&字母)]”, 菜单项ID [,选项]l调用EnableMenuItem函数可以改变菜单项的状态.BOOL EnableMenuItem(HMENU hMenu, //菜单句柄UINT uIDEnableItem, //菜单项标识UINT uEnable //菜单项操作标志); 菜单项操作标志说明MF_BYCOMMAND 以菜单项ID标识菜单项(默认)MF_BYPOSITION 以菜单项所处的位置标识菜单项MF_DISABLEDdisabled, but not grayedMF_ENABLED enabledMF_GRAYEDdisabled and grayed组合时按位或 对菜单项的操作(续)l调用CheckMenuItem函数可以设置或取消菜单项的选中标志;函数返回菜单项的前次状态(MF_CHECKED或MF_UNCHECKED). 菜单项标志说明MF_BYCOMMAND 以菜单项ID标识菜单项(默认)MF_BYPOSITION 以菜单项所处的位置标识菜单项MF_CHECKED 添加选中标志MF_UNCHECKED去除选中标志l其他菜单项操作包括增加菜单项、插入菜单项、删除菜单项、修改菜单项.DWORD CheckMenuItem(HMENU hmenu, //菜单句柄UINT uIDCheckItem, //菜单项标识,指明是哪个菜单项UINT uCheck //菜单项标志);组合时按位或 WM_COMMAND消息l当用户选择一个命令菜单项,系统将直接发送命令消息到(菜单所在的)窗口处理过程,也就是说命令消息是不入队消息.l若用户选择系统菜单(控制菜单)中的命令项,系统发送WM_SYSCOMMAND消息.l若用户选择的是非系统菜单(主菜单、快捷菜单)中的命令项,则系统发送WM_COMMAND消息.lWM_COMMAND消息中的wParam参数:菜单项、控件或加速键的标识用法: LOWORD(wParam)消息来自控件时为通知码;消息来自加速键时为1;消息来自命令菜单项时为0.用法: HIWORD(wParam) WM_COMMAND示例lStep 1: 实现例3-1lStep 2: 新建资源脚本文件lStep 3: 在resource.h中定义菜单项ID#define IDM_C 10#define IDM_E 11lStep 4: 用记事本打开工程目录下的资源文件(.rc),并定义如下菜单:My_Menu MENU DISCARDABLE{ POPUP "绘图(&D)" { MENUITEM "圆(&C)", IDM_C MENUITEM "椭圆(&E)", IDM_E }} Step 5: 修改源代码#include “resource.h” //定义有菜单项IDHMENU hmenu;int WINAPI WinMain(...){ ... hmenu = LoadMenu(hInstance, "My_Menu"); hwnd=CreateWindow( , , , , , , , , hmenu, , ); ...}LRESULT CALLBACK WndProc(...){ static DWORD itemC, itemE; //菜单项的选中状态标志 HDC hdc; PAINTSTRUCT ps; 以下是消息处理;} 消息处理的基本框架switch(message){ case WM_COMMAND: ...; break; case WM_PAINT: ...; break; case WM_DESTROY: PostQuitMessage(0); default: return DefWindowProc(hwnd, message, wParam, lParam);} 处理WM_COMMAND消息case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_C: if(itemC==MF_UNCHECKED) { CheckMenuItem(hmenu, IDM_C, MF_CHECKED); itemC = MF_CHECKED; } else { CheckMenuItem(hmenu, IDM_C, MF_UNCHECKED); itemC = MF_UNCHECKED; } InvalidateRect(hwnd, NULL, 1); break; case IDM_E: if(itemE==MF_UNCHECKED) { CheckMenuItem(hmenu, IDM_E, MF_CHECKED); itemE = MF_CHECKED; } else { CheckMenuItem(hmenu, IDM_E, MF_UNCHECKED); itemE = MF_UNCHECKED; } InvalidateRect(hwnd, NULL, 1); break; } break; 处理WM_PAINT消息case WM_PAINT: hdc = BeginPaint(hwnd, &ps); if(itemC == MF_CHECKED) Ellipse(hdc, 50, 50, 150, 150); if(itemE == MF_CHECKED) Ellipse(hdc, 200, 50, 250, 150); EndPaint(hwnd, &ps); break; 加速键l加速键: 对常用的命令提供直接的按键访问方式.alt+f4: 关闭应用或窗口f1: 帮助alt+print screen: 拷贝活动窗口到剪贴板ctrl+esc: 打开开始菜单.l加速键通常与某个菜单项紧密联系,使用户能够以更快捷的方式选择所要执行的命令.按键或组合键加速键与菜单访问键(热键)的区别:1.加速键不带下划线2.使用加速键时不需要激活菜单 使用加速键资源的一般步骤1.在资源描述文件中定义加速键资源(创建加速键表).2.加载加速键资源.调用LoadAccelerators函数加载加速键表资源,获取加速键表句柄.3.翻译加速键.消息循环中增加TranslateAccelerator函数.4.处理WM_COMMAND/WM_SYSCOMMAND消息. 1. 在资源描述文件中定义加速键资源加速键表名 ACCELERATORS{事件, 加速键ID, [类型] [选项]. . .} l事件: 指明加速键使用的按键.1.“字符”,例如“C”2.“^字符”,例如“^C”表示ctrl+C3.ASCII码,例如65表示shift a4.虚拟键码,例如VK_F1表示F1l加速键ID: 加速键标识(16-bit unsigned整数) l类型: 只能用于下面两种情况:1.65, IDR_A, ASCII2.VK_F1, IDR_F1, VIRTKEY l选项: 一个或多个选项值.1.NOINVERT: 使用加速键时菜单不会加亮显示2.ALT: 激活加速键要先按下alt键3.SHIFT: 激活加速键要先按下shift键4.CONTROL: 激活加速键要先按下ctrl键 只对虚拟键码有效 定义加速键资源示例My_Acc ACCELERATORS{ "^C", IDR_C //ctrl C “K”, IDR_K //shift k 98, IDR_b, ASCII //b "G", IDR_G //shift g VK_F1, IDR_F1, VIRTKEY //F1 VK_F1, IDR_CF1, CONTROL, VIRTKEY //ctrl F1 VK_F1, IDR_SF1, SHIFT, VIRTKEY //shift F1 VK_F1, IDR_AF1, ALT, VIRTKEY //alt F1 VK_F2, IDR_ASF2, ALT, SHIFT, VIRTKEY //alt shift F2 VK_F2, IDR_CSF2, CONTROL, SHIFT, VIRTKEY //ctrl shift F2 VK_F2, IDR_ACF2, ALT, CONTROL, VIRTKEY //alt ctrl F2} 2. 加载加速键资源HACCEL LoadAccelerators(HINSTANCE hInstance, //应用实例句柄LPCTSTR lpTableName //字符指针,指向一个字符串常量 //实参即为“加速键表名”); l函数调用成功,返回加载的加速键表句柄,否则返回NULL.l函数调用位置: 创建窗口之后,产生消息循环前(P147例7-1).HACCEL hAccel;UpdateWindow(...);hAccel = LoadAccelerators(hInstance, “My_Acc”);while(GetMessage(...)){ ... } 3. 翻译加速键l按下加速键时触发的是按键消息,而用户选择命令菜单项时触发的是命令消息.l在消息循环中增加对TranslateAccelerator函数的调用,可以将由加速键产生的按键消息转换为命令消息.TranslateAccelerator消息队列窗口处理加速键表按键消息命令消息int TranslateAccelerator(HWND hWnd, //窗口句柄HACCEL hAccTable, //加速键表句柄LPMSG lpMsg //MSG类型指针); 若函数调用成功,返回一个非0值. 翻译加速键(续)while(GetMessage(&Msg, NULL, 0, 0)){ if(!TranslateAccelerator(hwnd, hAccel, &Msg)) { TranslateMessage(&Msg); DispatchMessage(&Msg); }} 由加速键触发的按键消息转换成命令消息后将直接送往窗口处理过程 加速键示例1.Step 1: 实现WM_COMMAND示例2.Step 2: 在resource.h中定义加速键ID#define IDM_C 10#define IDM_E 11#define IDR_HELP 123.Step 3: 用记事本打开工程目录下的资源文件(.rc),修改菜单资源,补充定义加速键资源:My_Menu MENU DISCARDABLE{POPUP “绘图(&D) ”{MENUITEM “圆(&C)\t Ctrl+A", IDM_CMENUITEM "椭圆(&E)\t Ctrl+B", IDM_E}}My_Acc ACCELERATORS{"^A", IDM_C"^B", IDM_EVK_F1, IDR_HELP, VIRTKEY}黑色为原有的红色为新增的黑色为原有的红色为新增的 Step 4: 修改源代码HACCEL haccel;int WINAPI WinMain(...){ ... haccel = LoadAccelerators(hInstance, "My_Acc"); while(GetMessage(&Msg, NULL, 0,0)) { if(!TranslateAccelerator(hwnd, haccel, &Msg)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } } ... Step 4: 修改源代码(续)case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_C: ...; break; case IDM_E: ...; break; case IDR_HELP: MessageBox(hwnd, "加速键F1", "Help", MB_OK); }由于加速键ID与菜单项ID相同,不必再对加速键进行额外处理.加速键F1没有对应的命令菜单项u7.1节其他问题: 菜单的动态创建、例7-1,自学! 第第7 7章章 资源在资源在WindowsWindows编程中的应用编程中的应用7.1 7.1 菜单和加速键资源及其应用菜单和加速键资源及其应用7.2 7.2 位图资源及其应用位图资源及其应用7.3 7.3 对话框资源及其应用对话框资源及其应用7.4 7.4 图标资源的应用图标资源的应用7.5 7.5 小结小结 基本概念u位图(GDI对象)是一种数字化的图形表示形式,位图中的每个像素点由位图文件中的一位或多位数据表示.整个位图的信息被细化为每个像素点的属性值.l将一幅图片分成许许多多像素点,例如800×600.l每个像素点用一个或多个字节来描述颜色.例如,256色需一个字节,32位真彩色则需4个字节,其中3个字节分别表示红、绿、蓝. 在资源描述文件中定义位图资源l位图资源标识: 标识符或整数值.l文件名: 资源所在的文件,若文件不在当前目录,需指明路径.例如, pic7 BITMAP d:\xxx.bmp位图资源标识 BITMAP 文件名 加载位图资源1.定义位图句柄.HBITMAP hBm;2.加载位图资源,并获得位图句柄.HBITMAP LoadBitmap(HINSTANCE hInstance, //应用实例句柄LPCTSTR lpBitmapName //字符指针,指向字符串常量 //实参即为“位图资源标识”);函数调用成功返回加载的位图句柄,否则返回NULL.hBm = LoadBitmap(hInstance, “pic7”); l如果没有可用的位图资源或应用程序想要创建位图,则可调用函数来创建与指定设备兼容的位图.HBITMAP CreateCompatibleBitmap(HDC hdc,//DC句柄int nWidth,//位图宽度(像素)int nHeight//位图高度(像素)); 创建内存设备环境l由于位图的数据量大,为了提高显示刷新速度,对位图的操作必须内存中进行.l如果将内存视为一种特殊的虚拟设备,则对应的设备环境称为内存设备环境.l调用CreateCompatibleDC函数可以创建一个与指定设备兼容的内存设备环境. 创建内存设备环境HDC CreateCompatibleDC(HDC hdc //现有的设备环境句柄); 函数调用成功返回一个内存设备环境句柄,否则返回NULL.HDC hdc;HDC hdcmem;hdc = GetDC(...); //GetDCEx(...), BeginPaint(...)hdcmem = CreateCompatibleDC(hdc); 将位图对象选入内存设备环境HGDIOBJ SelectObject(HDC hdc,HGDIOBJ hgdiobj );l用法: SelectObject(hdcmem, hBm);l注意: 位图是一种GDI对象 位图输出l调用BitBlt函数将内存设备环境中的位图输出到指定设备上.BOOL BitBlt(HDC hdcDest, //目标设备环境句柄int nXDest, //待输出位图的左上角在目标区域的x坐标int nYDest, //待输出位图的左上角在目标区域的y坐标int nWidth, //目标区域用于显示位图的宽度int nHeight, //目标区域用于显示位图的高度HDC hdcSrc, //源设备环境句柄int nXSrc, //位图左上角在源设备环境中的x坐标int nYSrc, //位图左上角在源设备环境中的y坐标DWORD dwRop //光栅操作代码(表7-5)); l目标区域用于显示位图的宽度、高度往往与位图的实际宽度、高度相同,因此需要一种方法来获取位图的有关信息. 获取位图的信息l获取指定的图形对象信息int GetObject(HGDIOBJ hgdiobj, //图形对象句柄int cbBuffer, //指定写入到缓冲区中信息的字节数LPVOID lpvObject //void类型指针);调用成功返回存储在缓冲区中的字节数,否则返回0.l对于位图对象,函数调用的形式为:BITMAP bm; //准备将位图信息存放到bm中GetObject(hBm, sizeof(BITMAP), (LPVOID)&bm);typedef struct tagBITMAP {LONG bmType; //位图类型,值必须是0LONG bmWidth; //位图宽度LONG bmHeight; //位图高度...} BITMAP; 位图操作的一般流程定义位图资源加载位图获取设备环境获取内存设备环境创建位图将位图选入内存设备环境位图操作输出 例7-2l找一幅位图(.bmp),并在资源描述文件中定义位图资源.l编写例7-2代码. 第第7 7章章 资源在资源在WindowsWindows编程中的应用编程中的应用7.1 7.1 菜单和加速键资源及其应用菜单和加速键资源及其应用7.2 7.2 位图资源及其应用位图资源及其应用7.3 7.3 对话框资源及其应用对话框资源及其应用7.4 7.4 图标资源的应用图标资源的应用7.5 7.5 小结小结 对话框l对话框是由应用程序创建的临时窗口,通常对话框包括一个或多个控件.l对话框的功能(P156)1.接收输入2.提供附加信息“打开”对话框“关于”对话框Message Box Win32 API提供两类对话框1.模态对话框l一旦创建了模态对话框,该对话框总是处于活动状态,直到对话框处理过程调用EndDialog函数或系统激活了另一个应用程序窗口为止.例如,PowerPoint的“打开”对话框是模态对话框.l调用MessageBox函数产生的消息框也是一种模态对话框. 2.非模态对话框l创建非模态对话框后,用户可以在窗口、对话框之间来回切换.例如,PowerPoint的“查找”对话框是非模态对话框. 可以使用表3-5、表7-6中样式或样式组合(按位或)对话框在屏幕中的位置对话框的尺寸在资源描述文件中定义对话框资源对话框资源标识 DIALOG x, y, width, height [选项]{ 控件定义 . . .} l定义对话框时可带0个或多个选项1.CAPTION “标题”2.FONT 大小, “字体类型”3.STYLE 样式4.... 例7-3定义的对话框资源About DIALOG 10, 10, 100, 50STYLE WS_POPUP | WS_CAPTION | WS_SYSMENUCAPTION “关于”FONT 18, “楷体”{ ...}l推荐的模态对话框“样式”STYLE WS_POPUP | WS_SYSMENU | WS_CAPTION | DS_MODALFRAMEl推荐的非模态对话框“样式”STYLE WS_POPUP | WS_CAPTION | WS_BORDER | WS_SYSMENU | WS_VISIBLE 对话框中常用的控件(表7-7)复选框组合框列表框单选按钮编辑框组框文本框 定义对话框中控件示例ErrorDialog DIALOG 10, 10, 300, 110STYLE WS_POPUP | WS_BORDERCAPTION "Error!"{ CTEXT "Select One:", 1, 10, 10, 280, 12 PUSHBUTTON "Retry", 2, 75, 30, 60, 12 PUSHBUTTON "Abort", 3, 75, 50, 60, 12 PUSHBUTTON "Ignore", 4, 75, 80, 60, 12} 控件文本控件IDx,y,width,height 创建对话框l创建模态对话框(创建后自动显示)int DialogBox(HINSTANCE hInstance, //应用实例句柄LPCTSTR lpTemplate, //对话框资源名HWND hWndParent, //属主窗口句柄DLGPROC lpDialogFunc //对话框消息处理函数名); 函数调用失败,返回-1.l创建非模态对话框(若对话框“样式”选项含有WS_VISIBLE,则创建后显示)HWND CreateDialog(HINSTANCE hInstance, //应用实例句柄LPCTSTR lpTemplate, //对话框资源名HWND hWndParent, //属主窗口句柄DLGPROC lpDialogFunc //对话框消息处理函数名);函数调用成功,返回对话框句柄;否则返回NULL. 对话框消息处理函数l对话框消息处理与窗口消息处理类似.BOOL CALLBACK DlgProc(HWND hwndDlg, //对话框(窗口)句柄UINT message, WPARAM wParam, LPARAM lParam){switch (message){case WM_INITDIALOG: ...; return TRUE;case WM_COMMAND: ...; return TRUE;case WM_CLOSE: ...; return TRUE;default: return FALSE;} }l与窗口处理的不同之处1.函数返回值不同: BOOL而不是LRESULT.2.对话框不必处理WM_PAINT、WM_DESTROY、WM_CREATE消息,一般只需处理WM_INITDIALOG消息和WM_COMMAND消息. 3.对话框消息处理不会调用DefWindowProc函数.若对某个消息做了处理,返回TRUE.对未处理的消息,返回FALSE. 对话框创建后、显示之前系统产生的消息命令菜单项、加速键或由控件触发的消息 关闭对话框l关闭模态对话框BOOL EndDialog(HWND hDlg, //对话框句柄int nResult //指定一个值返回给DialogBox函数的 //主调函数 );l关闭非模态对话框BOOL DestroyWindow(HWND hWnd //窗口句柄或对话框句柄);该函数既可关闭窗口,也可关闭非模态对话框 模态对话框编程(例7-3)l在resource.h中定义菜单项ID和加速键ID#define IDM_OPEN 11#define IDM_SAVE 13#define IDM_EXIT 15#define IDM_ABOUT 20 在资源描述文件中定义资源Menu MENU DISCARDABLE{POPUP "文件(&F)"{MENUITEM "打开(&O)\t Ctrl+O", IDM_OPENMENUITEM SEPARATORMENUITEM "保存(&S)\t Ctrl+S", IDM_SAVEMENUITEM SEPARATORMENUITEM "退出(&X)", IDM_EXIT}POPUP "帮助(&H)"{MENUITEM "关于(&A)...", IDM_ABOUT}}Menu ACCELERATORS{"^O", IDM_OPEN"^S", IDM_SAVE}About DIALOG 10, 10, 100, 50STYLE WS_POPUP | WS_CAPTION | WS_SYSMENUCAPTION "关于" FONT 18, "楷体"{CTEXT "Windows模态对话框", -1, 13, 10, 80, 10DEFPUSHBUTTON "确定", IDOK, 35, 30, 30, 12}#define IDOK 1菜单加速键对话框 入口函数WinMain()#include#include "resource.h"HINSTANCE hInst;int WINAPI WinMain(...){HACCEL hAccel;...wndclass.lpszMenuName = "Menu";...hInst = hInstance;hAccel = LoadAccelerators(hInst, "Menu");while(GetMessage(&Msg, NULL, 0,0)){if(!TranslateAccelerator(hwnd, hAccel, &Msg)){TranslateMessage(&Msg);DispatchMessage(&Msg);}}return Msg.wParam;} 窗口消息处理LRESULT CALLBACK WndProc(...){ switch(message) { case WM_COMMAND: switch(LOWORD(wParam)) { case IDM_OPEN: MessageBox(hwnd, "文件已经打开!", "文件打开", MB_OK); break; case IDM_SAVE: MessageBox(hwnd, "文件保存成功!", "文件保存", MB_OK); break; case IDM_EXIT: SendMessage(hwnd, WM_DESTROY, 0, 0); break; case IDM_ABOUT: DialogBox(hInst, "About", hwnd, DlgProc); break; } break; ...} l一旦创建了模态对话框,该对话框总是处于活动状态lMessageBox是一种特殊的模态对话框(P158) SendMessage函数l发送指定的消息给目标窗口LRESULT SendMessage(HWND hWnd, //目标窗口句柄句柄UINT Msg, //消息标识WPARAM wParam,LPARAM lParam); About对话框消息处理BOOL CALLBACK DlgProc(...){switch(message){case WM_INITDIALOG: //对话框显示前产生return 1;case WM_COMMAND:switch(LOWORD(wParam)){case IDOK:EndDialog(hdlg, 0);return 1;}break;case WM_CLOSE: //关闭窗口时产生EndDialog(hdlg, 0);return 1;default:return 0;}return 0;}关闭模态对话框后,窗口又恢复为活动状态 l由于非模态对话框并不禁止应用程序向其他窗口发送消息,因此,在WinMain函数的消息循环中必须截获发往非模态对话框的消息,并将其发往相应的对话框处理函数进行处理.其消息循环过程的一般形式为:while(GetMessage(&Msg, NULL, 0, 0)){ if(! IsDialogMessage(hdlg, &Msg) ) { if(!TranslateAccelerator(hwnd, hAccel, &Msg)) { TranslateMessage(&Msg); DispatchMessage(&Msg); } }}l其它与模态对话框编程不同之处: 创建、关闭对话框和WS_VISIBLE(对话框样式).l注意: 对于模态对话框,一旦它创建后,系统将挂起所有外部的消息,只响应对话框内部的消息,直到该对话框关闭为止.随后,系统将控制权返回给模态对话框创建前的线程.非模态对话框编程(例7-4)BOOL IsDialogMessage(HWND hDlg, //对话框句柄LPMSG lpMsg //MSG类型指针)若为对话框消息,返回真,否则返回假. 第第7 7章章 资源在资源在WindowsWindows编程中的应用编程中的应用7.1 7.1 菜单和加速键资源及其应用菜单和加速键资源及其应用7.2 7.2 位图资源及其应用位图资源及其应用7.3 7.3 对话框资源及其应用对话框资源及其应用7.4 7.4 图标资源的应用图标资源的应用7.5 7.5 小结小结 图标l图标是一个特殊的最小位图(.ico).l系统用图标来表现对象(文件、目录、快捷方式、应用程序).l更改图标后,标题栏上的图标、程序最小化、程序文件均呈现该图标.l例7-51.找一个图标(.ico),并在资源描述文件中定义图标资源My_Icon ICON d:\myico.ico2.编写例7-5代码wndclass.hIcon=LoadIcon( hInstance, "My_Icon" );如果为NULL,标题栏上仍采用标准图标 第8章 MFC基础知识8.1 MFC8.1 MFC概述概述8.2 MFC8.2 MFC类的组织结构及主要的类的简介类的组织结构及主要的类的简介8.3 MFC8.3 MFC中的全局函数与全局变量中的全局函数与全局变量8.4 8.4 应用程序向导应用程序向导8.5 8.5 小结小结 MFC概述u微软将大部分API函数和Windows控件重新组织 成 类 ,构 成 Microsoft Foundation Class(MFC) Library.uMFC Library是一个应用程序框架,提供了编程所需要的大部分代码,程序员要做的工作只是向该框架添加、扩充或重写相应的代码. 第一个MFC程序 第一个MFC程序(续) 第一个MFC程序(续) 第8章 MFC基础知识8.1 MFC8.1 MFC概述概述8.2 MFC8.2 MFC类的组织结构及主要的类的简介类的组织结构及主要的类的简介8.3 MFC8.3 MFC中的全局函数与全局变量中的全局函数与全局变量8.4 8.4 应用程序向导应用程序向导8.5 8.5 小结小结 MFC类的组织结构lMFC编程关键是要了解MFC类的组织结构. 根类lCObject类是MFC的抽象基类,是大多数MFC类和用户自定义类的根类.lCObject类提供四种基本服务:1.串行化支持l能够在存储介质上写入对象的当前状态(成员变量的值)……串行化.l通过读取存储介质上的对象状态来重建对象.2.运行时类信息l指示一个对象是否属于(或继承于)某个特定的类,确定类的运行时信息(类名、基类名等). 3.对象诊断输出l检验对象的完整性.4.兼容集合类l数组类(CArray)、列表类(CList)、映射类(CMap).含有纯虚函数的类不能创建抽象类对象 CObject类成员构造/拷贝构造函数运算符重载对象诊断输出串行化支持运行时类信息 应用程序体系结构类1.应用程序类和线程支持类lCWinApp: 应用程序对象的基类,一个应用程序有且只有一个应用程序对象.lCWinThread: MFC支持多线程,任何应用至少有一个主线程,CWinThread是所有线程的基类.2.命令相关类(CCmdTarget)l具有消息映射属性的基类.消息映射是指发送命令或消息至相应的成员函数(处理消息).3.文档类(CDocumwnt)l文档对象负责管理应用程序使用的数据,它由文档模板对象创建.4.视图(CView)l视图是一个子窗口(框架窗口中的客户区),用于显示和处理文档对象中的数据.5.框架窗口(CFrameWnd)l含有视图窗口的窗口.6.文档模板类(CDocTemplate)l文档模板对象协调文档、视图和框架窗口对象的创建. 类的组织结构CObjectCCmdTargetCWinThreadCWinAppCDocumwntCWndCViewCFrameWndCDocTemplate 文档/视图结构lMFC支持文档/视图结构,目的是要将数据本身与数据的显示以及用户对数据的操作分离开.数据的存储、加载和管理由文档类来完成,数据的显示与用户对数据的操作由视图类来完成,视图在文档与用户之间起到一个中介的作用. CWinApp类l几 乎 所 有 的 基 于 MFC的 应 用 程 序 都 是 从CWinApp派生一个类,并通过创建这个派生类对象来创建一个应用程序对象.lCWinApp定义了一些数据成员(表8-1)和成员函数(表8-2),还有一些成员是从基类继承过来的.CWinAppCMyApp应用程序对象 Hierarchy Chart Categoriesl更详细的类的组织结构查看: Hierarchy Chart 第8章 MFC基础知识8.1 MFC8.1 MFC概述概述8.2 MFC8.2 MFC类的组织结构及主要的类的简介类的组织结构及主要的类的简介8.3 MFC8.3 MFC中的全局函数与全局变量中的全局函数与全局变量8.4 8.4 应用程序向导应用程序向导8.5 8.5 小结小结 部分全局函数(表8-6)函数名功能AfxAbort无条件终止一个应用程序AfxBeginThread创建一个新线程并执行它AfxEndThread终止当前正在执行的线程AfxFormatString格式化字符串AfxMessageBox显示一个Windows消息框AfxGetApp返回当前应用程序对象的指针AfxGetInstanceHandle返回标识当前应用程序对象的句柄AfxRegisterWndClass注册用于创建Windows窗口的窗口类 第8章 MFC基础知识8.1 MFC8.1 MFC概述概述8.2 MFC8.2 MFC类的组织结构及主要的类的简介类的组织结构及主要的类的简介8.3 MFC8.3 MFC中的全局函数与全局变量中的全局函数与全局变量( (表表8-6)8-6)8.4 8.4 应用程序向导应用程序向导8.5 8.5 小结小结 MFC AppWizard(exe) Step 1SDI应用(如记事本)只允许打开一个文档MDI应用(如Word)允许同时打开多个文档确定应用程序是否支持MFC的文档/视图结构,如果不选择该项,则应用程序不能从磁盘文件中打开文档资源文件使用什么语言 Step 2 Step 3An OLE 2.0-style document containerAn OLE server that cannot run as a standalone programAn OLE server that can also run as a standalone programlActive document: Active文档可能是多页的,并且可以在整个客户区内显示.lOLE(对象链接与嵌入): 微软的一种基于对象的技术,它可以用于处理复合文档. Step 4 Step 5 Step 6 运行情况 API & MFCWinMain( )安装目录\VC98\MFC\SRCAPPMODUL.CPP: _tWinMain( )WINMAIN.CPP: AfxWinMain( )消息循环CWinApp::Run( ) WndProc( )CWnd::WindowProc( )CWnd::DefWindowProc( ) MFC向导创建的类CAboutDlgCChildFrameCMainFrameCTestAppCTestDocCTestView应用程序对象CTestApp theApp; 第9章 Windows标准控件在可视化编程中的应用9.1 9.1 概述概述9.29.2 按钮控件及其应用按钮控件及其应用9.39.3 滚动条控件滚动条控件9.49.4 静态控件静态控件9.59.5 列表框控件列表框控件9.69.6 编辑框控件编辑框控件9.79.7 组合框控件组合框控件9.89.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 概述lMFC中所有的控件类都是CWnd类的子类,因此,控件实际上是一个(is a)窗口.lWindows程序中的控件通常出现在对话框和工具栏中.l利用MFC AppWizard(exe)创建一个Dialog based应用程序,将呈现如下界面:Controls Toolbar Controls Toolbar上的基本控件图像控件(Picture)静态文本框(Static Text)编辑框(Edit Box)组框(Group Box)按钮(Button)复选框(Check Box)单选按钮(Radio Button)组合框(Combo Box)列表框(List Box)水平滚动条(Horizontal Scroll Bar)垂直滚动条(Vertical Scroll Bar)上下/左右控件(Spin)进度条(Progress)滑动条(Slider)热键(Hot Key)列表控件(List Control)树视图控件(Tree Control)标签控件(Tab Control)动画控件(Animate)富文本编辑框(Rich Edit)日期和时间提取控件(Date Time Picker)月历控件(Month Calendar)IP地址控件(IP Address)自定义控件(Custom Control)扩展的组合框(Extended Combo Box) MFC向导创建的类C工程名APPCAboutDlgC工程名Dlg基于对话框的应用程序中,由MFC自动生成的类 常用控件及对应的控件类(表9-1)控件控件类名说明按钮CButton响应用户输入,触发相应事件单选按钮CButton从多个选项中选中一项复选框CButton用作选择标记组框CButton带文字的方框,将一些相关的控件组织在一起组合框CCombBox一个编辑框和一个列表框的组合编辑框CEdit输入并编辑正文,支持单行和多行编辑列表框CListBox显示一个列表,用户可以从该列表中选择一项或多项滚动条CScrollBar静态文本框CStatic显示文本,一般不能接受输入信息 MFC消息分类1.Windows消息lWM_***,以WM_开头的消息.lWM_COMMAND除外.2.控件通知消息: WM_COMMANDl由控件或其它子窗口发送给父窗口的消息.3.命令消息: WM_COMMANDl由用户接口对象(菜单, 加速键, 工具栏按钮)发出的消息.CWnd派生类对象处理消息各种对象都可以处理这类消息,包括文档、文档模板、应用程序及CWnd派生类对象 WM_COMMAND消息中的wParam参数菜单项/加速键/控件的标识若为控件通知消息,存放的是通知代码(表9-2)若为命令消息,加速键为1,命令菜单项为0.WM_COMMAND消息中的wParam参数 控件与窗口之间的消息传递l控件可以向其父窗口发送控件通知消息(WM_COMMAND).l父窗口或其它窗口也可以向控件发送控件消息.应用程序通过调用SnedMessage或SendDlgItemMessage函数向控件发送各种消息.LRESULT SendDlgItemMessage(HWND hDlg, //对话框句柄 int nID, //控件IDUINT message, //消息号WPARAM wParam,LPARAM lParam);父窗口控件其它窗口控件通知消息控件消息LRESULT SendMessage(HWND hWnd, //目标窗口句柄UINT Msg, //消息号WPARAM wParam,LPARAM lParam); 此处为API函数,CWnd类还有相应的成员函数 第第9 9章章 WindowsWindows标准控件在可视化编程中的应用标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 CButton类CButton(): 构造函数Create(): 创建按钮控件GetState(): 获取按钮的当前状态SetState(): 设置按钮状态GetCheck(): 获取按钮的check状态SetCheck(): 设置按钮的check状态GetButtonStyle(): 获取按钮样式SetButtonStyle(): 设置按钮样式GetIcon(): 获取图标句柄SetIcon(): 设置按钮上显示的图标GetBitmap(): 获取位图句柄SetBitmap(): 设置按钮上显示的位图GetCursor(): 获取光标句柄SetCursor(): 设置在按钮上显示的光标DrawItem(): 属主绘画按钮还有一些成员是从基类继承过来的 创建按钮控件BOOL Create(LPCTSTR lpszCaption, //字符指针,captionDWORD dwStyle, //按钮样式(表9-3)const RECT& rect, //按钮大小与位置,矩形结构或矩形对象CWnd* pParentWnd, //指向父窗口,通常为对话框,不能为NULLUINT nID //按钮控件ID);CButtonCButtonObj构造函数Create()IDE创建按钮控件是一件很简单的事 按钮控件的通知码l当用户操作某个控件时(如单击按钮),拥有此控件的父窗口将会收到该控件发来的控件通知消息(WM_COMMAND),其中wParam参数的高16位含有控件的通知代码.l按钮控件(普通按钮、单选按钮、复选框)的通知代码:1.BN_CLICKED: 单击按钮2.BN_DOUBLECLICKED: 双击按钮lMFC在处理控件消息的问题上做了极大地简化,只需利用ClassWizard将控件通知代码映射到成员函数中,然后在成员函数中编程即可. MFC消息映射机制u控件IDl编辑框ID: IDC_EDIT1l按钮ID: IDC_BUTTON1u对话框类名: C工程名Dlg,本例为CMFCDlgu要求: 单击按钮,在编辑框中显示Hello World!l单击按钮后对话框将收到控件通知消息,利用类向导将通知代码BN_CLICKED映射为CMFCDlg类的成员函数OnButton1(),该成员函数处理单击按钮事件.消息映射表映射条目通知码ON_IDC_BUTTON1BN_CLICKED在CMFCDlg类中增加成员函数:void MFCDlg::OnButton1(){ //单击按钮的消息处理}ClassWizard Step 1l新建一个MFC AppWizard工程,工程名为MFCl选择工程类型为Dialog basedl设计如下对话框:IDC_EDIT1IDC_BUTTON1控件ID Step 2l利用MFC ClassWizard在CMFCDlg类中增加成员函数 Step 3l利用MFC ClassWizard在CMFCDlg类中增加成员变量 Step 4l查看CMFCDlg类,编写消息处理代码编辑框控件对象单击按钮的消息处理函数双击后将自动转到MFCDlg.cpp的相应位置void CMFCDlg::OnButton1() { // TODO: Add your control notification handler code here m_edit.SetSel(0, -1); //在编辑框中选定文本区域(全选) m_edit.ReplaceSel("Hello World!"); //用字符串替换选定的区域} 例9-1说明l更正: 图9-6成员变量的类型均为CButton类型设置窗口Captionvoid SetWindowText( LPCTSTR lpszString );获取按钮的check状态int GetCheck();返回0表示unchecked返回1表示checked返回2表示不确定设置按钮的check状态void SetCheck( int nCheck );实参为0表示unchecked实参为1表示checked实参为2表示不确定 图标按钮与位图按钮1.设计对话框.IDC_BUTTON1Icon样式IDC_BUTTON2Bitmap样式 续2.为了体现多种编程风格,在对话框类中增加一个成员变量. 续3.导入(Import)图标和位图资源. 续4.编写对话框类的OnInitDialog()成员函数代码.HICON hIcon = AfxGetApp()->LoadIcon(IDI_ICON1);SendDlgItemMessage(IDC_BUTTON1, BM_SETIMAGE,(WPARAM)IMAGE_ICON, (LPARAM)(HANDLE)hIcon);HBITMAP hBm = LoadBitmap(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDB_BITMAP1));m_bmp.SetBitmap(hBm);//SendDlgItemMessage(IDC_BUTTON2, BM_SETIMAGE,//(WPARAM)IMAGE_BITMAP, (LPARAM)(HANDLE)hBm);l查阅MSDN,了解函数的用法:1.AfxGetApp()全局函数返回当前应用程序对象的指针2.CWinApp::LoadIcon()3.CWnd::SendDlgItemMessage(),BM_SETIMAGE为按钮控件消息4.LoadBitmap()为GDI函数5.AfxGetInstanceHandle()全局函数返回标识当前应用程序对象的句柄6.MAKEINTRESOURCE()转换整数值到资源串7.CButton::SetBitmap() 第第9 9章章 WindowsWindows标准控件在可视化编程中的应用标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 滚动条控件l滚动条是一个交互式的可视化控件,它包括一个滑块和两个方向箭头.l滚动条控件与属于窗口的滚动条是有区别的.1.滚动条控件是由用户创建、管理和释放的.2.处于窗口的滚动条是由该窗口创建、管理和释放的.CScrollBar(): 构造函数Create(): 创建滚动条控件GetScrollPos(): 获取滑块位置SetScrollPos(): 设置滑块位置GetScrollRange(): 获取滑块最小、最大位置SetScrollRange(): 设置滑块最小、最大位置ShowScrollBar(): 显示或隐藏滚动条EnableScrollBar(): Enable or disable滚动条两端的按钮SetScrollInfo(): 设置滚动条的信息GetScrollInfo(): 获取滚动条的信息GetScrollLimit(): 获取最大的滚动位置 创建滚动条控件BOOL Create(DWORD dwStyle, //滚动条样式const RECT& rect, //滚动条的尺寸和位置CWnd* pParentWnd, //指定滚动条的父窗口,不能为NULLUINT nID //控件ID);CScrollBarCScrollBarObj构造函数Create()IDE创建滚动条控件是一件很简单的事情 WM_HSCROLL、WM_VSCROLL消息lWM_HSCROLL消息1.当窗口的标准水平滚动条滚动时,窗口将收到WM_HSCROLL消息.2.当水平滚动条控件滚动时,其属主窗口将收到WM_HSCROLL消息.lWM_VSCROLL消息1.当窗口的标准垂直滚动条滚动时,窗口将收到WM_VSCROLL消息.2.当垂直滚动条控件滚动时,其属主窗口将收到WM_VSCROLL消息.WM_HSCROLL消息的wParam参数nScrollCode = (int) LOWORD(wParam);SB_ENDSCROLL: 结束滚动SB_LEFT: 滚动到最左端SB_RIGHT: 滚动到最右端SB_LINELEFT: 左滚一行SB_LINERIGHT 右滚一行SB_PAGELEFT: 左滚一页SB_PAGERIGHT:右滚一页SB_THUMBPOSITION: 拖动滑块至新位置SB_THUMBTRACKThe: 拖动滑块nPos = (short int) HIWORD(wParam);滑块位置对垂直滚动条还有:SB_TOP: 滚动到最顶端SB_BOTTOM: 滚动到最底端SB_LINEUP: 上滚一行SB_LINEDOWN: 下滚一行SB_PAGEUP: 上滚一页SB_PAGEDOWN: 下滚一页 MFC对滚动消息的处理l从表9-2可以看出,没有与滚动条相关的通知代码.lMFC处 理 滚 动 消 息 要 用 到 CWnd类 的 成 员 函 数 :void OnHScroll(UINT nSBCode, //滚 动 码 (表 9-7),描 述 滚 动 事 件UINT nPos, //滑块位置CScrollBar* pScrollBar //若滚动消息来自滚动条控件,指针指//向该控件;若滚动消息来自窗口的标准滚动条,该参数为NULL);void OnVScroll(UINT nSBCode,UINT nPos,CScrollBar* pScrollBar); 例9-2lStep 1: 新建MFC AppWizard工程,工程名为“例9_2”,工程类型为Dialog based.Application of ScrollBar清除对话框上的默认控件 Step 2: 设计对话框控件IDCaptionRead_only滚动条IDC_SCROLLBAR编辑框IDC_EDIT1√Up按钮IDC_UP_BUTTON&UpDown按钮IDC_DOWN_BUTTON&DownReset按钮IDC_RESET_BUTTON&ResetExit按钮IDC_EXIT_BUTTON&Exit利用Layout菜单调整控件位置 Step 3: 添加成员变量 查看对话框类CMy9_2Dlg有何变化?下一步工作 Step 4: 编写OnInitDialog()代码BOOL CMy9_2Dlg::OnInitDialog(){ ... // TODO: Add extra initialization here m_Scrollbar.SetScrollRange(0, 20); //设置滚动条的最小、最大位置 m_Scrollbar.SetScrollPos(10); //设置滑块位置 char sPos[10]; itoa(m_Scrollbar.GetScrollPos(), sPos, 10); //将int数据(滑块当前位置) // 以十进制格式转换为字符串 //并存放在sPos中 m_Edit.SetSel(0, -1); //选中编辑框的文本区域(全选) m_Edit.ReplaceSel(sPos); //用指定的字符串替换编辑框的选中区域 UpdateData(FALSE); //CWnd类的成员函数,FALSE表示初始化对话框中的数据 //TRUE表示获取、验证对话框中的数据 return TRUE; // return TRUE unless you set the focus to a control}新增的代码 Step 5: 添加成员函数 查看对话框类CMy9_2Dlg有何变化?下一步工作 Step 6: 编写OnVScroll()代码void CMy9_2Dlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: Add your message handler code here and/or call default char sPos[10]; //存放编辑框的显示的文本 int iNowPos; //当前滑块位置 switch(nSBCode) { if(pScrollBar == &m_Scrollbar) //如果消息来自滚动条控件 { case SB_THUMBTRACK: //拖动滑块 ...; break; case SB_LINEDOWN: //下滚一行,即单击向下箭头 ...; break; case SB_LINEUP: //上滚一行,即单击向上箭头 ...; break; case SB_PAGEDOWN: //下滚一页,单击向下箭头与滑块之间的区域 ...; break; case SB_PAGEUP: //上滚一页,即单击向上箭头与滑块之间的区域 ...; break; } } CDialog::OnVScroll(nSBCode, nPos, pScrollBar);} Step 7: 增加成员函数处理按钮消息 单击按钮时的消息处理void CMy9_2Dlg::OnUpButton() { m_Scrollbar.SetScrollPos(0); m_Edit.SetSel(0, -1); m_Edit.ReplaceSel("0");}void CMy9_2Dlg::OnDownButton() { m_Scrollbar.SetScrollPos(20); m_Edit.SetSel(0, -1); m_Edit.ReplaceSel("20");}void CMy9_2Dlg::OnResetButton() { m_Scrollbar.SetScrollPos(10); m_Edit.SetSel(0, -1); m_Edit.ReplaceSel("10");}void CMy9_2Dlg::OnExitButton() { OnOK(); //关闭对话框} 第9章 Windows标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 静态控件lA static control displays a text string, box, rectangle, icon, cursor, bitmap, or enhanced metafile. It can be used to label, box, or separate other controls.l静态控件通常不必考虑输入和输出.静态控件Static TextPicture 静态控件l静态控件通常不会向其父窗口发送控件通知消息.l如果想要静态控件触发WM_COMMAND消息,则该控件必须设置为Notify样式,同时还要修改控件ID使它不再为默认值(IDC_STATIC).修改 CStatic类CStatic(): 构造函数Create(): 创建静态控件SetBitmap(): 设置要在静态控件中显示的位图GetBitmap(): 获取前次设置的位图句柄SetIcon(): 设置要在静态控件中显示的图标GetIcon(): 获取前次设置的图标句柄SetCursor(): 设置在静态控件区域中的光标图案GetCursor(): 获取前次设置的光标句柄SetEnhMetaFile(): 设置要在静态控件中显示的图元文件GetEnhMetaFile(): 获取前次设置的图元文件句柄ModifyStyle(): 修改窗口样式 例9-3l对话框中放置一个静态文本框控件,要求程序运行时该文本框显示一幅位图,单击位图时报告位图的尺寸. 例9-3用到的其它函数l获取图形对象信息(第7章P152)int GetObject(HGDIOBJ hgdiobj, //GDI对象句柄int cbBuffer, //对象信息的字节数LPVOID lpvObject //void类型指针);l格式化串对象CString::Format()lMFC全局函数AfxGetInstanceHandle(): 获取当前应用实例的句柄AfxMessageBox(): 显示一个Windows消息框l将一个整数值转换为资源标识串LPTSTR MAKEINTRESOURCE(WORD wInteger //要转换的整数); 第第9 9章章 WindowsWindows标准控件在可视化编程中的应用标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 列表框(List Box)l提供多个选项供用户选择.l当用户选中数据项后,该数据项高亮显示,并向其父窗口发送控件通知消息(WM_COMMAND).l提供多种数据项的选择模式(单选/多选/扩展/不可选). CListBox类CListBox( ): 构造函数Create( ): 创建列表框控件InitStorage( ): 预分配内存通用方法(表9-13)单项方法(P222)多选方法(表9-14)字符串方法(表9-15)虚函数(表9-16) 列表框的通知码(表9-17)通知码说明LBN_SELCHANGE改变选项时触发(原来选了某个选项,现在选另一个)LBN_DBLCLK双击选项时触发LBN_ERRSPACE当列表框不能分配足够内存以满足特定需要时触发LBN_KILLFOCUS列表框失去键盘焦点时触发LBN_SELCANCEL取消选择时触发(原来选了某个选项,现在不选了)LBN_SETFOCUS列表框获得键盘焦点时触发 如何理解控件通知码?l当用户操作控件时,该控件将向其父窗口发送控件通知消息(WM_COMMAND).l对于同一个控件,可以有各种不同的操作.例如,用户可以对按钮进行单击和双击操作.这两种操作尽管触发的都是WM_COMMAND消息,但消息的wParam参数中高16位含有不同的通知码:1.BN_CLICKED(BN_CLICKED通知消息)2.BN_DOUBLECLICKED(BN_DOUBLECLICKED通 知消息)l命令相关类(CCmdTarget)将含有不同通知码的控件通知消息映射到不同的消息处理函数中.含有BN_CLICKED通知码的WM_COMMAND消息含有BN_DOUBLECLICKED通知码的WM_COMMAND消息单击按钮双击按钮OnButton1()OnDoubleclickedButton1()消息映射消息映射 向列表框发送的消息l应用程序(或父窗口)也可以向控件发送指定的消息(表9-18).LRESULT SendDlgItemMessage(int nID, //接收消息的控件IDUINT message, //消息号,例如表9-18WPARAM wParam = 0,LPARAM lParam = 0); 例9-4l创建一个常用样式的单选列表框,并在该列表框中列出当前目录的文件,双击后删除该项.l设计思路1.对话框显示时,在列表框中列出当前目录下的文件名(每个文件名作为列表框的一个选项).2.双击列表框的某个选项后,显示一个Windows消息框,并从列表框中删除该项.对话框即将显示时会触发WM_INITDIALOG消息,该消息由对话框类的成员函数OnInitDialog()处理,常用于对对话框中的控件进行初始化.双击列表框的某个选项后,将向其父窗口发送含有LBN_DBLCLK通知码的控件通知消息,将它映射到某个函数进行消息处理. 准备工作l获取当前目录(API函数)l用指定目录中的文件名填充列表框,并将目录名显示在Static Text控件中(CWnd类成员)DWORD GetCurrentDirectory(DWORD nBufferLength,//指定目录缓冲区大小//即目录名(字符串)的长度LPTSTR lpBuffer//字符指针,指向当前目录名//注意: 目录名包括盘符和路径); int DlgDirList(LPTSTR lpPathSpec, //字符指针,指向某个目录名int nIDListBox, //列表框IDint nIDStaticPath, //Static Text控件IDUINT nFileType //文件属性值(表9-19)); 准备工作(续)l获取列表框中当前选中项的索引(CListBox类成员)l将列表框中指定项的信息(即显示的字符串)保存到字符串或串对象中(CListBox类成员)l删除列表框中指定的项(CListBox类成员)int GetCurSel();int GetText( int nIndex, LPTSTR lpszBuffer );或void GetText( int nIndex, CString& rString );int DeleteString( UINT nIndex ); Step 1l利用MFC AppWizard,创建一个Dialog based的应用程序.l设计如下对话框:Static Text用于显示当前目录名(路径串)List Box用于显示当前目录下的文件名控件IDStatic TextIDC_STATIC_DIRList BoxIDC_LIST_DIR Step 2l在对话框类的成员函数OnInitDialog()中添加代码(建议将P225粗体代码简化成如下形式):char CurDir[MAX_PATH];//字符数组用于存放当前目录名//#define MAX_PATH 260GetCurrentDirectory(MAX_PATH, CurDir); //获取当前目录// 用当前目录中所有普通文件名填充列表框// 目录名显示在静态文本框中DlgDirList(CurDir, IDC_LIST_DIR, IDC_STATIC_DIR, 0);目录名列表框ID静态文本框ID文件属性 Step 3l利用MFC ClassWizard,将由双击列表框选项触发的控件通知消息映射到某个函数(消息处理). Step 4l利用MFC ClassWizard,为列表框控件添加一个类型为CListBox的成员变量(将用到CListBox类成员函数). Step 5l处理由双击列表框选项触发的控件通知消息,在相应的消息处理函数中添加代码.int i = m_list.GetCurSel(); //获取列表框当前选中项的索引CString str; //串对象m_list.GetText(i, str); //将索引为i的项的信息保存到串中m_list.DeleteString(i); //从列表框中删除索引为i的项CString msg = “Item ” + str + “ deleted!”; //定义新串AfxMessageBox(msg); //显示一个消息框(表8-6) //消息框中显示msg串信息 例9-4修改1.设计如下对话框:控件IDCaption静态控件IDC_STATIC_DIR列表框IDC_LIST_DIR按钮IDC_BUTTON1&Delete2.在对话框类的成员函数OnInitDialog( )中添加代码.char CurDir[MAX_PATH];GetCurrentDirectory(MAX_PATH, CurDir);DlgDirList(CurDir, IDC_LIST_DIR, IDC_STATIC_DIR, 0); 例9-4修改(续)3.增加成员函数(处理单击按钮触发的消息) 例9-4修改(续)4.在OnButton1()中添加代码(换一种思路).lSendDlgItemMessage函数的作用是向指定的控件(由第1个参数决定)发送特定的控件消息(由第2个参数决定),第3、4个参数分别为控件消息的wParam参数和lParam参数列表框控件消息wParamlParam说明LB_GETCURSEL00获取列表框当前选中项的索引LB_DELETESTRING待删除项的索引0删除列表框中相应的项(由wParam参数决定)//告诉我列表框当前选中了哪个选项long i = SendDlgItemMessage(IDC_LIST_DIR, LB_GETCURSEL, 0, 0);//命令列表框删除它的第i项SendDlgItemMessage(IDC_LIST_DIR, LB_DELETESTRING, i, 0);若按例9-4方法,应该怎样做? 第第9 9章章 WindowsWindows标准控件在可视化编程中的应用标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 编辑框控件简介l编辑框控件是一个矩形窗口,常用于用户键入文本.l编辑框控件有两种形式: 单行、多行.lCEdit类:CEdit()Create()通用方法(表9-20)用于多行的方法(表9-21) 编辑框通知码(表9-22)通知码说明EN_CHANGE编辑框文本改变时(显示后发生)EN_ERRSPACE编辑框没有足够的内存时EN_HSCROLL移动编辑框的水平滚动条时EN_KILLFOCUS编辑框失去键盘焦点时EN_MAXTEXT用户输入的文本数超出编辑框的最大字符数时EN_SETFOCUS编辑框获得键盘焦点时EN_UPDATE编辑框将要显示改变的文本时(显示前发生)EN_VSCROLL移动编辑框的垂直滚动条时父窗口控件含有通知码的控件通知消息 编辑框控件消息(表9-23)编辑框控件消息wParamlParam说明EM_UNDO00撤销上一次对编辑框的操作EM_CANUNDO00确定控件能否响应EM_UNDO消息EM_CHARFROMPOS0(LPARAM)(POINTL*) lpPoint获取指定点字符的行、列索引EM_EMPTYUNDOBUFFER00重新设置undo标志……父窗口控件其它窗口或应用通过函数调用向指定控件发送消息LRESULT SendDlgItemMessage(int nID, //接收消息的控件IDUINT message, //控件消息,例如表9-18WPARAM wParam = 0,LPARAM lParam = 0); 例9-51.利用MFC AppWizard建立Dialog based的应用程序.2.设计如下对话框:3.按表9-24修改控件属性.4.按图9-18设置编辑框样式(带水平、垂直滚动条). 续5.增加成员变量(修改图9-17).二个就可以了 续6.增加成员函数响应单击按钮事件,编辑处理代码. 例9-61.利用MFC AppWizard建立Dialog based的应用程序.2.设计如下对话框:l说明:例9-6将3个编辑框样式均设置为Number,这样做可以避免用户在编辑框中键入非数字字符,而负号是非数据字符,故本例不选用该样式!IDC_EDIT1IDC_EDIT2IDC_EDIT3 Read_onlyIDC_BUTTON1 续3.向对话框类中增加成员变量.理解值变量与控件变量有何不同? 续4.编写对话框类的OnInitDialog()函数代码:UpdateData(TRUE);m_Result = m_A*m_B;UpdateData(FALSE);BOOL UpdateData(BOOL bSaveAndValidate = TRUE); FALSE表示初始化对话框中的数据TRUE表示获取、验证对话框中的数据 续5.向对话框类中增加成员函数.控件ID通知码函数名IDC_EDIT1EN_CHANGEOnChangeEditMul1IDC_EDIT2EN_CHANGEOnChangeEditMul2IDC_BUTTON1BN_CLICKEDOnReset 续5.编写代码:void CMy9_6Dlg::OnChangeEditMul1() { UpdateData(TRUE); m_Result = m_A*m_B; UpdateData(FALSE);}void CMy9_6Dlg::OnChangeEditMul1() { UpdateData(TRUE); m_Result = m_A*m_B; UpdateData(FALSE);}void CMy9_6Dlg::OnReset(){ m_A = 0; m_B = 0; m_Result = m_A*m_B; UpdateData(FALSE);} 补充: 用户登录1.利用MFC AppWizard建立Dialog based的应用程序.2.设计如下对话框:Password 续3.向对话框类中增加成员变量. 续4.向对话框类中增加成员函数,并编写代码.void CMyDlg::OnButton1() { char* user = "abc"; char* password = "1234"; UpdateData(TRUE); if( !strcmp(m_EDIT1, user)&& !strcmp(m_EDIT2, password)) MessageBox("登录成功!"); else MessageBox("用户名或密码不正确!");}void CMyDlg::OnButton2() { m_EDIT1 = ""; m_EDIT2 = ""; UpdateData(FALSE); m_E1.SetFocus();}CWnd* SetFocus( );编辑框类继承了该方法 第第9 9章章 WindowsWindows标准控件在可视化编程中的应用标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结 组合框l三类组合框1.Simple2.DropDown3.Drop Listl组合框类可编辑 组合框通知码(表9-28)通知码说明CBN_CLOSEUP关闭列表框时CBN_DBLCLK双击列表框选项串时CBN_DROPDOWN列表框将要可视时CBN_EDITCHANGE编辑框文本改变时(显示后发生)CBN_EDITUPDATE编辑框将要显示改变的文本时(显示前发生)CBN_ERRSPACE 组合框没有足够的内存时CBN_KILLFOCUS组合框失去键盘焦点时CBN_SELCHANGE用户更改列表框选项时CBN_SELENDCANCEL用户先选中某一选项,但随后选择另一个控件或关闭对话框CBN_SELENDOK用户选择一个选项,或选择一个选项后关闭列表框CBN_SETFOCUS组合框得到键盘焦点时父窗口控件含有通知码的控件通知消息 组合框控件消息(表9-29)父窗口控件其它窗口或应用通过函数调用向指定控件发送消息 例9-7用到的函数(P240~241)l增加一个字符串到(组合框的)列表框尾部:int AddString(LPCTSTR lpszString);l从(组合框的)列表框中获取一个串:void GetLBText(int nIndex, CString& rString);l得到当前选中项的索引:int GetCurSel( ); 例9-8l“例9_8界面”目录已设计好程序界面(下图),但未增加成员变量和成员函数,请在该基础上完成例9-8,并阅读MSDN理解代码.lP250 ⑤、P251 ⑥代码存在问题,请更正! 例9-8更正⑤void CMy9_8Dlg::OnShowButton(){GetDlgItem(IDC_DATE_CHECK)->ShowWindow(SW_SHOW);GetDlgItem(IDC_TIME_CHECK)->ShowWindow(SW_SHOW);m_DateEdit.ShowWindow(SW_SHOW);m_TimeEdit.ShowWindow(SW_SHOW);}⑥void CMy9_8Dlg::OnHideButton(){GetDlgItem(IDC_DATE_CHECK)->ShowWindow(SW_HIDE);GetDlgItem(IDC_TIME_CHECK)->ShowWindow(SW_HIDE);m_DateEdit.ShowWindow(SW_HIDE);m_TimeEdit.ShowWindow(SW_HIDE);} 第第9 9章章 WindowsWindows标准控件在可视化编程中的应用标准控件在可视化编程中的应用9.1 9.1 概述概述9.2 9.2 按钮控件及其应用按钮控件及其应用9.3 9.3 滚动条控件滚动条控件9.4 9.4 静态控件静态控件9.5 9.5 列表框控件列表框控件9.6 9.6 编辑框控件编辑框控件9.7 9.7 组合框控件组合框控件9.8 9.8 对话框通用控件对话框通用控件9.9 9.9 小结小结图像控件Spin控件进度条控件滑动条控件日期/时间提取控件列表(视图)控件树视图控件扩展的组合框控件 图像控件(Picture)l图像控件是一种静态控件.图像控件的类型 图像控件的使用分隔线Type: FrameModal frame显示位图或图标Type: Bitmapl在显示图像方面,Picture控件比Static Text控件更好用. Spin控件l提供一对箭头(上下或左右),通常用于调整伙伴窗口中的数值. CSpinButtonCtrl类常用成员(表9-33)CSpinButtonCtrl( ): 构造函数Create( ): 创建Spin控件SetBase( ): 设置Spin控件的基(伙伴窗口数值的进制)SetBuddy( ): 设置Spin控件的伙伴窗口GetBuddy( ): 得到伙伴窗口的指针 SetPos( ): 设置Spin控件的当前位置SetRange( ): 设置Spin控件的取值范围l得到子窗口或控件的IDint GetDlgCtrlID( );l得到指定控件(或子窗口)指针CWnd* GetDlgItem(int nID);l设置标题或控件文本void SetWindowText( LPCTSTR lpszString ): Spin控件的使用Read-onlyIDC_SPIN1RightAuto Buddy 在OnInitDialog函数中添加代码CSpinButtonCtrl* pSpin =(CSpinButtonCtrl*)GetDlgItem(IDC_SPIN1);pSpin->SetRange(0, 100);pSpin->SetPos(50);pSpin->GetBuddy()->SetWindowText("5.0");如果在相应的对话框类中增加一个CSpinButtonCtrl类型的变量成员m_spin, 则上述代码可以采用另一种形式:m_spin.SetRange(0, 100);m_spin.SetPos(50);m_spin.GetBuddy()->SetWindowText("5.0"); 处理WM_VSCROLL消息lSpin控件可视为一个简化的滚动条,而MFC处理滚动消息要用到CWnd类的成员函数OnVScroll或OnHScroll:void OnVScroll(UINT nSBCode, //滚动码(表9-7)UINT nPos, //滑块位置(Spin控件的当前位置)CScrollBar* pScrollBar //指向滚动条);l本例代码:void CMy9_9Dlg::OnVScroll(UINT nSBCode, UINT nPos,CScrollBar* pScrollBar){ // TODO: Add your message handler code here and/or call default if(pScrollBar->GetDlgCtrlID() == IDC_SPIN1) { CString strValue; strValue.Format("%3.1f", nPos/10.0); ((CSpinButtonCtrl*)pScrollBar)->GetBuddy()->SetWindowText(strValue); } CDialog::OnVScroll(nSBCode, nPos, pScrollBar);} 进度条控件(Progress)l进度条用于指示长时间操作的进度.CProgressCtrl( )Create( )SetRange( ): 设置进度条范围GetRange( ): 得到进度条范围SetPos( ): 设置当前位置GetPos( ): 得到当前位置OffsetPos( ): 将当前位置偏离指定的数值SetStep( ): 设置步长StepIt( ): 将当前位置向前推进一个步长 进度条控件的使用IDC_PROGRESS1SmoothIDC_BUTTON_START 在OnInitDialog函数中添加代码CProgressCtrl* pProg = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1);pProg->SetRange(0, 100);pProg->SetPos(0); //教材设置为50 处理开始按钮的单击事件void CMy9_9Dlg::OnButtonStart() { CProgressCtrl* pProg = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1); pProg->SetPos(0); SetTimer(1000, 100, NULL);}定时器标识时间间隔消息入队并由CWnd对象处理 处理WM_TIMER消息void CMy9_9Dlg::OnTimer(UINT nIDEvent) { if(nIDEvent == 1000) { CProgressCtrl* pProg = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1); pProg->SetPos(pProg->GetPos()+1); if(pProg->GetPos()>=100) { KillTimer(nIDEvent); AfxMessageBox("进行完毕"); } } CDialog::OnTimer(nIDEvent);}定时器标识 改进Static TextIDC_STATIC1Caption为空 处理WM_TIMER消息(改进后)void CMy9_9Dlg::OnTimer(UINT nIDEvent) { CString str; if(nIDEvent == 1000) { CProgressCtrl* pProg = (CProgressCtrl*)GetDlgItem(IDC_PROGRESS1); pProg->SetPos(pProg->GetPos()+1); str.Format("%d",pProg->GetPos()); CStatic* pStatic =(CStatic*)GetDlgItem(IDC_STATIC1); pStatic->SetWindowText(str+"%"); if(pProg->GetPos()>=100) { KillTimer(nIDEvent); AfxMessageBox("进行完毕"); } } CDialog::OnTimer(nIDEvent);} 滑动条控件(Slider)l滑动条控件是一个包含滑块的窗口,用户通过拖动滑块选择所需要的值. CSliderCtrl类的主要成员(表9-35)CSliderCtrl( )Create( )SetRange( ): 设置滑块min、max位置SetPos( ): 设置滑块当前位置GetPos( ): 得到滑块当前位置SetSelection( ): 设置滑块当前的起始位置和终止位置SetBuddy( ): 设置滑动条的伙伴窗口获取窗口或对话框中指定控件(或子窗口)指针CWnd* GetDlgItem( int nID );设置窗口或对话框中指定控件的标题(或文本)void SetDlgItemText( int nID, LPCTSTR lpszString ); 滑动条控件的使用IDC_SLIDER1Point属性设置为Bottom/Right静态文本框用于显示滑块位置IDC_STATIC_SLIDERCaption为空 在OnInitDialog函数中添加代码CString strText1;CSliderCtrl* pSlide1 =(CSliderCtrl*)GetDlgItem(IDC_SLIDER1);pSlide1->SetRange(0, 100);pSlide1->SetPos(50);strText1.Format("%d", pSlide1->GetPos());SetDlgItemText(IDC_STATIC_SLIDER, strText1); 处理WM_HSCROLL消息l滑动条控件可视为一个简化的滚动条,而MFC处理滚动消息要用到CWnd类的成员函数OnVScroll或OnHScroll:void OnHScroll(UINT nSBCode, //滚动码(表9-7)UINT nPos, //滑块位置(Spin控件的当前位置)CScrollBar* pScrollBar //指向滚动条);l本例代码:void CMy9_9Dlg::OnHScroll(UINT nSBCode, UINT nPos,CScrollBar* pScrollBar){ // TODO: Add your message handler code here and/or call default if(pScrollBar->GetDlgCtrlID() == IDC_SLIDER1) { CSliderCtrl* pSlide = (CSliderCtrl*)pScrollBar; CString strText; strText.Format("%d", pSlide->GetPos()); SetDlgItemText(IDC_STATIC_SLIDER, strText); } CDialog::OnHScroll(nSBCode, nPos, pScrollBar);} 日期/时间提取控件(Date Time Picker)l日期/时间提取控件(DTP)提供了一个友好的界面,可以直观地显示时间,同时便于用户选择日期、时间. CDateTimeCtrl类成员(表9-36)CDateTimeCtrl( )Create( )GetMonthCalColor( ): 获取控件中月历指定部分的颜色SetMonthCalColor( ): 设置控件中月历指定部分的颜色SetFormat( ): 设置日期/时间的显示格式GetMonthCalCtrl( ): 获取控件中月历子窗口(指针)GetMonthCalFont( ): 获取控件中月历子窗口使用的字体(指针)SetMonthCalFont( ): 设置控件中月历子窗口使用的字体SetRange( ): 设置控件的min、max时间GetRange( ): 获取控件的min、max时间SetTime( ): 设置控件时间GetTime( ): 获取控件时间 DTP控件的使用lDTN_DATETIMECHANGE通知码Notifies the parent that a change has occurred in the control.2.在对话框类中增加二个成员函数,处理DTP控件的日期或时间改变事件.IDC_DATETIMEPICKER1IDC_DATETIMEPICKER2Format设置为Time1.设计对话框: 编写成员函数代码void CMyDlg::OnDatetimechangeDatetimepicker1(...) { CDateTimeCtrl* pDT =(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER1); SYSTEMTIME st; pDT->GetTime(&st); SetLocalTime(&st); *pResult = 0;}void CMyDlg::OnDatetimechangeDatetimepicker2(...) { CDateTimeCtrl* pDT =(CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER2); SYSTEMTIME st; pDT->GetTime(&st); SetLocalTime(&st); *pResult = 0;} 改进(显示数字时钟)与系统时钟保持同步IDC_DATETIMEPICKER3Format: Timel在OnInitDialog函数中添加代码:SetTimer(1001, 1000, NULL);l处理WM_TIMER消息void CMyDlg::OnTimer(UINT nIDEvent){ // TODO: Add your message handler code here and/or call default if(nIDEvent == 1001) { CDateTimeCtrl* pDT = (CDateTimeCtrl*)GetDlgItem(IDC_DATETIMEPICKER3); CTime tNow = CTime::GetCurrentTime(); pDT->SetTime(&tNow); } CDialog::OnTimer(nIDEvent);} 课外作业l实现Windows操作系统任务栏上的“日期和时间”程序.模拟时钟月历控件Tab控件 补充: 秒钟示例1.利用MFC应用程序向导创建一个基于对话框的应用程序,清除对话框上的所有控件. 秒钟示例(续)2.在相应的对话框类的头文件件中添加数据成员.class CMyDlg : public CDialog{public: POINT startPoint, endPoint; int radius; //秒钟长度…};秒钟示例Dlg.h 秒钟示例(续)3.在相应的对话框类的实现文件的头部添加代码:#include "stdafx.h"#include "秒钟示例.h"#include "秒钟示例Dlg.h"#include "math.h"const double PI = 3.1415926;…秒钟示例Dlg.cpp 秒钟示例(续)4.在对话框类的OnInitDialog函数中添加代码:BOOL CMyDlg::OnInitDialog(){ … // TODO: Add extra initialization here radius = 100; SetTimer(101, 1000, NULL); return TRUE;} 秒钟示例(续)5.在对话框类的OnPaint函数中添加代码(画直线):void CMyDlg::OnPaint() { … CDC* pDC = GetDC(); pDC->MoveTo(startPoint); pDC->LineTo(endPoint); pDC->DeleteDC();} 秒钟示例(续)6.利用类向导向对话框类添加一个成员函数,用于响应定时器消息. 秒钟示例(续)7.编写OnTimer函数代码:void CMyDlg::OnTimer(UINT nIDEvent) { if(nIDEvent == 101) { CRect rect; GetClientRect(rect); startPoint.x = rect.Width()/2; startPoint.y =rect.Height()/2; CTime tNow = CTime::GetCurrentTime(); int sec = tNow.GetSecond(); int angle = 6*sec; endPoint.x = startPoint.x + (int)(radius*sin(PI/180*angle)); endPoint.y = startPoint.y - (int)(radius*cos(PI/180*angle)); Invalidate(); } CDialog::OnTimer(nIDEvent);} 列表(视图)控件(List Control)l列表控件通常用于显示若干项,每一项包括一个图标(来自于图像列表)和一个标签(文本),还可以有其它的信息(子项).列表控件 CListCtrl类的主要成员(表9-37)SetImageList( ): 设置图像列表(CImageList)InsertItem( ): 插入一个新的列表项SetBkColor( ): 设置背景颜色SetTextBkColor( ): 设置文本背景颜色GetItemText( ): 得到列表项(或子项)文本SetItemText( ): 设置列表项(或子项)文本EditLabel( ): 开始编辑列表项文本...BOOL Create(int cx, //图像尺寸(单位像素)int cy, //图像尺寸UINT nFlags, //图像列表的类型int nInitial, //最初包含的图像数int nGrow //可以追加的图像数); Add(HICON hIcon ); //增加图像到图像列表中l图像列表是一个具有相同大小的图像集, 常用于管理大量的图标或位图. 列表控件的视图风格lIcon: 32×32图标尺寸,标签位于图标之下,可以拖动lSmall Icon: 16×16图标尺寸,标签位于图标右侧,可以拖动lList: 16×16图标尺寸,标签位于图标右侧,按列排列,不能拖动lReport: 类似于资源管理器->查看->详细信息CHeaderCtrl对象子项描述的附加信息列报表视图示例 项与子项l列表控件中的每一个项由图标、标签、当前状态、应用定义的值(项数据)组成,每一项可以附加一个或多个子项.l子项是一个字符串,只在报表视图才可见.列表控件中的所有项都具有相同的子项数. 列表控件的使用l在Resource View的Icon中插入(新建)8个图标,并按要求(表9-40)绘制. 续l在相应的对话框类中声明一个图像列表对象(管理图标).CImageList m_imageList; //加在相应的头文件中l在初始化对话框成员函数中加载图标资源.HICON hIcon[8];hIcon[0] = AfxGetApp()->LoadIcon(IDI_ICON_WHITE);hIcon[1] = LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON_BLACK));...hIcon[7] = ... ;l在初始化对话框成员函数中创建图像列表.m_imageList.Create(16, 16, 0, 8, 8);l在初始化对话框成员函数中添加图标至图像列表中.int n;for(n = 0; n < 8; n++)m_imageList.Add(hIcon[n]);l在初始化对话框成员函数中准备好标签文本.static char* color[] = {"white", "black", "red","blue", "yellow", "cyan", "purple", "green"}; 续l在对话框中添加一个List Control.IDC_LIST1View: ListEdit Labels: √静态文本框用于显示项的标签IDC_STATIC_LISTCaption为空 续l在初始化对话框成员函数中添加代码.CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST1);pList->SetImageList(&m_imageList, LVSIL_SMALL);for( n = 0; n < 8; n++)pList->InsertItem(n, color[n], n);pList->SetBkColor(RGB(0, 255, 255));pList->SetTextBkColor(RGB(255, 0, 255));CImageList* SetImageList(CImageList* pImageList, //图像列表指针int nImageList //图像列表类型);int InsertItem(int nItem, //项索引LPCTSTR lpszItem, //指向该项的标签串int nImage //该项的图标索引); LVSIL_NORMAL: 大图标LVSIL_SMALL: 小图标LVSIL_STATE: 状态位图 列表控件的通知码Ø列表控件的通知码多达35种.ØLVN_ITEMCHANGED(改变列表项的选择后)pnmv = (LPNMLISTVIEW) lParam;pnmv表示NMLISTVIEW结构的地址,NMLISTVIEW结构含有项的信息.void CMyDlg::OnItemchangedList1(NMHDR* pNMHDR, LRESULT* pResult) { NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; // TODO: Add your control notification handler code here CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST1); int nSelected = pNMListView->iItem; //见表9-41 if(nSelected >=0) { CString strItem = pList->GetItemText(nSelected, 0); SetDlgItemText(IDC_STATIC_LIST, strItem); } *pResult = 0;}l本例对LVN_ITEMCHANGED消息的响应如下:项索引子项索引 列表控件的通知码(续)ØNM_RCLICK(右击列表项时)lpnmlv = (LPNMLISTVIEW) lParam; void CMyDlg::OnRclickList1(NMHDR* pNMHDR, LRESULT* pResult){ // TODO: Add your control notification handler code here NM_LISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR; CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST1); int nSelected = pNMListView->iItem; if(nSelected >=0) pList->EditLabel(nSelected); //开始编辑列表项文本 //但无法保存编辑的结果 *pResult = 0;}l本例对NM_RCLICK消息的响应如下: 列表控件的通知码(续)ØLVN_ENDLABELEDIT(列表项的标签编辑结束后)pdi = (LPNMLVDISPINFO) lParam;pdi表示NMLVDISPINFO结构的地址void CMyDlg::OnEndlabeleditList1(NMHDR* pNMHDR, LRESULT* pResult) { LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR; // TODO: Add your control notification handler code here LVITEMA item = pDispInfo->item; //列表项信息结构 CString str = item.pszText; //列表项文本 str.TrimLeft(); //去除首部空白 str.TrimRight(); //去除尾部空白 if(str.GetLength()>0) { CListCtrl* pList = (CListCtrl*)GetDlgItem(IDC_LIST1); pList->SetItemText(item.iItem, item.iSubItem, item.pszText); } *pResult = 0;}l本例对LVN_ENDLABELEDIT消息的响应如下: 树视图控件(Tree Control)l树视图控件是一种用来显示项的层次结构的控件,它将项组织成树状结构.每一个项由一个标签和一个可选的位图构成,项还可能有若干子项,单击项后可以展开或合拢子项. CTreeCtrl类主要成员(表9-42)l设置图像列表(这样树控件就可以访问图像列表中的图像了)CImageList* SetImageList(CImageList * pImageList,int nImageListType //图像列表类型);l向树控件插入一个新项HTREEITEM InsertItem(LPTVINSERTSTRUCT lpInsertStruct); 与树结点有关的结构typedef struct tagTVINSERTSTRUCT {HTREEITEM hParent; //父结点句柄HTREEITEM hInsertAfter; //新增结点的位置(表9-43)TVITEM item; //新增结点的信息(结构,表9-44)} TVINSERTSTRUCT;typedef struct tagTVITEM{UINT mask; //掩码(表9-45),指定该结构的哪里成员必须被填充//TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_TEXTHTREEITEM hItem; //项句柄UINT state; //项状态UINT stateMask; //状态掩码LPTSTR pszText; //指向项文本串 int cchTextMax;//项文本串最大长度int iImage; //非选中状态时图标索引int iSelectedImage; //选中状态时图标索引int cChildren; //子项标志,o表示没有子项,1表示有子项LPARAM lParam; //用户设置的数据} TVITEM; 树视图控件的使用l在对话框中添加一个Tree Control.IDC_TREE1Has button: √Has Lines: √Lines at root: √Edit Labels: √ 续l在初始化对话框成员函数中添加代码(创建树).添加一个静态文本框IDC_STATIC_TREE 续ØTVN_SELCHANGED(通知码,选择改变时,即从一个结点转到另一个结点)pnmtv = (LPNMTREEVIEW) lParam typedef struct tagNMTREEVIEW {NMHDR hdr;UINT action;TVITEM itemOld;TVITEM itemNew; //TVITEM结构,包含新选定项的信息POINT ptDrag;} NMTREEVIEW; l本例选择某个结点后,要在相应的静态文本框中显示结点文本.对LVN_SELCHANGED消息的响应见P269.l最后本例还响应了TVN_ENDLABELEDIT消息(树结点项的标签文本编辑结束后).代码见P269. 扩展的组合框控件(Extended Combo Box)l扩展的组合框支持图像列表,该控件可以通过图像列表来访问图像.Ø设置图像列表CImageList* SetImageList(CImageList* pImageList);Ø向控件插入一个新项int InsertItem( const COMBOBOXEXITEM* pCBItem ); 控件中项的信息结构(表9-47)typedef struct {UINT mask; //掩码,指定该结构的哪里成员必须被填充//CBEIF_IMAGE|CBEIF_INDENT|CBEIF_SELECTEDIMAGE|CBEIF_TEXTint iItem; //项索引LPTSTR pszText; //指向项文本串int cchTextMax; //项文本串最大长度int iImage; //非选中状态时图标索引int iSelectedImage; //选中状态时图标索引int iOverlay; //从1开始的覆盖图片索引int iIndent; //显示项时的缩进量LPARAM lParam; //用户设置的数据} COMBOBOXEXITEM; 扩展的组合框控件的使用IDC_COMBOBOXEX1Type: Dropdown 在OnInitDialog函数中添加代码CComboBoxEx* pComboEx = (CComboBoxEx*)GetDlgItem(IDC_COMBOBOXEX1);pComboEx->SetImageList(&m_imageList);COMBOBOXEXITEM comboItem;comboItem.mask =CBEIF_IMAGE|CBEIF_INDENT|CBEIF_SELECTEDIMAGE|CBEIF_TEXT;for(int i = 0; i < 3; i++){ comboItem.iItem = i; comboItem.iImage = i; comboItem. iSelectedImage = i; comboItem.iIndent = i; comboItem.pszText = color[i]; pComboEx->InsertItem(&comboItem);} 第10章 在MFC中创建应用程序的资源10.1 10.1 获取资源的一个样例获取资源的一个样例10.2 10.2 资源的应用资源的应用10.2.1 10.2.1 菜单资源的使用菜单资源的使用10.2.2 10.2.2 快捷菜单的创建及其应用快捷菜单的创建及其应用10.2.3 10.2.3 加速键资源的创建及其应用加速键资源的创建及其应用10.2.4 10.2.4 工具条资源的创建及其应用工具条资源的创建及其应用10.2.5 10.2.5 图标资源的创建及其应用图标资源的创建及其应用10.2.6 10.2.6 字符串资源的创建及其应用字符串资源的创建及其应用10.2.7 10.2.7 对话框资源的创建及其应用对话框资源的创建及其应用10.2.8 10.2.8 位图资源的创建及其应用位图资源的创建及其应用10.3 10.3 小结小结自学 资源简介l资源是独立于代码的,通过专门的Resource Compiler进行编译,可以链接到可执行文件中.l代码是可复用的,资源也是可复用的.通过资源的“导入”和“导出”功能来实现资源的复用.l程序的国际化也是通过资源来实现的.可执行文件.exe.dll.ocx资源类型 DLLlDLL是Dynamic Link Library的缩写,意为动态链接库.l在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的DLL文件,放置于系统中.当执行程序时,相应的DLL文件就会被调用.l一个应用程序可以有多个DLL文件,一个DLL文件也可以被几个应用程序所共享.l使用DLL的好处:1.多个应用程序共享代码和数据.2.DLL以一种自然的方式将一个大的应用程序划分为几个小的模块,有利于开发小组成员的分工与合作.而且,各个模块可以独立升级.3.为了实现应用程序的国际化,往往需要使用DLL.使用DLL可以将针对某一国家、语言的信息存放在其中.对于不同的版本,使用不同的动态连接库. OCXlOCX = OLE Customer ControllOCX = OLE Control eXtensionlOLE = Object Linking and Embedding 10.1 获取资源的一个样例l在VC IDE中打开可执行文件,可以查看其使用的资源.空当接龙、蜘蛛纸牌游戏用到了这个文件 续l打开后可以看到cards.dll文件使用的资源.l鼠标右击某个资源项,可以将选定的资源Export,将来需要时可以再Import.ØWindows XP使用了大量的图标和位图资源,这些资源在编 写 Windows程 序 时 经 常 用 到 ,它 们 存 放 在C:\WINDOWS\system32\shell32.dll文件中. 第10章 在MFC中创建应用程序的资源10.1 10.1 获取资源的一个样例获取资源的一个样例10.2 10.2 资源的应用资源的应用10.2.1 10.2.1 菜单资源的使用菜单资源的使用10.2.2 10.2.2 快捷菜单的创建及其应用快捷菜单的创建及其应用10.2.3 10.2.3 加速键资源的创建及其应用加速键资源的创建及其应用10.2.4 10.2.4 工具条资源的创建及其应用工具条资源的创建及其应用10.2.5 10.2.5 图标资源的创建及其应用图标资源的创建及其应用10.2.6 10.2.6 字符串资源的创建及其应用字符串资源的创建及其应用10.2.7 10.2.7 对话框资源的创建及其应用对话框资源的创建及其应用10.2.8 10.2.8 位图资源的创建及其应用位图资源的创建及其应用10.3 10.3 小结小结自学 10.2.1 菜单资源的使用l三类菜单:1.系统菜单2.主菜单 √3.快捷菜单l回顾API编程菜单的创建过程:在资源描述文件中定义菜单在资源头文件中定义菜单项在资源头文件中定义菜单项IDID在窗口类中加载菜单资源WNDCLASS wndclass;wndclass.lpszMenuName = “My_Menu”;在创建窗口时加载菜单资源在创建窗口时加载菜单资源HWND HWND hwndhwnd; ;HMENU HMENU hmenuhmenu; ;hmenuhmenu = = LoadMenu(hInstanceLoadMenu(hInstance, “, “My_MenuMy_Menu”);”);hwndhwnd = = CreateWindowCreateWindow( , , , , , , , , ( , , , , , , , , hmenuhmenu, , );, , );动态加载菜单动态加载菜单HWND HWND hwndhwnd; ;HMENU HMENU hmenuhmenu; ;hmenuhmenu = = LoadMenu(hInstanceLoadMenu(hInstance, “, “My_MenuMy_Menu”);”);SetMenu(hwndSetMenu(hwnd, , hmenuhmenu); );l利用Visual C++资源编辑器来创建菜单是一件简单的事. 例10-1lStep 1: 创建一个My_Res的单文档项目文件. 例10-1(续)lStep 2: 在资源编辑器中编辑菜单(菜单项属性设置见表10-1).Pop-up: √ Hello World!CMainFrame对象例10-1(续)Ø本例要在视图(窗口客户区)中显示“Hello World!”,视图对象对应的类为CMy_ResView.CMy_ResView对象 例10-1(续)lStep 3: 在My_ResView.h中向CMy_ResView类添加成员.class CMy_ResView : public CView{public: COLORREF m_nColors[3]; //存放红绿蓝的RGB值 DWORD m_nColorIndex; //标识当前选择的颜色 CString m_strShow; //存放待显示的串 BOOL m_bShow; //标识是否选择了“显示”菜单项...};My_ResView.h类定义 例10-1(续)lStep 4: 在My_ResView.cpp文件的构造函数中对成员变量初始化.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;}My_ResView.cpp在源文件中实现类的成员函数 例10-1(续)void CMy_ResView::OnDraw(CDC* pDC){ CMy_ResDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here if(m_bShow) { pDC->SetTextColor(m_nColors[m_nColorIndex]); pDC->TextOut(100, 100, m_strShow); }}My_ResView.cppØOnDraw函数是CView类的虚成员函数,其公有派生类 CMy_ResView也有一个函数原型完全相同的虚OnDraw函数,主要用于屏幕显示、打印和打印预览(有点类型API编程时处理WM_PAINT消息).lStep 5: 在My_ResView.cpp的OnDraw函数中添加代码. 例10-1(续)lStep 6: 向My_ResView类添加成员函数,处理用户选择“显示”菜单项事件. 命令消息Ø命令消息(COMMAND)是由用户接口对象(菜单、工具栏按钮、加速键)发出的.Ø当用户点击某个菜单项后,将触发命令消息,该消息wParam参数的高16位为1.lStep 7: 在成员函数OnOperShow中编写代码void CMy_ResView::OnOperShow(){ m_bShow = !m_bShow; Invalidate(); //标记整个客户区为无效区域 //擦除背景}更新区域非空且队列中没有其他消息Windows发送COMMAND消息调用CMy_ResView类的成员函数OnDrawCWnd::Invalidatevoid Invalidate( BOOL bErase = TRUE ); UPDATE_COMMAND_UI消息ØUPDATE_COMMAND_UI消息在窗口将要绘制菜单项(或工具条按钮)时产生,常用于设置菜单项(或工具条按钮)的Enable、Check状态和Caption.lStep 8: 在 My_ResView类 中 添 加 成 员 函 数 ,处 理UPDATE_COMMAND_UI消息. 例10-1(续)lStep 9: 在成员函数OnUpdateOperShow中编写代码void CMy_ResView::OnUpdateOperShow(CCmdUI* pCmdUI){ // TODO: Add your command update UI handler code here pCmdUI->SetCheck(m_bShow);}指向CCmdUI对象的指针ØCCmdUI类常用的成员函数(表10-2)1.void Enable( BOOL bOn = TRUE );2.void SetCheck( int nCheck = 1 );3.void SetRadio( BOOL bOn = TRUE );4.void SetText( LPCTSTR lpszText ); 例10-1(续)Ø余下的三个子菜单项(“红色”、“绿色”、“蓝色”)也可以像“显示”菜单项一样做类似的处理,但这样做的工作量会很大.下面介绍的方法可以一次处理多个菜单项,但前提条件是这些菜单项的ID值(在Resource.h文件中定义)是连续的.lStep 10: 在My_ResView.h中向CMy_ResView类增加成员函数OnOperColorChange,该函数将处理用户选择子菜单项事件.class CMy_ResView : public CView{...protected: //{{AFX_MSG(CMy_ResView) afx_msg void OnOperShow(); afx_msg void OnUpdateOperShow(CCmdUI* pCmdUI); afx_msg void OnOperColorChange(WORD nID); //}}AFX_MSG...};My_ResView.h手工添加 例10-1(续)lStep 11: 在My_ResView.cpp文件中设置消息映射....BEGIN_MESSAGE_MAP(CMy_ResView, CView) //{{AFX_MSG_MAP(CMy_ResView) ON_COMMAND(ID_OPER_SHOW, OnOperShow) ON_UPDATE_COMMAND_UI(ID_OPER_SHOW, OnUpdateOperShow) //}}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) ON_COMMAND_RANGE(ID_OPER_RED, ID_OPER_BLUE, OnOperColorChange)END_MESSAGE_MAP()...My_ResView.cpp手工设置表示用户选择ID值在某个范围内的菜单项事件均由OnOperColorChange函数处理 例10-1(续)lStep 12: 在My_ResView.cpp中实现OnOperColorChange成员函数....void CMy_ResView::OnOperColorChange(WORD nID){ m_nColorIndex = nID - ID_OPER_RED; Invalidate();}My_ResView.cpp点击的菜单项ID 例10-1(续)lStep 13: 在My_ResView.h中向CMy_ResView类增加成员函数OnUpdateOperColorChange,响应窗口绘制UI对象消息(UPDATE_COMMAND_UI).class CMy_ResView : public CView{...protected: //{{AFX_MSG(CMy_ResView) afx_msg void OnOperShow(); afx_msg void OnUpdateOperShow(CCmdUI* pCmdUI); afx_msg void OnOperColorChange(WORD nID); afx_msg void OnUpdateOperColorChange(CCmdUI* pCmdUI); //}}AFX_MSG...};My_ResView.h手工添加 例10-1(续)lStep 14: 在My_ResView.cpp文件中设置消息映射....BEGIN_MESSAGE_MAP(CMy_ResView, CView) //{{AFX_MSG_MAP(CMy_ResView) ON_COMMAND(ID_OPER_SHOW, OnOperShow) ON_UPDATE_COMMAND_UI(ID_OPER_SHOW, OnUpdateOperShow) //}}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) ON_COMMAND_RANGE(ID_OPER_RED, ID_OPER_BLUE, OnOperColorChange) ON_UPDATE_COMMAND_UI_RANGE(ID_OPER_RED, ID_OPER_BLUE, OnUpdateOperColorChange)END_MESSAGE_MAP()...My_ResView.cpp手工设置表示窗口绘制ID值在某个范围内的菜单项均由OnUpdateOperColorChange函数处理 例10-1(续)lStep 15: 在My_ResView.cpp中实现OnUpdateOperColorChange成员函数....void CMy_ResView::OnUpdateOperColorChange(CCmdUI* pCmdUI){ pCmdUI->SetRadio(m_nColorIndex == ( pCmdUI->m_nID - ID_OPER_RED) );}My_ResView.cpp点击的菜单项ID 补充:如果不想自动加载主菜单BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs){ if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs cs.hMenu = NULL; return TRUE;}在窗口创建之前被调用 10.2.2 快捷菜单的创建及其应用l通常情况下,主菜单在框架窗口初始化时自动加载(类似于P140第2种方法).l快捷菜单的加载及显示要手工编码,它用到了CMenu类的成员函数(表10-4,表10-5).下面列出的是例10-2用到的成员函数.LoadMenu(): 加载菜单资源,并将它附属于一个CMenu对象DestroyMenu(): 释放菜单GetSubMenu(): 获得子菜单(指针)CheckMenuItem(): 对菜单项添加/去除check标记TrackPopupMenu(): 在指定位置显示弹出式菜单 并追踪选定菜单项 CMenu类的成员函数1.BOOL LoadMenu(UINT nIDResource);2.BOOL DestroyMenu();3.CMenu* GetSubMenu(int nPos);菜单(栏)上可能有多个子菜单,每个子菜单都有一个位置编号nPos4.UINT CheckMenuItem(UINT nIDItem, UINT nCheck);5.BOOL TrackPopupMenu(UINT nFlags, //屏幕位置标志和鼠标按键标志int x, //弹出式菜单出现在屏幕上的x坐标int y, //y坐标,屏幕坐标系CWnd* pWnd, //弹出式菜单的属主指针LPCRECT lpRect = NULL //在弹出式菜单区域外单击时将隐藏菜单);0123nFlags取值TPM_CENTERALIGNTPM_LEFTALIGNTPM_RIGHTALIGN ClientToScreen函数void ClientToScreen(LPRECT lpPoint); l将Point结构的客户坐标转换成屏幕坐标,并将结果保存在Point结构中. 例10-2(续例10-1)lStep 1: 在资源编辑器中创建菜单资源,编辑菜单(菜单项属性设置见表10-3).ID_POP_SHOW菜单项ID与主菜单项相同 例10-2(续)lStep 2: 在My_ResView.h中向CMy_ResView类添加成员.class CMy_ResView : public CView{public: COLORREF m_nColors[3]; DWORD m_nColorIndex; CString m_strShow; BOOL m_bShow; CMenu m_PopMenu; //表示菜单(栏) CMenu* m_pPop; //指向子菜单...}; 例10-2(续)lStep 3: 在My_ResView.cpp的构造函数中加载菜单.CMy_ResView::CMy_ResView(){ // TODO: add construction code here 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; m_PopMenu.LoadMenu(IDR_MENU_POP);}教材有错误 例10-2(续)lStep 4: 在My_ResView.cpp的析构函数中释放菜单.CMy_ResView::~CMy_ResView(){ m_PopMenu.DestroyMenu();} 例10-2(续)lStep 5: 向CMy_ResView类添加成员函数,处理鼠标右击窗口客户区事件(也可按前面的方法手工设置消息映射). 例10-2(续)lStep 6: 在成员函数OnRButtonDown中编写代码.void CMy_ResView::OnRButtonDown(UINT nFlags, CPoint point){ m_pPop = m_PopMenu.GetSubMenu(0); //快捷菜单只有一个弹出式子菜单 UINT nCheck = m_bShow ? MF_CHECKED : MF_UNCHECKED; m_pPop->CheckMenuItem(ID_POP_SHOW, MF_BYCOMMAND|nCheck); ClientToScreen(&point); m_pPop->TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this); CView::OnRButtonDown(nFlags, point);}光标位置Ø至此,用户右击窗口客户区时能够显示快捷菜单,但是还不能响应快捷菜单的“显示”菜单项. 例10-2(续)lStep 7: 在My_ResView.cpp中设置消息映射.ON_COMMAND(ID_POP_SHOW, OnOperShow)它表示用户点击ID值为ID_POP_SHOW的菜单项事件由OnOperShow函数处理. 10.2.3 加速键资源的创建及其应用lAPI编程使用加速键资源的一般步骤:1.在资源描述文件中定义加速键资源(创建加速键表)2.加载加速键资源调用LoadAccelerators函数加载加速键表资源,获取加速键表句柄3.翻译加速键消息循环中增加TranslateAccelerator函数4.处理WM_COMMAND/WM_SYSCOMMAND消息lVisual C++处理加速键是一件很简单的事. 例10-3(续例10-2)双击 10.2.4 工具条资源的创建及其应用l工具条是由一组工具条按钮(和其他功能控件)组成的一个特定区域,通常按下一个工具条按钮等价于选择了某个菜单项.lCToolBar类的层次结构:位图按钮组合框 工具条类的常用方法l表10-6 工具条类的常用方法(续)l表10-7 工具条通用控件lA Windows toolbar common control is a rectangular child window that contains one or more buttons. These buttons can display a bitmap image, a string, or both. When the user chooses a button, it sends a command message to the toolbar’s owner window. Typically, the buttons in a toolbar correspond to items in the application’s menu; they provide a more direct way for the user to access an application’s commands.l工具条通用控件类的层次结构:CToolBar工具条的底层是一个CToolBarCtrl工具条 MFC支持的工具条lMFC支持二类工具条(CToolBar、CToolBarCtrl)两者既可单独使用,也可以结合起来使用:1.Create the toolbar using CToolBar2.Call CToolBar::GetToolBarCtrl to get access to the CToolBarCtrl member functions. 创建工具条的一般方法1.创建工具条资源:Insert → Resource → 先择ToolBar → NEW2.构造CToolBar对象,即在MainFrm.h中声明一个工具条对象成员.3.调用Create(或CreateEx)函数创建工具条,并把它附加到工具条对象上.4.调用LoadToolBar加载工具条资源. CToolBar::Create BOOL Create(CWnd* pParentWnd, //父窗口指针DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_TOP,//窗口+工具条样式组合UINT nID = AFX_IDW_TOOLBAR //工具条的子窗口ID);函数调用成功返回非0.由于CToolBar的父类是CControlBar,因此工具条样式可以使用控件条样式(表10-9). Control bar is at the right of the frame window CToolBar::CreateEx l创建工具条并把它附加到CToolBar对象上,同时还设置了嵌入的CToolBarCtrl对象的样式BOOL CreateEx(CWnd* pParentWnd, //父窗口指针DWORD dwCtrlStyle = TBSTYLE_FLAT,//嵌入的CToolBarCtrl对象的样式DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP,//窗口+工具条样式组合CRect rcBorders = CRect(0, 0, 0, 0),//CRect对象,定义了工具条边框的宽度//默认值表示无边框UINT nID = AFX_IDW_TOOLBAR //工具条的子窗口ID); CToolbar::LoadToolBar l加载工具条资源BOOL LoadToolBar(LPCTSTR lpszResourceName);BOOL LoadToolBar(UINT nIDResource);函数调用成功返回非0.l如何理解P289底部代码?if(!m_wndToolBar.Create(...)||!m_wndToolBar.LoadToolBar(...)){TRACE0(“...”); //向文件或调试监控程序发送信息return -1;}二个函数中只要有一个调用失败,该表达式为真 例10-4(续例10-3)lStep 1: 插入工具条资源(创建工具条资源). 例10-4(续)lStep 2: 绘制工具条上的4个位图按钮,并设置ID.S: ID_OPER_SHOWR: ID_OPER_REDG: ID_OPER_GREENB: ID_OPER_BLUE与菜单项ID相同 例10-4(续)lStep 3: MainFrm.h中声明一个工具条对象成员.class CMainFrame : public CFrameWnd{...protected: // control bar embedded members CStatusBar m_wndStatusBar; CToolBar m_wndToolBar; CToolBarm_wndToolBarNew;...};MainFrm.h 例10-4(续)lStep 4: 在CMainFrame::OnCreate的成员函数中添加代码.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; }...}MainFrm.cpp 例10-4(续)lStep 5: 为了使新增的工具条可以在窗口中自由停靠,向CMainFrame::OnCreate的成员函数中添加代码.int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){... // TODO: Delete these three lines if you don't want the toolbar to // be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); m_wndToolBarNew.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBarNew); return 0;}MainFrm.cpp 补充: 显示/隐藏工具条和状态条lStep 1: 在资源编辑器中编辑主菜单.菜单项ID如下:工具条1: ID_SHOW_TOOLBAR1工具条2: ID_SHOW_TOOLBAR2状态条: ID_SHOW_STATUSBAR 续lStep 2: 在MainFrm.h中向CMainFrame类添加三个成员变量,分别表示三个菜单项的选择状态.class CMainFrame : public CFrameWnd{public: BOOL ToolBar1, ToolBar2, StatusBar;...};MainFrm.hlStep 3: 在CMainFrame类的构造函数中初始化上述三个变量.CMainFrame::CMainFrame(){ ToolBar1 = ToolBar2 = StatusBar = TRUE;} 续lStep 4: 利用类向导在CMainFrame类中添加三个成员函数,分别处理用户点击“工具条1”、“工具条2”、“状态条”菜单项事件.添加的三个成员函数,分别处理用户单击菜单项事件在CMainFrame类中已经声明了三个对象成员,并且它们已经被创建 CFrameWnd::ShowControlBar void ShowControlBar(CControlBar* pBar, //指向将要显示或隐藏的控件条BOOL bShow, //TRUE表示显示,FALSE表示隐藏BOOL bDelay //TRUE表示延迟显示,FALSE表示不延迟); 续lStep 5: 处理用户点击“状态条”菜单项事件.void CMainFrame::OnShowStatusbar(){ StatusBar = !StatusBar; if(StatusBar) ShowControlBar(&m_wndStatusBar, TRUE, FALSE); else ShowControlBar(&m_wndStatusBar, FALSE, FALSE);} 续lStep 6: 处理用户点击“工具条1”、“工具条2”菜单项事件.void CMainFrame::OnShowToolbar1(){ ToolBar1 = !ToolBar1; if(ToolBar1) ShowControlBar(&m_wndToolBar, TRUE, FALSE); else ShowControlBar(&m_wndToolBar, FALSE, FALSE);}void CMainFrame::OnShowToolbar2(){ ToolBar2 = !ToolBar2; if(ToolBar2) ShowControlBar(&m_wndToolBarNew, TRUE, FALSE); else ShowControlBar(&m_wndToolBarNew, FALSE, FALSE);} 续lStep 7: 利用类向导在CMainFrame类中添加三个成员函数,分别处理三个菜单项的UPDATE_COMMAND_UI. 续lStep 8: 编写代码void CMainFrame::OnUpdateShowStatusbar(CCmdUI* pCmdUI){ pCmdUI->SetCheck(StatusBar);}void CMainFrame::OnUpdateShowToolbar1(CCmdUI* pCmdUI){ pCmdUI->SetCheck(ToolBar1);}void CMainFrame::OnUpdateShowToolbar2(CCmdUI* pCmdUI){ pCmdUI->SetCheck(ToolBar2);} 。

      点击阅读更多内容
      关于金锄头网 - 版权申诉 - 免责声明 - 诚邀英才 - 联系我们
      手机版 | 川公网安备 51140202000112号 | 经营许可证(蜀ICP备13022795号)
      ©2008-2016 by Sichuan Goldhoe Inc. All Rights Reserved.