高级程序设计复习
第一章 Windows编程基础知识
可视化开发系统集成了一系列系统可用资源和开发工具
- 程序调试工具:包括源程序语法检查、可执行程序修改和运行监视等
- 资源管理器:包括图形化窗口及组成元素的多种对象的编辑器
- 系统函数库和系统函数开发工具
- 源程序编辑器和编译器
- 应用程序Help和Setup开发工具包
- 可选择并构成具体语句或源程序结构的例程库及Help
Windows的程序设计语言
- 都是“面向对象”的程序设计语言
- VC
- VB
- VJ
对象是Windows的规范部件
- 窗口
- 菜单
- 按钮
- 对话框
- 程序模块
对象特征:具有规范形态和操作模式
编程方法
传统编写法–>API
交互式方法–>MFC
采用交互式方法时,可视化开发平台给出了许多选用的对象,程序员可选择所需对象并确定其属性,由此搭建起应用程序的“大框架”,并可根据需要进一步编写必要的细节代码段,最后构成完整的应用程序
- API
- 为应用程序提供Windows系统特殊函数及数据结构
- Win应用程序可以利用标准大量API函数调用系统功能
- 是Win系统与Win应用程序间的标准程序接口
- API函数的功能
- 窗口管理函数实现窗口的创建、移动和修改功能
- 系统服务函数:实现与操作系统有关的多种功能
- 图形设备(GDI)函数:实现与设备无关的图形操作功能
利用Windows API函数编写Windows应用程序必须首先了解以下内容:
(1)窗口的概念
(2)事件驱动的概念
(3)句柄
(4)消息
窗口
系统管理应用程序的基本单位,应用程序与用户之间交互的接口环境,Win应用程序基本的操作单元
一个应用程序的窗口一般包含下列成分:
- 控制菜单框
- 下拉菜单
- 标题栏
- 工作区
- 窗口边界
- 最大化按钮
- 最小化按钮
- 垂直滚动条
- 水平滚动条
编写一个Windows应用程序首先应创建一个或多个窗口,随后应用程序的运行过程即是窗口内部、窗口与窗口之间、窗口与系统之间进行数据处理与数据交换的过程。
事件驱动
Windows程序设计是针对事件或消息的处理进行(消息是描述事件发生的信息(如按下鼠标或键盘)。Windows程序的执行顺序取决于事件发生的顺序,程序的执行顺序是由顺序产生的消息驱动的,但是消息的产生往往并不要求有次序之分。
事件驱动编程方法对于编写交互式程序很有用处,它避免了死板的操作模式
句柄
句柄是PVOID型的数据一个4字节长的数值,用于标识应用程序中不同的对象和同类对象中不同的实例,应用程序通过句柄访问相应的对象信息。
HWND 窗口句柄
HDC 设备环境句柄
HBITMAP 位图句柄
HCURSOR 光标句柄
HICON 图标句柄
HFONT 字体句柄
HMENU 菜单句柄
HPEN 画笔句柄
HFILE 文件句柄
HBRUSH 画刷句柄
HINSTANCE 当前实例句柄
消息
Windows应用程序利用Windows消息(Message)与应用程序及系统进行信息交换。
消息:
- 消息号:由事先定义好的消息名标识、
- 字参数(wParam) :用于提供消息的附加信息
- 长字参数(lParam) :用于提供消息的附加信息
VC中存在几种系统定义的消息分类,不同的前缀符号经常用于消息宏识别消息附属的分类,系统定义的消息宏前缀如下:
BM 表示按钮控制消息
CB 表示组合框控制消息
DM 表示默认下压式按钮控制消息
EM 表示编辑控制消息
LB 表示列表框控制消息
SBM 表示滚动条控制消息
WM 表示窗口消息
常用消息类型
- 鼠标消息:
WM_LBUTTONDOWN
、WM_RBUTTONDBLCLK
等。 - 键盘消息:
WM_KEYDOWN
(虚拟键码)、WM_CHAR
(ASCII码)。 - 窗口生命周期消息:
WM_CREATE
(创建)、WM_CLOSE
(关闭)、WM_DESTROY
(销毁)、WM_QUIT
(退出)。 - 绘图消息:
WM_PAINT
(窗口需重绘时触发)
事件驱动程序设计
- 与传统过程驱动的区别:
- 过程驱动:严格按代码顺序执行(如输入成绩→计算平均分)。
- 事件驱动:由用户交互触发消息(如点击按钮后计算平均分)。
- 优势:灵活响应用户操作,适合交互式程序。
Windows应用程序结构
文件组成
- C源文件、头文件、模块定义文件、资源描述文件、项目文件。
程序框架
入口函数:
WinMain
(初始化、消息循环)。窗口函数:
WndProc
(处理消息的分支逻辑)。核心流程
:
- 初始化:注册窗口类(
RegisterClass
)、创建窗口(CreateWindow
)、显示窗口(ShowWindow
)。 - 消息循环:
GetMessage
获取消息→TranslateMessage
转换→DispatchMessage
分发。 - 退出:
WM_DESTROY
调用PostQuitMessage(0)
结束循环。
- 初始化:注册窗口类(
关键数据结构
WNDCLASSEX
:窗口类属性(图标、光标、背景等)。POINT
/RECT
:坐标与矩形区域定义。
第二章 Windows的图形设备接口及windows绘图
一、 GDI基础概念与设备环境(DC)
GDI定义与目的:
◦ Windows GDI (Graphics Device Interface) 是为实现设备无关性图形设计的系统组件。◦ 设备无关性: 操作系统屏蔽硬件差异,开发者编程时无需关心具体硬件配置。
GDI作用:
◦ 负责系统、用户/绘图程序之间的信息交换。◦ 控制输出设备(显示器、打印机等)上的图形和文字显示。
◦ 是Windows系统的核心组成部分。
设备环境(DC - Device Context):
◦ 本质: 设备描述表是设备环境属性的集合。◦ 角色: 是应用程序与物理输出设备之间的桥梁。
◦ 功能: 为实现图形输出的设备无关性,GDI提供统一的DC。应用程序通过DC与设备连接,利用GDI函数和设备驱动程序进行绘图。
◦ 关键点: 应用程序不能直接访问外设,必须通过DC。
二、 图形刷新
必要性: 绘图过程中必须处理窗口内容被覆盖或改变后的恢复问题。
刷新请求来源:
◦ 窗口移动、大小调整。◦ 被其他窗口(如下拉菜单、对话框)覆盖后恢复。
◦ 程序滚动窗口。
◦ 光标/图标穿越用户区(系统自动处理)。
◦ 应用程序需要恢复被覆盖部分(如颜色选择框覆盖图形后)。
系统响应:
◦ 当用户区需要刷新时,系统向应用程序消息队列发送WM_PAINT
消息。◦ 被覆盖的区域称为无效区域(Invalid Region)。
刷新数据结构:
◦ Windows为每个窗口维护一个PAINTSTRUCT
结构。◦ 关键成员:
▪ `hdc`: 刷新用的设备环境句柄。 ▪ `fErase`: 指示是否擦除无效矩形背景(通常为`TRUE`)。 ▪ `rcPaint`: 一个 `RECT` 结构,定义了包围无效区域的最小矩形(无效矩形),包含左上角(`left`, `top`)和右下角(`right`, `bottom`)坐标。
有效刷新方法:
◦ 记录事件: 刷新时重新执行导致绘图的事件。◦ 保存副本: 刷新时将保存的窗口内容副本拷贝回相应区域。
◦ 重新绘制: 最常用。将图形绘制代码放在响应
WM_PAINT
消息的模块中,刷新时调用这些代码重绘图形。应用程序根据rcPaint
标识的无效矩形进行优化绘制。
三、 获取设备环境(DC)
响应
WM_PAINT
刷新:
◦ 使用BeginPaint
函数获取DC。◦ 函数原型:
hdc = BeginPaint(hwnd, &ps);
(ps
是PAINTSTRUCT
类型变量)。◦ 作用: 获取DC的同时,系统填充
ps
结构(特别是rcPaint
)标识无效区域。◦ 释放: 必须使用
EndPaint(hwnd, &ps)
释放获取的DC。非
WM_PAINT
驱动绘图:
◦ 使用GetDC
函数获取DC。◦ 函数原型:
hdc = GetDC(hwnd);
◦ 释放: 必须使用
ReleaseDC(hwnd, hdc)
释放获取的DC。
四、 绘图工具与颜色
画笔(Pen): 用于绘制线条和形状边框。
◦ 创建:▪ 定义句柄:`HPEN hP;` ▪ 获取库存画笔:`hP = GetStockObject(STOCK_PEN_TYPE);` (如 `BLACK_PEN`, `WHITE_PEN`, `DC_PEN`, `NULL_PEN`)。 ▪ 创建新画笔:`hP = CreatePen(nPenStyle, nWidth, rgbColor);` ▪ `nPenStyle`: 线型 (`PS_SOLID`, `PS_DASH`, `PS_DOT`, `PS_DASHDOT`, `PS_DASHDOTDOT`, `PS_INSIDEFRAME`, `PS_NULL`)。 ▪ `nWidth`: 线宽(逻辑单位)。 ▪ `rgbColor`: 颜色 (`COLORREF`)。
◦ 选入DC:
SelectObject(hdc, hP);
◦ 删除:
DeleteObject(hP);
(不再使用时释放资源)。画刷(Brush): 用于填充形状内部。
◦ 创建:▪ 定义句柄:`HBRUSH hBr;` ▪ 获取库存画刷:`hBr = (HBRUSH)GetStockObject(STOCK_BRUSH_TYPE);` (如 `BLACK_BRUSH`, `DKGRAY_BRUSH`, `GRAY_BRUSH`, `LTGRAY_BRUSH`, `HOLLOW_BRUSH`, `NULL_BRUSH`, `WHITE_BRUSH`)。 ▪ 创建单色画刷:`hBr = CreateSolidBrush(rgbColor);` ▪ 创建阴影画刷:`hBr = CreateHatchBrush(nHatchStyle, rgbColor);` ▪ `nHatchStyle`: 阴影模式 (`HS_HORIZONTAL`, `HS_VERTICAL`, `HS_FDIAGONAL`, `HS_BDIAGONAL`, `HS_CROSS`, `HS_DIAGCROSS`)。
◦ 选入DC:
SelectObject(hdc, hBr);
◦ 删除:
DeleteObject(hBr);
(不再使用时释放资源)。颜色:
◦ 使用RGB
宏定义颜色:RGB(nRed, nGreen, nBlue)
(每个分量0-255)。◦ 示例:
RGB(255,0,0)
(红),RGB(0,255,0)
(绿),RGB(0,0,255)
(蓝)。◦ 也可用十六进制表示:
0x00bbggrr
(文档中0x00rrggbb
似有笔误,标准为0x00bbggrr
)。
五、 常用绘图函数
• MoveToEx(hdc, X, Y, lpPoint)
: 设置当前画笔位置到(X
,Y
),lpPoint
可返回原位置。
• LineTo(hdc, X, Y)
: 从当前位置画直线到(X
,Y
),更新当前位置。
• Polyline(hdc, lpPoints, nCount)
: 从当前位置开始,依次连接lpPoints
(指向POINT
数组)中的nCount
个点画折线。
• Arc(hdc, X1, Y1, X2, Y2, X3, Y3, X4, Y4)
: 绘制椭圆弧。(X1
,Y1
)-(X2
,Y2
)定义边框矩形,(X3,Y3)指定弧起点径向线交点,(X4,Y4)指定弧终点径向线交点。弧按逆时针方向从起点到终点绘制。
• Pie(hdc, X1, Y1, X2, Y2, X3, Y3, X4, Y4)
: 绘制饼图(填充扇形)。参数含义同Arc
,但会填充起点、终点与椭圆中心点连线形成的扇形区域。
• Rectangle(hdc, X1, Y1, X2, Y2)
: 绘制(并填充)矩形。(X1
,Y1
)左上角,(X2
,Y2
)右下角。
• RoundRect(hdc, X1, Y1, X2, Y2, nWidth, nHeight)
: 绘制(并填充)圆角矩形。nWidth
, nHeight
定义圆角椭圆的宽和高。
• Ellipse(hdc, X1, Y1, X2, Y2)
: 绘制(并填充)椭圆。(X1
,Y1
)-(X2
,Y2
)定义边框矩形。
• Polygon(hdc, lpPoints, nCount)
: 绘制(并填充)多边形。连接lpPoints
(指向POINT
数组)中的nCount
个点,并自动闭合图形。
六、 映像模式 (Mapping Mode)
目的: 定义逻辑单位如何转换为设备单位(像素、毫米等)以及设备X、Y轴的方向。实现逻辑坐标系与物理设备坐标系的映射,使程序员能在统一逻辑坐标系中工作。
关键概念:
◦ 窗口(Window): 程序员在逻辑坐标系中定义的区域。◦ 视口(Viewport): 程序员在物理输出设备上定义的区域。
◦ 映射: 将窗口中的点映射到视口中的点。映射比例由窗口范围和视口范围决定。
◦ 目标: 保持图形比例(等比例映射)或允许独立缩放(非等比例映射)。
设置与获取:
◦ 设置映像模式:SetMapMode(hdc, nMapMode);
◦ 获取当前映像模式:
nMapMode = GetMapMode(hdc);
设置窗口与视口范围 (仅对
MM_ISOTROPIC
和MM_ANISOTROPIC
有效):
◦ 设置窗口范围:SetWindowExtEx(hdc, nWidth, nHeight, lpSize);
(逻辑单位)◦ 设置视口范围:
SetViewportExtEx(hdc, nWidth, nHeight, lpSize);
(设备单位)◦ 作用: 定义窗口(逻辑)区域大小和视口(物理)区域大小,确定缩放比例。
▪ `MM_ISOTROPIC`: 强制X、Y方向缩放比例相同(保持纵横比)。 ▪ `MM_ANISOTROPIC`: 允许X、Y方向独立缩放。
设置窗口与视口原点:
◦ 设置窗口原点:SetWindowOrgEx(hdc, X, Y, lpPoint);
(逻辑坐标)◦ 设置视口原点:
SetViewportOrgEx(hdc, X, Y, lpPoint);
(设备坐标)◦ 作用: 定义逻辑坐标系原点(
SetWindowOrgEx
)映射到设备坐标系的位置(SetViewportOrgEx
)。缺省模式:
MM_TEXT
(1逻辑单位=1像素,X向右,Y向下)。获取窗口尺寸 (辅助绘图适应):
◦ 获取窗口矩形(含边框、标题栏等):GetWindowRect(hWnd, &rect);
◦ 获取客户区矩形(仅绘图区域):
GetClientRect(hWnd, &rect);
七、 应用实例 (核心要点)
例4-1:填充图形与映像模式切换
◦ 功能: 绘制圆角矩形(深灰填充)、椭圆(亮灰填充)、饼图(虚画刷填充,效果不可见)。◦ 交互: 鼠标左键点击切换6种映像模式演示:
▪ `MM_TEXT` (默认) ▪ `MM_ISOTROPIC` (窗口20x20 -> 视口10x10,图形缩小) ▪ `MM_ISOTROPIC` (窗口10x10 -> 视口20x20,图形放大) ▪ `MM_ANISOTROPIC` (窗口10x10 -> 视口20x10,横向拉伸) ▪ `MM_ANISOTROPIC` (窗口10x10 -> 视口20x5,横向拉伸纵向压缩) ▪ `MM_ISOTROPIC` (窗口10x10 -> 视口20x5,系统自动调整比例保持纵横比)
◦ 实现: 在
WM_PAINT
中根据dispMode
变量设置SetMapMode
,SetWindowExtEx
,SetViewportExtEx
,然后绘制图形。例4-2:销售数据图表 (柱形图 & 饼图)
◦ 功能: 根据季度销售数据(75,50,60,90),在窗口左侧绘制柱形图,右侧绘制饼图展示比例。◦ 关键点:
▪ 计算数据总和(`s`)和最大值(`maxValue`)。 ▪ 获取客户区尺寸(`GetClientRect`)。 ▪ 检查客户区尺寸是否足够绘图 ▪ 柱形图: ▪ 计算坐标原点(`xOrg`, `yOrg`)。 ▪ 计算坐标轴范围(`xEnd`, `yEnd`)。 ▪ 计算单位数据对应的像素(`deltaX` 水平间隔, `deltaY` 垂直高度)。 ▪ 使用不同阴影模式的画刷(`CreateHatchBrush`)绘制柱体(`Rectangle`)。 ▪ 饼图: ▪ 计算饼图中心(`xOrg`, `yOrg`)和半径(`deltaX`, `deltaY`取最小值)。 ▪ 计算每个扇形的角度(`sita = sita - 2*π*a[i]/s`)。 ▪ 使用不同颜色的单色画刷(`CreateSolidBrush`)绘制扇形(`Pie`)。
◦ 目标: 图形随窗口尺寸自动调整比例。
例4-3:模拟时钟
◦ 功能: 绘制带刻度的粉色表盘,并模拟秒针、分针、时针的实时运动。◦ 关键点:
▪ 数据结构: `TimeStructure { hour, min, sec }` 存储时间。 ▪ 定时器: 在`WM_CREATE`中设置定时器(`SetTimer`),间隔1000ms (1秒)。 ▪ 时间更新: 在`WM_TIMER`消息中增加秒数,调用`AdjustTime`函数处理进位(秒->分->时),并触发刷新(`InvalidateRect`)。 ▪ 绘制(`WM_PAINT`): ▪ 更新时间(`x.sec++`, `AdjustTime(&x)`)。 ▪ 获取客户区中心(`xOrg`, `yOrg`)。 ▪ 计算表盘半径(`rClock`)和各指针长度(`rSec`, `rMin`, `rHour`)。 ▪ 绘制粉色表盘(`Ellipse`)。 ▪ 绘制刻度: ▪ 循环60次(每分钟/秒)。 ▪ 区分整点刻度(粗长)和非整点刻度(细短)。 ▪ 使用三角函数(`sin`, `cos`)计算刻度起点和终点坐标。 ▪ 绘制指针: ▪ 秒针: 细红线(`PS_SOLID, 2`),计算角度(`sita=2π*x.sec/60`),计算端点坐标,画线(`MoveToEx`, `LineTo`)。 ▪ 分针: 粗黑线(`PS_SOLID, 5`),计算角度(`sita=2π*x.min/60`),同上。 ▪ 时针: 更粗黑线(`PS_SOLID, 10`),计算角度(`sita=2π*x.hour/12`),同上。 ▪ 窗口调整: 响应`WM_SIZE`消息刷新窗口(`InvalidateRect`)。
第三章 文本的输出方法和字体的设计
第3章 文本输出与字体设计
核心概念
1.
GDI文本输出原理
- 图形与文本无明确界限,均视为图形实体
- 使用设备无关的**逻辑字体**实现"所见即所得"
- 流程:获取文本句柄 → 设置属性 → 选入设备环境
5.1 设置文本设备环境
系统字体获取
步骤:
1
2
3HFONT hF; // 定义字体句柄
hF = GetStockObject(字体类型); // 获取系统字体
SelectObject(hdc, hF); // 选入设备环境常用系统字体类型:
字体常量 说明 ANSI_FIXED
ANSI标准固定宽度(默认字体) ANSI_VAR
ANSI可变宽度 DEFAULT_GUI
当前GUI默认字体 OEM_FIXED
设备制造商提供字体 SYSTEM_FIXED
Windows固定宽度字体
创建自定义字体
函数:
HFONT CreateFont(14个参数)
关键参数解析:
1
2
3
4
5
6int nHeight, // 字体高度(0=系统默认)
int nEscapement, // 文本行倾斜角(0.1度单位)
DWORD nWeight, // 字体粗细(0-1000,如FW_BOLD=700)
DWORD dwItalic, // 斜体(非0启用)
DWORD dwUnderline, // 下划线(非0启用)
DWORD dwCharset // 字符集(如GB2312_CHARSET)
颜色设置
- 文本色:
SetTextColor(hdc, RGB(r,g,b))
- 背景色:
SetBkColor(hdc, RGB(r,g,b))
- 文本色:
5.2 文本输出流程
获取字体信息
函数:
GetTextMetrics(hdc, &tm)
关键结构体:
1
TEXTMETRIC tm
1
2
3
4tm.tmHeight; // 总高度
tm.tmAscent; // 基线以上高度
tm.tmExternalLeading; // 行间距
tm.tmAveCharWidth; // 平均字符宽度
坐标计算
后续文本坐标:
1
2
3SIZE size;
GetTextExtentPoint32(hdc, text, len, &size); // 获取字符串尺寸
x_next = x_current + size.cx; // 计算下一文本起点换行坐标:
1
y_next = y_current + tm.tmHeight + tm.tmExternalLeading;
文本输出函数
基础输出:
1
TextOut(hdc, x, y, text, len); // 指定坐标输出
格式化输出:
1
DrawText(hdc, text, len, &rect, DT_LEFT); // 在矩形区域内左对齐输出
5.3 实例分析
例5-1:扇形诗词输出
核心逻辑:
计算扇形极坐标:
x = org.x + r*cos(θ)
,y = org.y - r*sin(θ)
动态创建字体:
1
CreateFont(高度, 0, 倾斜角, 0, FW_HEAVY, ... , "楷体_GB2312");
逐字输出:
1
TextOut(hdc, x, y, &诗句[i], 1); // 单字符输出
特效:
- 文字颜色渐变(RGB动态计算)
- 文字沿扇形径向排列
例5-2:多格式文本输出
技术要点:
1.
多行格式控制 : - 通过`tm.tmHeight + tm.tmExternalLeading`计算行间距
1
y += tm.tmHeight + 5*tm.tmExternalLeading; // 增加5倍行距
混合字体效果:
- 红色系统字体、绿色自定义粗体、蓝色粗体、灰色斜体下划线
卡拉OK效果:
1
2rect.right += 2; // 矩形右边界扩展
DrawText(hdc, text, len, &rect, DT_LEFT); // 动态绘制区域同行输出多字符串:
1
2
3TextOut(hdc, x, y, text1, len1); // 输出第一部分
GetTextExtentPoint32(...); // 计算宽度
TextOut(hdc, x+size.cx+5, y, text2, len2); // 紧接输出
关键总结
技术点 | 实现方式 |
---|---|
字体管理 | GetStockObject() 获取系统字体,CreateFont() 自定义 |
坐标计算 | GetTextMetrics() + GetTextExtentPoint32() |
基础输出 | TextOut() 直接坐标定位 |
高级排版 | DrawText() 矩形区域格式化输出 |
动态效果 | 定时器刷新 + 矩形区域扩展 |
第四章 Windows应用程序对键盘与鼠标的响应
以下是对PPT文档《第四章 Windows应用程序对键盘与鼠标的响应》的细致总结,严格依据原始内容整理:
一、键盘处理机制
输入流程
- 物理按键 → 扫描码(设备相关)→ 设备驱动程序 → 虚拟码(设备无关)→ 系统消息队列 → 线程消息队列 → 窗口过程处理。
- 虚拟码值存储在
wParam
中(如VK_BACK
、VK_RETURN
)。
消息类型
-
按键消息 :按下/释放键时触发 - 系统按键:`WM_SYSKEYDOWN`/`WM_SYSKEYUP`(Alt组合键,通常由系统处理)。 - 非系统按键:`WM_KEYDOWN`/`WM_KEYUP`(应用程序处理)。
- 字符消息:
WM_CHAR
(TranslateMessage转换后生成,对应可显示字符)。
- 字符消息:
按键消息参数解析
wParam
:虚拟键码(标识具体按键)。lParam
CreateCaret() // 创建位图插字符 ShowCaret() // 显示 SetCaretPos() // 设置位置 GetCaretPos() // 获取位置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(32位):
- 重复计数(0-15位)、OEM扫描码(16-23位)、扩展键标志(24位)、关联码(29位)、键先前状态(30位)、转换状态(31位)。
4. **特殊键处理**
- **回车键**:换行并调整字符缓冲区。
- **退格键**:删除字符并移动光标,行首时提示“已至文件头”。
- **Delete键**:行末时提示“已至文件尾”。
- **方向键**:移动光标位置(边界检查)。
- **Home/End键**:光标跳至行首/行末。
------
### **二、插字符(Caret)管理**
1. **特性**
- 指示文本输入位置,仅拥有输入焦点的窗口可持有。
- 桌面唯一,通过函数控制:static TCHAR cCharInfo[MAXLINE][MAXNUMCHAR]; // 字符缓冲区 static int nX, nY; // 光标行列位置1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2. **应用示例**
- 在 `WM_PAINT` 中计算文本尺寸 → `SetCaretPos()` 更新光标位置。
- 行编辑时动态调整坐标(如换行后光标移至新行首)。
------
### **三、鼠标处理机制**
1. **消息类型**
- 基础消息:`WM_LBUTTONDOWN`、`WM_LBUTTONUP`、`WM_MOUSEMOVE`。
- 双击消息:`WM_LBUTTONDBLCLK`(需窗口类含 `CS_DBLCLKS` 样式)。
2. **参数解析**
- `lParam`:低16位为X坐标,高16位为Y坐标(窗口客户区坐标系)。
- `wParam`:指示辅助键状态(如 `MK_CONTROL`、`MK_SHIFT`)。
3. **光标控制**
- **预定义光标**:通过 `LoadCursor(NULL, IDC_常量)` 加载(如 `IDC_WAIT`沙漏)。
- **自定义光标**:资源文件定义 → `LoadCursor(hInst, 资源名)` 加载。
- 动态切换:在 `WM_MOUSEMOVE` 中根据坐标区域设置不同光标(例:十字/箭头/I型)。
------
### **四、核心代码逻辑示例**
#### **1. 键盘输入程序(例6-1)**
-
数据结构
:WM_MOUSEMOVE1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
-
消息处理
:
- `WM_CHAR`:处理字符插入、退格、换行及边界提示。
- `WM_KEYDOWN`:处理方向键、Home/End/Del键的光标移动与删除。
- `WM_PAINT`:绘制文本并更新插字符位置。
#### **2. 组合键检测(例6-2)**
- `WM_KEYDOWN`:检测 `VK_CONTROL`。
- `WM_CHAR`:检测 `'K'`(独立按)或 `'K'-64`(Ctrl+K组合)。
- 输出对应提示信息(如"CTRL+K键被压下")。
#### **3. 鼠标动态效果(例6-3)**
-
字符串跟随光标
:
- `WM_TIMER` 定时刷新 → `WM_PAINT` 中获取光标位置 → 重绘渐变颜色字符串。
- **颜色渐变**:每个字符颜色值按 `RGB(255-color[i], color[i], 255)` 变化。
#### **4. 光标区域响应(例6-2扩展)**
- 在if (x∈[50,150] && y∈[50,150]) SetCursor(LoadCursor(NULL, IDC_CROSS)); // 十字光标1
2
3
中:My_menu MENU MOVEABLE { POPUP "文件(&F)" { MENUITEM "新建(&N)", IDM_NEW MENUITEM "打开(&O)", IDM_OPEN MENUITEM SEPARATOR MENUITEM "退出(&X)", IDM_EXIT } }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
------
### **五、关键细节**
1. **设备无关性**:虚拟码屏蔽硬件差异,确保跨设备兼容。
2. **双击检测**:窗口类必须包含 `CS_DBLCLKS` 样式,否则视为两次单击。
3. **坐标转换**:`ScreenToClient()` 将屏幕坐标转为窗口客户区坐标。
4. **资源释放**:删除创建的GDI对象(如 `DeleteObject(hF)`)
# 第五章 资源在windows编程中的应用
### **5.1 菜单和加速键资源**
#### **5.1.1 菜单的创建过程**
1. **定义菜单(资源描述文件)**
- **语法**:`menuID MENU [载入特性] { 菜单项列表 }`
- 载入特性:
- `DISCARDABLE`(可丢弃)
- `FIXED`(固定内存位置)
- `MOVEABLE`(内存可移动)
- `LOADONCALL`(需时加载)
- `PRELOAD`(立即加载)
- 菜单项类型:
- `POPUP "菜单项名" [选项]`:定义弹出菜单,选项包括 `MENUBARBREAK`(纵向分隔)、`CHECKED`(选中标志)、`INACTIVE`(禁用)、`GRAYED`(禁用且变灰)。
- `MENUITEM "文本" ID [选项]`:定义普通菜单项,`&`定义热键(如`"文件(&F)"`)。
- `MENUITEM SEPARATOR`:创建水平分隔线。
- 示例wndclass.lpszMenuName = lpszMenuName;1
2
3
4
5
2. **加载菜单资源**
- 窗口类中加载:hmenu = LoadMenu(hInstance, "My_menu"); CreateWindow(..., hmenu, ...);1
2
3
- 创建窗口时加载:SetMenu(hwnd, LoadMenu(hInstance, "Menu2"));1
2
3
- 动态加载:EnableMenuItem(hmenu, ID, MF_BYCOMMAND | MF_GRAYED);1
2
3
4
5
#### **5.1.2 操作菜单项**
1. **启用/禁用菜单项**CheckMenuItem(hmenu, ID, MF_BYCOMMAND | MF_CHECKED);1
2
3
4
5
- **选项**:`MF_BYCOMMAND`(按ID标识)、`MF_BYPOSITION`(按位置标识)、`MF_ENABLED`(启用)、`MF_GRAYED`(禁用变灰)。
2. **设置选中标志**AppendMenu()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
3. **增删改菜单项**
- **末尾添加**:`AppendMenu(hmenu, MF_ENABLED, IDM_NEW, "新建(&N)");`
- **插入**:`InsertMenu(hmenu, IDM_EXIT, MF_BYCOMMAND, IDM_PRINT, "打印(&P)");`
- **删除**:`DeleteMenu(hmenu, IDM_SAVEAS, MF_BYCOMMAND);`
- **修改**:`ModifyMenu(hmenu, IDM_OPEN, MF_BYCOMMAND, IDM_LOAD, "加载(&L)");`
4. **刷新菜单**:`DrawMenuBar(hwnd);`
#### **5.1.3 动态创建菜单**
1. 创建空菜单:`CreateMenu()`
2. 添加菜单项:InsertMenu()1
2
3
或haddmenu = CreateMenu(); AppendMenu(haddmenu, MF_ENABLED, IDM_qiuhe, "求和"); InsertMenu(hmenu, 2, MF_POPUP, (UINT)haddmenu, "统计计算(&C)");1
加速键名 ACCELERATORS { "^S", IDM_SAVE // Ctrl+S VK_F1, IDM_HELP, VIRTKEY // F1键 }1
2
3
4
5
#### **5.1.4 加速键资源**
1. **定义加速键(资源文件)**HACCEL hAccel = LoadAccelerators(hInstance, "MYMENUACCEL"); while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(hwnd, hAccel, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }1
2
3
4
5
- **选项**:`NOINVERT`(不高亮菜单项)、`ALT/SHIFT/CONTROL`(组合键)。
2. **加载与翻译**HBITMAP hBm = LoadBitmap(hInstance, "pic7"); // 从资源加载 // 或创建兼容位图:CreateCompatibleBitmap(hdc, width, height);1
2
3
4
5
6
7
8
9
------
### **5.2 位图资源**
#### **操作流程**
1. 加载位图:BITMAP bm; GetObject(hBm, sizeof(BITMAP), &bm);1
2
3
2. 获取位图信息:HDC hdcmem = CreateCompatibleDC(hdc); SelectObject(hdcmem, hBm);1
2
3
3. 选入内存设备环境:BitBlt(hdc, x, y, bm.bmWidth, bm.bmHeight, hdcmem, 0, 0, SRCCOPY);1
2
3
4. 输出位图:IDD_DIALOG1 DIALOGEX x, y, width, height STYLE DS_SETFONT | WS_POPUP | WS_CAPTION BEGIN DEFPUSHBUTTON "确定", IDOK, x, y, width, height EDITTEXT IDC_EDIT1, x, y, width, height END1
2
3
4
5
6
7
8
9
10
11
- **光栅操作码**:`SRCCOPY`(直接复制)、`SRCAND`(与操作)、`WHITENESS`(全白输出)等。
------
### **5.3 对话框资源**
#### **5.3.1 模式对话框**
1. 定义对话框(资源文件):DialogBox(hInst, "IDD_DIALOG1", hwnd, (DLGPROC)DlgProc);1
2
3
2. 显示对话框HWND hdlg = CreateDialog(hInst, "IDD_DIALOG1", hwnd, (DLGPROC)DlgProc);1
2
3
4
5
6
7
8
9
10
11
12
13
3. 处理消息:
- `WM_INITDIALOG`:初始化控件(如 `SetDlgItemText()`)。
- `WM_COMMAND`:响应按钮事件(如 `IDOK` 保存数据,`IDCANCEL` 关闭)。
- **关闭**:`EndDialog(hdlg, 0);`
#### **5.3.2 非模式对话框**
1. **样式要求**:必须包含 `WS_VISIBLE`。
2. 创建对话框:while (GetMessage(&msg, NULL, 0, 0)) { if (!IsDialogMessage(hdlg, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }1
2
3
3. 消息循环处理:1
2
3
4
5
4. **关闭**:`DestroyWindow(hdlg);`
#### **消息框(特殊模式对话框)**
MessageBox(hwnd, “内容”, “标题”, MB_OKCANCEL | MB_ICONQUESTION);
1 |
|
TREE ICON tree.ico // 自定义图标
1
2
3
2. 加载图标:
// 自定义图标
wndclass.hIcon = LoadIcon(hInstance, "TREE");
// 系统图标(如 IDI_APPLICATION)
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
------
### **关键总结**
- **菜单**:通过资源定义,支持动态增删改,加速键需配合消息循环翻译。
- **位图**:需内存设备环境操作,使用 `BitBlt` 输出。
- 对话框:
- 模式:阻塞父窗口,需 `EndDialog` 关闭。
- 非模式:需特殊消息循环和 `DestroyWindow` 关闭。
- **图标**:在窗口类中加载,区分自定义与系统图标。
- **资源文件**:统一定义各类资源(菜单、加速键、位图、对话框、图标)。
# 第六章 MFC概述
### **第6章 MFC基础知识**
#### **6.1 MFC概述**
1. **MFC定义**
- 用于编写Windows应用程序的**C++类库**,以层次结构组织。
- 封装大部分Windows API函数和控件,覆盖整个Windows操作系统功能。
2. **核心功能**
- 提供Windows图形应用程序框架及创建组件。
- 提供大量可扩展的基类,支持自定义和扩展类。
- 保持向下兼容性和跨平台移植性。
3. **发展历程**
| 版本 | 关键特性 | 配套环境 |
| -------- | ----------------------------------------------- | ------------ |
| MFC 1.0 | 基础GUI类 | MS C/C++ 7.0 |
| MFC 2.0 | 增强应用程序功能 | VC++ 1.0/1.5 |
| MFC 3.0 | 支持32位应用、Win95新控件、DAO、MAPI | VC++ 2.0 |
| MFC 4.0 | 强化数据库支持(DAO类) | - |
| MFC 4.21 | 增强Internet支持 | - |
| MFC 5.0 | 支持ODBC/DAO数据库、Win32 Internet API、ActiveX | - |
| MFC 6.0 | 活动文档容器、动态HTML(CHtmlView)、新控件 | - |
| MFC 9.0 | 支持AJax、强化数据库、工作流编程模型 | VC++ 2008 |
------
#### **6.2 MFC类的组织结构**
1. **类层次划分(10大类)**
- 根类:`CObject`
- 应用程序体系结构类
- 窗口、对话框和控件类
- 绘图和打印类
- 简单数据类型类
- 数组、列表和映射类
- 文件和数据库类
- Internet和网络类
- OLE类
- 调试和异常类
2. **关键类详解**
- **根类 `CObject`**
- 所有MFC类的基类,提供公共操作:
- 对象创建/删除、运行时类型信息、串行化支持、诊断输出。
- **应用程序体系结构类**
- `CCmdTarget`:消息映射基类(如菜单命令处理)。
- `CWinThread`:线程基类,`CWinApp`(应用程序主对象)的父类。
- 文档/视类
- 文档类管理数据,视类(`CView`)显示数据并处理用户交互。
- **可视对象类**
- `CWnd`:所有窗口的基类,封装窗口操作。
- `CView`:框架窗口客户区显示,派生类包括滚动视图(`CScrollView`)、编辑视图(`CEditView`)。
- 控件类:按钮、列表框等UI组件。
- `CDC`:设备上下文类,支持绘图操作。
- `CGdiObject`:绘图工具基类(画笔、画刷等)。
- **通用类**
- 文件类:`CFile`(文件I/O)、`CArchive`(序列化)。
- 异常类:`CException`及其子类(如内存异常`CMemoryException`、文件异常`CFileException`)。
- 模板收集类:管理数组、列表、映射等数据结构。
- **OLE类**
- 支持OLE技术,包含9个核心类(如`COleDocument`、`COleServer`)。
- **ODBC数据库类**
- `CDatabase`:连接数据源。
- `CRecordset`:操作记录集。
- `CRecordView`:表单视图显示记录。
------
#### **6.3 全局函数与变量**
- **命名规则**:以 `Afx` 为前缀(数据库类函数除外)。
- 常用全局函数:
- `AfxMessageBox()`:弹出消息框。
- `AfxGetApp()`:获取当前应用程序对象指针。
- `AfxBeginThread()`:创建新线程。
- `AfxRegisterWndClass()`:注册窗口类。
------
#### **6.4 应用程序向导**
- 用于生成**单文档应用(SDI)** 框架,提供项目配置选项卡。
------
### **关键要点总结**
1. **MFC定位**:封装Windows API的C++类库,提供应用程序框架和组件。
2. **类层次结构**:以`CObject`为根,10大类覆盖从UI到数据库的全功能支持。
3. 核心类:
- `CWinApp`管理应用生命周期,`CWinThread`支持多线程。
- 文档/视结构分离数据管理与显示逻辑。
- `CWnd`和`CDC`实现窗口与绘图功能。
4. 扩展能力:
- 数据库(ODBC/DAO)、Internet(Win32 Internet API)、OLE技术深度集成。
5. 开发支持
- 全局函数简化常用操作(如`AfxMessageBox`)。
- 应用程序向导快速生成项目框架。
# 第7章 Windows 标准控件在可视化编程中的应用
#### **7.1 概述**
• 控件的作用:Windows GUI的核心组件,用户通过控件与应用程序交互,体现面向对象特性。
• 控件添加方法:
1. 代码创建:
◦ 步骤:定义控件对象(如 `CButton mybtn`)→ 调用 `Create()` 初始化(指定样式、位置、父窗口、ID)→ 显示控件(`ShowWindow()`)→ 管理控件(`MoveWindow()`, `SetWindowText()`等)。
◦ 备注:需预定义窗口类。
2. 可视化工具:在对话框编辑器中拖放控件。
• 消息映射机制:
• 目的:绑定控件事件与处理函数。
• 流程:
◦ 声明消息处理函数(如 `afx_msg void OnBnClickedButton1();`)。
◦ 添加消息映射宏(如 `ON_BN_CLICKED(IDC_BUTTON1, OnBnClickedButton1)`)。
◦ 实现处理函数(如 `void CMyDlg::OnBnClickedExit() { OnOK(); }`)。
• 控件使用技巧:
1. 获取控件指针:`GetDlgItem(IDC_EDIT1)` 返回 `CWnd*`。
2. 控件变量绑定:
◦ Control型:访问控件成员(如 `CEdit* pEdit`)。
◦ Value型(如 `CString`):通过 `UpdateData(TRUE/FALSE)` 刷新数据,依赖 `DoDataExchange()` 中的 `DDX_Text` 等函数。
• 自定义控件类:
• 步骤:继承MFC控件类(如 `CButton`)→ 添加新功能成员 → 在变量类型中使用自定义类。
---
#### **7.2 按钮控件(CButton)**
• 类型:普通按钮、单选按钮、复选框、组框、自绘按钮。
• 创建方法:
```cpp
BOOL Create(LPCTSTR lpszCaption, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
• 常用消息:
• ON_BN_CLICKED
:单击事件。
• ON_BN_DBLCLICKED
:双击事件。
• 状态管理函数:
• GetCheck()
/SetCheck()
:获取/设置选中状态。
• SetBitmap()
/SetIcon()
:设置位图/图标。
• 特殊按钮类:
• CBitmapButton
:支持4种状态位图(正常、按下、聚焦、禁用),通过 LoadBitmaps()
加载。
7.3 滚动条控件(CScrollBar)
• 与窗口滚动条的区别:独立创建、由用户管理。
• 关键消息码:
• SB_LINEUP/DOWN
:单步滚动。
• SB_PAGEUP/DOWN
:翻页滚动。
• SB_THUMBTRACK
:拖动滑块。
• 初始化步骤:
- 创建对象:
CScrollBar* pMyScroll = new CScrollBar
。 - 初始化:
pMyScroll->Create(...)
。 - 设置范围:
pMyScroll->SetScrollRange(min, max)
。 - 设置位置:
pMyScroll->SetScrollPos(value)
。
7.4 静态控件(CStatic)
• 特点:默认不发送消息,需添加 SS_NOTIFY
样式才能响应事件(如单击)。
• 应用示例:
• 显示位图:m_bmp.ModifyStyle(0, SS_BITMAP)
+ SetBitmap()
。
• 响应单击:处理 BN_CLICKED
消息,获取位图尺寸并显示。
7.5 列表框控件(CListBox)
• 功能:从列表中选择单项或多项。
• 关键方法:
• 通用:AddString()
, DeleteString()
, ResetContent()
。
• 单项选择:GetCurSel()
, SetCurSel()
。
• 多项选择:GetSelItems()
, SetSel()
。
• 消息传递:
• 用户操作 → 发送 WM_COMMAND
(含 LBN_DBLCLK
等通知码)。
• 程序操作:通过 SendMessage
发送消息(如 LB_DIR
加载文件列表)。
7.6 编辑框控件(CEdit)
• 类型:单行/多行(支持滚动条)。
• 数据交互:
• 获取/设置文本:GetWindowText()
/SetWindowText()
。
• 剪贴板操作:Copy()
, Paste()
。
• 撤销操作:Undo()
。
• 实时计算示例:编辑框内容变化时触发 OnEnChangeNum1()
更新结果。
7.7 组合框控件(CComboBox)
• 特点:编辑框 + 列表框的组合。
• 常用方法:
• AddString()
:添加选项。
• GetCurSel()
/GetLBText()
:获取选中项。
• 消息响应:CBN_SELCHANGE
选项改变时触发。
7.8 对话框通用控件
Picture控件:
• 分隔线:设置Type=Frame
,Color=Etched
。• 显示图片:
Type=Bitmap/Icon
, 绑定资源ID。Spin控件:
• 与伙伴控件(如编辑框)联动:设置Auto Buddy
和SetBuddy()
。• 范围设置:
SetRange(0, 100)
。Progress控件:
• 初始化:SetRange(0,100)
,SetPos(0)
。• 模拟进度:定时器调用
SetPos(i++)
。Slider控件:
• 响应滑动:处理WM_HSCROLL
消息,用GetPos()
更新显示。DateTimePicker控件:
• 格式化日期:SetFormat("'Today: 'yy'/'MM'/'dd")
。• 获取时间:
GetTime(t)
→t.Format()
。List Control控件:
• 视图模式:图标/列表/报表。• 关键操作:
InsertItem()
, 响应LVN_ENDLABELEDIT
编辑标签。Tree Control控件:
• 构建层级:InsertItem()
填充TV_INSERTSTRUCT
结构。• 消息响应:
TVN_SELCHANGED
获取选中项,TVN_ENDLABELEDIT
编辑节点。
核心知识点总结
• 控件共性:通过 Create()
动态创建或资源编辑器添加,依赖消息映射处理事件。
• 数据绑定:DDX
机制实现控件与变量同步(UpdateData()
)。
• 高级控件:如 CListCtrl
和 CTreeCtrl
需配合图像列表(CImageList
)管理图标。
• 交互设计:滚动条/滑块的范围控制、Spin的伙伴控件、Progress的定时更新等需精细处理。
此总结完全基于原始文档内容,未增删技术细节,保留了所有关键API、消息机制和示例逻辑。
第8章 在MFC中创建应用程序的资源
8.0 资源基础
- 资源特性
- 独立于代码,由Resource Compiler编译后嵌入可执行文件。
- 支持复用:通过导入/导出功能实现。
- 国际化:通过资源替换实现多语言支持。
- 资源查看示例
- 路径:
c:\Windows\cards.dll
或c:\WINNT\System32
(查看图片资源)。
- 路径:
8.2 资源应用
8.2.1 菜单资源
示例功能
单文档程序显示字符串”Hello World!”,通过菜单控制显示状态和颜色(红/绿/蓝)。关键步骤
1.
成员变量声明 (
):1
CMy_ResView.h
1
2
3
4COLORREF m_nColors[3]; // 颜色数组
DWORD m_nColorIndex; // 当前颜色索引
CString m_strShow; // 显示内容
BOOL m_bShow; // 显示状态初始化
(构造函数):
1
2
3
4
5
6m_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 = L"Hello World!";
m_bShow = TRUE;绘制字符串
(
1
OnDraw
):
1
2
3
4if(m_bShow) {
pDC->SetTextColor(m_nColors[m_nColorIndex]);
pDC->TextOut(100, 100, m_strShow);
}
消息处理机制
COMMAND消息
(菜单点击响应):
- 函数:
OnOperShow()
,切换m_bShow
并刷新视图。 - 映射:
ON_COMMAND(ID_OPER_SHOW, OnOperShow)
。
- 函数:
UPDATE_COMMAND_UI消息
(菜单状态更新):
- 函数:
OnUpdateOperShow(CCmdUI* pCmdUI)
,设置勾选状态。 - 方法:
pCmdUI->SetCheck(m_bShow)
。
- 函数:
批量处理连续ID
(颜色菜单):
- 宏:
ON_COMMAND_RANGE(ID_OPER_RED, ID_OPER_BLUE, OnOperColorChange)
。 - 函数:
OnOperColorChange(WORD nID)
,计算颜色索引。 - 更新宏:
ON_UPDATE_COMMAND_UI_RANGE
,设置单选状态。
- 宏:
8.2.2 快捷菜单
创建步骤
新增菜单资源
IDR_MENU_POP
。声明变量:
CMenu m_PopMenu
,CMenu* m_pPop
。加载资源(构造函数):
m_PopMenu.LoadMenu(IDR_MENU_VIEW)
。右键响应:
1
OnRButtonDown()
中显示菜单:
1
2m_pPop = m_PopMenu.GetSubMenu(0);
m_pPop->TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this);
8.2.3 加速键
- 添加方法
- 在加速键资源表(
IDR_MAINFRAME
)新增条目。 - 绑定菜单项ID(如
ID_OPER_SHOW
)。 - 设置快捷键:按
Ctrl+W
自动填充属性。
- 在加速键资源表(
8.2.4 工具条
关键类:
CToolBar
(派生自CWnd
)。创建流程
添加工具条资源
IDR_TOOLBAR_NEW
。在
CMainFrame
声明变量:CToolBar m_wndToolBarNew
。OnCreate()
m_wndToolBarNew.CreateEx(...); m_wndToolBarNew.LoadToolBar(IDR_TOOLBAR_NEW);1
2
3
中创建并加载:m_wndToolBarNew.EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBarNew);1
2
3
4
5
6
7
4.
停靠设置
:CInputDlg dlgInput; if (dlgInput.DoModal() == IDOK) { m_strShow = dlgInput.m_strInput; Invalidate(); }1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
- **样式控制**:
`SetBarStyle()` 设置提示文本(`CBRS_TOOLTIPS`)和动态尺寸(`CBRS_SIZE_DYNAMIC`)。
------
##### **8.2.5 图标资源**
- **用途**:程序窗口/任务栏/资源管理器图标。
- 修改方法
1. 编辑资源 `IDR_MAINFRAME`。
2. 支持多尺寸:16×16(任务栏)、32×32(对话框)、48×48(缩略图)。
3. 通过 **New Device Image** 添加新尺寸。
------
##### **8.2.6 字符串资源**
- 多语言支持
1. 在字符串表新增条目(如 `IDS_STRING_HELLO`)。
2. 代码加载:`m_strShow.LoadString(IDS_STRING_HELLO)`。
- **优势**:集中管理字符串,便于维护和国际化。
------
##### **8.2.7 对话框资源**
- 创建步骤
1. 添加对话框资源 `IDD_DIALOG_NEW`。
2. 绑定类 `CInputDlg`,关联控件变量 `m_strInput`(`DDX_Text` 映射)。
3. 使用对话框:CDC dcMemory; dcMemory.CreateCompatibleDC(pDC); dcMemory.SelectObject(&bmp);1
2
3
4
5
6
7
8
9
10
11
12
13
------
##### **8.2.8 位图资源**
- 显示流程
1. 加载位图资源:`bmp.LoadBitmap(IDB_BITMAP_256)`。
2. 获取尺寸:`bmp.GetBitmap(&bmpInfo)`。
3. 内存DC缓冲:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
4. 绘制到屏幕:`pDC->BitBlt(...)`。
- **注意事项**:VC6 仅支持 ≤256 色位图编辑。
------
### **关键总结**
- **资源复用**:通过导入/导出实现跨项目共享。
- 消息机制:
- `COMMAND` 响应操作,`UPDATE_COMMAND_UI` 更新状态。
- `ON_COMMAND_RANGE` 批量处理连续ID。
- **资源类型关联**:菜单、加速键、工具条需绑定同一ID实现功能统一。
- **内存管理**:手动释放资源(如 `m_PopMenu.DestroyMenu()`)。
# 第9章 单文档与多文档
###
#### **9.1 概述**
1. 9.1.1 单文档界面(SDI)与多文档界面(MDI)
• SDI特点:
◦ 仅一个主窗口(`CMainFrame`基类为`CFrameWnd`)。
◦ 每次操作一个文档(如记事本)。
• MDI特点:
◦ 多个子窗口(`CMainFrame`基类为`CMDIFrameWnd`)。
◦ 同时操作多个文档(如Visual Studio)。
• 创建流程:
◦ 使用AppWizard创建SDI/MDI过程相似。
◦ MDI通过`CDocument::OnNewDocument`创建子窗口。
2. 9.1.2 文档/视图结构
• 核心分工:
◦ 文档类(CDocument):
◦ 管理数据(成员变量存储)。
◦ 串行化(`Serialize`)保存/加载数据。
◦ 仅处理`WM_COMMAND`消息(菜单/工具栏)。
◦ 视图类(CView):
◦ 显示数据(通过`GetDocument`访问文档)。
◦ 接收用户输入并更新文档。
◦ 可处理所有Windows消息。
• 工作机制:
◦ 视图通过`GetDocument`获取文档指针。
◦ 用户通过视图修改数据 → 视图通知文档更新 → 文档保存数据。
3. 9.1.3 SDI对象创建流程
• 在`InitInstance()`中通过文档模板创建:
```cpp
CSingleDocTemplate* pDocTemplate = new CSingleDocTemplate(
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc), // 文档类
RUNTIME_CLASS(CMainFrame), // 框架类
RUNTIME_CLASS(CMyView) // 视图类
);
AddDocTemplate(pDocTemplate);
9.1.4 SDI消息传递
•WM_COMMAND
消息传递路径:视图 → 文档 → 文档模板 → 框架窗口 → 应用程序。
9.2 Doc/View框架核心类
类 | 核心职责 | 关键成员/方法 |
---|---|---|
CWinApp | 管理进程生命周期、消息循环、资源 | m_pMainWnd (主窗口指针)LoadCursor() (加载资源) |
CDocument | 数据管理、串行化、维护视图列表 | SetModifiedFlag() (标记修改)UpdateAllViews() (刷新视图)Serialize() |
CView | 数据显示、用户交互 | OnDraw() (绘制数据)GetDocument() (获取文档指针) |
CDocTemplate | 关联文档/视图/框架对象 | 构造函数绑定运行时类(文档、框架、视图) |
CFrameWnd | 管理框架窗口(菜单/工具栏/状态栏) | 维护视图布局和消息路由 |
9.3 关键技术概念
9.3.1 串行化(Serialization)
• 流程:通过CArchive
对象读写数据。1
2
3
4void CMyDoc::Serialize(CArchive& ar) {
if (ar.IsStoring()) ar << m_data; // 保存
else ar >> m_data; // 加载
}• 文件操作路径:
CWinApp::OnFileOpen
→CDocument::OnOpenDocument
→Serialize()
。9.3.2 消息映射(Message Map)
• 机制:消息处理函数绑定(通过宏实现):1
2
3
4BEGIN_MESSAGE_MAP(CMyView, CView)
ON_COMMAND(ID_EDIT_CUT, OnEditCut) // 菜单命令
ON_WM_MOUSEMOVE() // Windows消息
END_MESSAGE_MAP()9.3.3 消息传递顺序
视图 → 文档 → 文档模板 → 子框架(MDI)→ 主框架 → 应用程序。
9.4 SDI实例:动态文本显示
• 功能:窗口中央显示文本,通过对话框修改内容。
• 关键实现:
- 文档类:
定义CString m_str
存储文本,在OnNewDocument()
中初始化。 - 菜单命令:
调用对话框修改m_str
,触发UpdateAllViews(NULL)
刷新视图。 - 视图类:
OnDraw()
中调用pDC->TextOut()
居中显示文本。 - 串行化:
Serialize()
中保存/加载m_str
。
9.5 MDI实例:多类型文档支持
• 功能:支持文本文档(默认)和绘图文档。
• 关键实现:
多文档模板注册:
1
2
3
4
5
6
7
8// 在InitInstance()中添加第二类文档模板
CMultiDocTemplate* pDocTemplate2 = new CMultiDocTemplate(
IDR_MYMDITYPE2, // 资源ID
RUNTIME_CLASS(CMyMdiDoc2), // 自定义文档类
RUNTIME_CLASS(CChildFrame), // 子框架
RUNTIME_CLASS(CMyMdiView2) // 自定义视图类
);
AddDocTemplate(pDocTemplate2);绘图文档:
◦ 文档类:用CPtrArray m_data
存储图形数据(DrawData
对象)。◦ 视图类:处理鼠标事件(
OnLButtonDown/Up
),在OnDraw()
中绘制图形。资源定制:
◦ 为第二类文档定义独立菜单(ID范围:ID_LINE
至ID_RECTANGLE
)。
附录:关键技术速查表
操作 | 方法 |
---|---|
获取文档关联的视图 | GetFirstViewPosition() + GetNextView() |
视图获取文档指针 | GetDocument() |
视图获取框架窗口 | GetParentFrame() |
全局获取应用程序对象 | AfxGetApp() |
强制刷新视图 | Invalidate() + UpdateWindow() |