第 三 部 分 编 程 帮 助 工 具
第 6 章 C lass W izard ( 类 向 导 )
用 AppWizard 创 建 一 个 项 目 之 后 , 你 便 拥 有 了 ClassWizard 这 个 Visual C++ “ 程序 员 助 手 ” 选 项 。 从 广 义 上 讲 , ClassWizard 与 类 的 关 系 和 AppWizard 与 应 用 程序 的 关 系 是 相 同 的 。 ClassWizard 通 过 生 成 实 现 CPP 文 件 , 以 及 一 个 带 有 合 适 存根 函 数 的 头 文 件 ,来 帮 助 你 开 始 编 写 新 类 。用 实 际 的 代 码 填 充 这 些 函 数 则 是 你 的责 任 。
ClassWizard 在 四 个 区 域 提 供 帮 助 , 它 可 以 为 如 下 目 的 生 成 代 码 :
-
从 接 收 消 息 或 管 理 控 件 窗 口 的 许 多 MFC 类 中 的 一 个 派
生 出 来 的 新类。
-
处 理 消 息 的 成 员 函 数 。
-
OLE/ActiveX 方 法 、 属 性 和 事 件 触 发 。
-
用 于 输 入 到 对 话 控 件 中 的 数 据 交 换 和 验 证 函 数 。
ClassWizard 识 别 和 支 持 MFC 基 类 , 它 们 用 某 种 方 法 与 用 户 进 行 交 互 。除 了 少 数例 外 的 类 ( 例 如 CRecordSet 和 CHttpServer) 之 外 , 基 类 都 是 由 CCmdTarget 派
生 而 来 , 它 们 能 够 对 消 息 作 出 反 应 , 并 能 够 管 理 对 话 框 中 的 控 件 。 大 约 有 50 个多 个 MFC 基 类 , 你 可 以 使 用 ClassWizard 从 这 样 的 类 中 创 建 一 个 派 生 类 ; 参 考本 书 附 录 B , 可 以 得 到 一 个 完 整 列 表 。
访 问 ClassWizard
不 能 从 一 个 空 的 项 目 中 访 问 ClassWizard 。项 目 中 至 少 应 有 一 个 RC 文 件 ,即 使 这个 RC 文 件 是 空 的 。 一 旦 RC 文 件 被 附 加 到 项 目 之 中 ( AppWizard 可 以 自 动 完 成这 项 工 作 ), 你 就 可 以 通 过 从 View 菜 单 中 选 择 ClassWizard 命 令 来 调 用ClassWizard 对 话 了 , 如 图 6-1 所 示 。
图 6-1 View 菜单中的 ClassWizard
关 于 ClassWizard , 有 两 点 不 大 明 显 。 首 先 , 它 的 服 务 完 全 是 可 选 的 。 你 在 开 发自 己 项 目 的 过 程 中 , 如 果 自 己 愿 意 的 话 , 从 头 至 尾 , 都 可 以 不 处 理 ClassWizard 。其 次 , 你 可 以 使 用 ClassWizard 向 MFC 项 目 添 加 新 类 , 即 使 该 项 目 不 是 由AppWizard 创 建 的 。 ClassWizard 编 译 项 目 的 类 的 数 据 库 , 并 将 它 存 储 在 与 项 目同 名 且 扩 展 名 为 CLW 的 一 个 文 件 之 中 。 如 果 你 一 直 都 是 使 用 ClassWizard 为 项目 创 建 新 类 , 那 么 CLW 文 件 可 以 保 持 最 新 。 不 过 , 在 Visual C++ 中 , 你 与ClassWizard 之 间 并 不 是 全 有 或 全 无 的 关 系 , 你 可 以 自 由 地 编 写 新 类 , 或 者 从 当前 项 目 之 外 的 其 他 源 文 件 中 复 制 代 码 。 在 一 个 类 不 是 以 ClassWizard 为 起 源 的 情况 下 , 有 一 个 简 单 的 方 法 可 以 更 新 CLW 数 据 库 。 在 你 使 用 了 Project 菜 单 上 的Add To Project 命 令 向 项 目 添 加 新 类 源 文 件 之 后 , 请 删 除 CLW 文 件 ,并 再 次 调 用
ClassWizard 。 Visual C++ 将 检 测 到 数 据 库 不 存 在 了 , 并 提 供 重 新 创 建 它 的 服 务 :
当 你 单 击 Yes 接 受 创 建 新 数 据 库 的 服 务 之 后 , 将 出 现 一 个 标 题 为 Select Source Files 的 对 话 ,其 中 带 有 一 个 Visual C++ 创 建 类 数 据 库 将 要 读 取 的 实 现 文 件 和 文 件夹 列 表 。如 果 你 已 经 将 全 部 的 新 源 文 件 都 插 入 到 了 项 目 之 中 ,那 么 列 表 应 该 已 经是 完 整 的 了 , 因 此 除 单 击 O K 外 , 你 不 需 要 做 任 何 事 情 。 进 程 指 示 器 主 要 用 来 指示 Visual C++ 正 在 创 建 数 据 库 文 件 , 在 此 之 后 , 将 出 现 ClassWizard 对 话 框 。
ClassWizard 对 话
图 6-2 显 示 了 主 ClassWizard 对 话 框 。 我 之 所 以 叫 它 为 “ 主 ” 对 话 , 是 因 为
ClassWizard 可 以 在 20 多 种 不 同 的 对 话 中 显 示 自 己 , 究 竟 在 哪 一 个 对 话 中 显 示 需
取 决 于 环 境 。 图 6-2 中 的 对 话 充 当 着 到 ClassWizard 主 入 口 的 角 色 , 将 其 命 名 为MFC ClassWizard , 以 便 于 让 你 记 住 它 所 处 理 的 仅 仅 是 MFC 类 。 ClassWizard 不能 帮 助 你 创 建 从 除 了 支 持 MFC 类 之 外 的 任 何 类 中 派 生 的 类 ; 对 于 带 有 任 何 其 他基 的 类 , 你 必 须 使 用 文 本 编 辑 器 或 Insert 菜 单 上 的 New Class 命 令 从 零 开 始 自 己编 写 代 码 。 在 本 章 稍 后 将 详 细 介 绍 New Class 命 令 。
图 6-2 MFC ClassWizard 对话
MFC ClassWizard 对 话 的 五 个 选 项 卡 具 有 不 同 的 用 途 , 对 于 任 何 一 个 特 定 的 类 , 都 不 是 完 全 需 要 这 五 个 选 项 卡 。表 6-1 可 以 帮 助 你 确 定 自 己 需 要 哪 个( 或 哪 几 个 ) 选 项 卡 , 这 主 要 取 决 于 你 想 为 自 己 的 类 做 哪 些 工 作 。
表 6-1 MFC C lass W izard 对 话 框 的 五 个 选 项 卡选 项 卡 用 途
M essage Map s( 消 息 映射 )
M ember Variables ( 成员 变 量 )
添 加 或 删 除 处 理 消 息 的 成 员 函 数
添 加 或 删 除 附 加 到 使 用 控 件 的 类 上 的 成 员变 量 。 一 般 地 说 , 这 些 是 从 CDialog , CPropertyPage , CRecordView 或CDaoRecordView 中 派 生 的 对 话 类
Automation 向 支 持 Automation 的 类 ( 例 如 ActiveX 控
件 类 ) 添 加 属 性 或 方 法
续 表
ActiveX Events 为 触 发 事 件 ( 通 常 是 实 现 ActiveX 控 件 的
类 )添 加 支 持 。在 开 发 接 收 触 发 事 件 的 容 器应 用 程 序 时 , 不 用 该 选 项 卡
Class Info 有 关 项 目 的 类 的 其 他 信 息
在 ClassWizard 对 话 中 , 标 为 M essage Maps 和 Member Variables 的 头 两 个 选 项 卡将 在 下 两 节 介 绍 。Automation 和 ActiveX Event 选 项 卡 的 讨 论 推 迟 到 第 8 章 和 第 9 章 , 这 两 章 将 阐 述 ClassWizard 如 何 在 包 含 ActiveX 控 件 的 项 目 开 发 中 起 帮 助 作用 。
Message Maps ( 消 息 映 射 ) 选 项 卡
M essage Map s( 消 息 映 射 ) 选 项 卡 是 你 为 自 己 的 类 指 定 消 息 处 理 函 数 的 地 方 。 该选 项 卡 中 的 两 个 组 合 框 和 前 两 个 列 表 框 是 这 样 安 排 的 , 每 个 控 件 都 显 示 逐 渐 高 一级 的 控 件 详 细 资 料 。换 句 话 说 ,控 件 的 内 容 取 决 于 前 面 控 件 中 的 选 中 部 分 。Class Nam e( 类 名 ) 组 合 框 列 出 了 Project 组 合 框 中 选 中 的 项 目 的 类 ; Object IDs 框 中显 示 的 是 与 Class Name 框 中 选 中 的 类 相 关 联 的 标 识 符 , M essage 框 中 显 示 的 是Object IDs 框 中 当 前 选 中 部 分 的 消 息 和 其 他 信 息 。 表 6-2 显 示 了 Object IDs 框 中
选 中 的 项 目 和 M essage 框 内 容 之 间 的 关 系 。
表 6-2 在 Message Map 选 项 卡 中 , Object Ids 框 中 的 选 中 部 分 决 定 了 Message
框 的 内 容
Object IDS 框 中 选中 部 分
Message 框 的 内 容
类 名 W M _ 消 息 和 处 理 消 息 的 类 虚 拟 函 数
菜 单 命 令 标 识 符 用 于 菜 单 命 令 消 息 的 ON_COMMAD 和
ON_COMMAND_UI 宏
控 件 标 识 符 控 件 通 知 消 息 。 反 应 的 消 息 用 等 于 ( = ) 前 缀
标 记
当 你 在 M essage 框 中 选 中 一 条 消 息 或 虚 拟 函 数 的 时 候 ,将 在 MFC ClassWizard 对话 的 底 部 出 现 选 中 项 目 的 简 要 说 明 。 如 果 想 了 解 有 关 选 中 项 目 的 详 细 信 息 , 可 以像 第 一 章 中 介 绍 的 那 样 切 换 到 M S D N 在 线 帮 助 ,然 后 再 搜 索 索 引 。与 Visual C++ 旧 版 本 不 同 , 按 下 F1 键 将 显 示 有 关 M essage 框 本 身 的 一 般 信 息 , 而 不 是 有 关 选中 项 目 的 信 息 。
如 果 想 向 选 定 的 类 添 加 消 息 处 理 程 序 函 数 ,请 双 击 Message 框 中 的 消 息 或 虚 拟 函
数 。Member Functions 框 包 含 有 当 前 类 函 数 的 一 个 列 表 ,在 图 6-2 中 是 InitInstance 和 OnAppAbou t 。“ W ” 标 识 符 将 OnAppAbout 作 为 一 个 处 理 带 有 W M _ 前 缀 的 系统 消 息 的 函 数 来 标 识 , 在 本 例 中 , 是 包 含 有 ID_APP_ABOUT 菜 单 值 的W M _ C O M M A N D 。“ V ” 用 来 将 InitInstance 作 为 一 个 超 越 虚 拟 函 数 来 标 识 。
对 于 添 加 到 类 的 每 个 消 息 处 理 程 序 函 数 , ClassWizard 对 该 类 的 源 文 件 做 三 处 修改 :
-
向 头 文 件 添 向 函 数 声 明 。
-
向 CPP 实 现 文 件 添 加 带 有 骨 干 代 码 的 函 数 定 义 。
-
将 代 表 该 函 数 的 条 目 添 加 到 类 的 消 息 映 射 。
Member Variables ( 成 员 变 量 ) 选 项 卡
M ember Variables( 成 员 变 量 ) 选 项 卡 与 使 用 控 件 的 类 相 关 , 这 些 类 中 的 大 部 分是 从 CDialog , CPropertyPage, CFormView , CRecordView 或 CDaoRecordView 中 派 生 出 来 的 。 从 上 述 五 个 MFC 类 中 的 一 个 派 生 出 来 的 类 叫 做 对 话 类 , 因 为 它需 要 一 个 代 表 对 话 资 源 的 标 识 符 。 Member Variable s( 成 员 变 量 ) 选 项 卡 是 指 定从 类 对 话 中 的 控 件 中 接 收 数 据 的 成 员 变 量 的 地 方 。
如 果 想 向 对 话 类 添 加 成 员 变 量 , 请 打 开 M ember Variables ( 成 员 变 量 ) 选 项 卡 , 并 从 Class Nam e( 类 名 ) 框 中 选 择 类 。 在 Control IDs 框 中 , 选 择 你 想 向 其 上 附加 新 变 量 的 控 件 的 标 识 符 , 然 后 单 击 Add Variable 按 钮 打 开 如 图 6-3 所 示 的 Add M ember Variable 对 话 。
图 6-3 从 Member Variables( 成 员 变 量 ) 选 项 卡 中 调 用 的 Add Member Variable 对话框
在 可 选 的“ M ” 前 缀 后 面 键 入 变 量 名 , 然 后 根 据 控 件 类 型 , 在 Category 框 中 选 择Value 或 Control。 Value 设 置 的 意 思 是 指 该 变 量 包 含 有 这 个 控 件 的 数 据 , 例 如 用户 向 编 辑 框 键 入 的 文 字 或 数 字 值 。 Control 设 置 的 意 思 是 该 变 量 代 表 控 件 本 身 。作 为 一 个 例 子 , 可 以 把 成 员 变 量 考 虑 成 一 个 复 选 框 控 件 。 选 定 Value 类 别 可 以 使该 成 员 变 量 成 为 Boolean 型 , 能 够 包 含 有 用 来 指 示 该 复 选 框 状 态 的 值 TRUE 或FALSE 。然 而 ,选 择 Control 类 别 , 将 使 变 量 成 为 一 个 代 表 复 选 框 控 件 的 CButton 对 象 。如 果 你 想 使 用 该 变 量 来 确 定 用 户 是 打 开 还 是 关 闭 了 这 个 复 选 框 ,那 么 请 选择 Value 类 别 。 如 果 你 想 使 用 该 变 量 在 运 行 时 以 某 种 方 式 改 变 复 选 框 , 例 如 通 过调 用 CButton:SetWindowText 来 改 变 标 题 ,或 通 过 调 用 CButton::SetCheck 设 置 复选 框 的 状 态 , 那 么 请 选 择 Control 类 别 。
表 6-3 列 出 了 可 用 的 标 准 控 件 的 变 量 类 型 。 当 你 阅 读 该 表 时 , 请 记 住 如 下 几 点 :
-
编 辑 框 特 别 适 合 将 数 据 传 递 给 许 多 不 同 类 型 的 变 量 。
表 中 提 到 的 “ 数字 ”数 据 类 型 是 一 个 包 罗 万 象 的 术 语 ,它 包 括 BYTE ,short ,int ,UNIT , long, DWORD , float 和 double 。
-
ClassWizard 不 列 出 由 IDC_STATIC 值 标 识 的 静 态 控 件 。如 果
想 把 静 态控 件 与 变 量 关 联 起 来 , 应 首 先 为 该 控 件 分 配 一 个 除 了 IDC_STATIC 之外 的 值 。
-
在 一 组 单 选 按 钮 中 , 仅 有 该 组 中 第 一 个 按 钮 的 标 识 符
出 现 在 Control ID s 框 中 。 当 我 们 稍 后 讨 论 与 小 组 的 第 一 个 按 钮 相 关 联 的 单 个 变 量 是
如 何 代 表 整 个 小 组 的 时 候 , 你 就 会 清 楚 为 什 么 不 包 括 小 组 中 其 他 按 钮的 原 因 。
- 正 如 表 中 所 指 示 的 , Push 按 钮 控 件 不 允 许 Value 类 别 的
变 量 , 因 为 这些 控 件 不 接 受 来 自 用 户 的 数 据 。
表 6-3 用 于 标 准 控 件 的 Value 和 Control 类 别 的 变 量 类 型
数
据 类 型
控 件 |
Value 类 别 |
Control 类 别 |
|||
---|---|---|---|---|---|
复 选 框 |
BOOL |
CButton |
|||
复 选 框态 ) |
( |
三 |
Int |
CButton |
|
组 合 框 |
CString 或 |
int |
CComboxBox |
编 辑 框 CString, BOOL , 数 字 ,
续 表
CEdit
COleDateTime |
或 | ||
---|---|---|---|
列 表 框 |
COLeCurrency Cstring 或 int |
CListBox |
|
压 入 式 按 钮 |
CButton |
||
单 选 按 钮 |
Int |
CButton |
|
滚 动 条 静 态 文 本 |
int CString |
CScrollBar CStatic |
通 过 使 用 ClassWizard 向 对 话 类 添 加 成 员 变 量 ,你 可 以 利 用 ClassWizard 所 提 供 的高 效 特 征 : 为 对 话 数 据 交 换 和 对 话 数 据 验 证 自 动 生 成 源 代 码 ,也 就 是 人 们 所 熟 知的 DDX/DDV 。 数 据 交 换 和 验 证 仅 仅 应 用 于 为 之 选 定 了 Value 类 别 的 成 员 变 量 。也 就 是 说 , 具 有 在 表 6-3 中 间 那 列 列 出 的 类 型 的 成 员 变 量 。
对 话 数 据 交 换 负 责 数 据 在 控 件 中 的 进 出 。当 对 话 首 次 出 现 的 时 候 , 每 个 控 件 窗 口自 动 用 相 应 的 成 员 变 量 的 值 进 行 初 始 化 。 当 用 户 通 过 单 击 O K 按 钮 , 或 通 过 按
Enter 键 关 闭 对 话 的 时 候 , 该 控 件 无 论 是 包 含 哪 一 个 值 或 文 本 , 都 将 被 复 制 回 该变 量 。 对 话 数 据 验 证 可 以 确 保 值 落 在 规 定 的 限 制 之 内 。 交 换 和 验 证 机 制 都 是 由MFC 框 架 通 过 表 6-4 和 6-5 中 所 列 出 的 函 数 集 提 供 的 。 每 个 函 数 都 有 一 个 前 缀D D X _ 或 D D V _ , 来 把 它 作 为 数 据 交 换 或 数 据 验 证 函 数 来 标 识 。
表 6-4 常 见 的 对 话 数 据 交 换 函 数
交 换 函 数 获 得 / 设 置 这 种 类 型 的数 据 …
… 用 于 该 种 类 型 控件
DDX_CBIndex int Combo box
DDX_CBString CString Combo box
DDX_CBStringExa ct
CString Combo box
DDX_Check int Check box
DDX_DateTimeCtrl Ctime Date-time picker
DDX_LBIndex int List box
续 表
DDX_LBString CString List box
DDX_LBStringExa ct
CString List box
DDX_MonthCalCtrl Ctime Month calendar
DDX_Radio int Radio button
DDX_Scroll int Scroll bar
DDX_Text CString or numerical (BYTE,
short,int,UINT,long,etc.)
Edit control
对 话 数 据 交 换 ( DDX )
MFC 提 供 了 大 量 的 对 话 数 据 交 换 函 数 , 它 们 可 以 在 对 话 类 中 的 控 件 成 员 变 量 之间 移 动 数 据 。 除 了 表 6-4 中 所 列 的 常 见 函 数 之 外 , 还 有 用 于 记 录 集 数 据 和 由ActiveX 控 件 返 回 的 数 据 的 特 殊 交 换 函 数 。 DDX_Control 函 数 可 以 为 几 种 不 同 类型 的 控 件 传 输 数 据 , 例 如 Animate 和 IP Address。 如 果 想 了 解 有 关 数 据 交 换 函 数
的 更 为 详 细 的 信 息 , 请 参 考 Visual C++ 在 线 帮 助 。
表 6-4 中 列 出 的 DDX_Radio 函 数 值 得 讨 论 一 下 。 在 所 有 的 数 据 交 换 函 数 之 中 , 该 函 数 是 独 一 无 二 的 , 它 只 应 用 于 一 组 控 件 , 而 不 是 一 个 控 件 。 DDX_Radio 返回 一 个 int 值 用 来 指 示 用 户 打 开 了 组 中 的 哪 个 按 钮 : 0 代 表 组 中 的 第 一 个 按 钮 , 1 代 表 第 二 个 按 钮 , 以 此 类 推 。值 -1 的 意 思 是 小 组 中 的 所 有 按 钮 都 是 清 除 的 。你 可以 调 用 DDX_Radio 来 确 定 单 个 单 选 按 钮 的 状 态 ( 假 如 它 是 组 中 的 唯 一 一 个 按钮 )。在这种情况下,返回值 0 的 意 思 是 按 钮 是 打 开 的 ,值 -1 意 为 按 钮 是 关 闭 的 。建 立 一 个 单 选 按 钮 通 常 在 对 话 编 辑 器 中 进 行 , 我 们 一 会 儿 就 能 看 到 。
对 话 数 据 验 证 ( DDV )
表 6-5 列 出 了 八 个 对 话 数 据 验 证 函 数 ,它 们 仅 仅 应 用 于 接 受 用 于 从 键 盘 输 入 数 据的 控 件 成 员 变 量 。 换 言 之 , 就 是 编 辑 控 件 和 组 合 框 。
表 |
6-5 |
对 话 数 据 交 换 函 数 |
|
---|---|---|---|
验 证 函 数 |
验 证 … |
||
DDV_MinMaxByte |
指 定 限 制 范 围 内 的 一 个 |
BYTE 值 |
|
DDV_MinMaxInt |
指 定 限 制 范 围 内 的 一 个 |
int 值 |
|
DDV_MinMaxUInt |
指 定 限 制 范 围 内 的 一 个 |
UNIT 值 |
|
DDV_MinMaxLong |
指 定 限 制 范 围 内 的 一 个 |
long 值 |
|
DDV_MinMaxDWord DDV_MinMaxFloat |
指 定 限 制 范 围 内 的 一 个 指 定 限 制 范 围 内 的 一 个 |
DWORD 值 float 值 |
|
DDV_MinMaxDouble |
指 定 限 制 范 围 内 的 一 个 |
double 值 |
DDV_MaxChars CString 字 符 串 的 长 度 不 能 超 过 指 定的 最 大 长 度
当 你 为 编 辑 控 件 或 组 合 框 添 加 成 员 变 量 , 然 后 在 M ember Variable 选 项 卡 中 的
Control IDs 框 中 选 择 控 件 的 时 候 , 两 个 提 示 之 一 将 会 出 现 在 该 选 项 卡 的 底 部 。究
竟 出 现 哪 一 个 提 示 取 决 于 变 量 所 具 有 的 是 数 字 数 据 ,还 是 文 字 数 据 ;在 任 一 种 情况 下 , 都 要 输 入 用 于 验 证 的 变 量 限 制 值 :
除 了 一 个 对 话 数 据 验 证 函 数 之 外 , 所 有 函 数 都 监 视 数 值 数 据 ,以 确 保 由 用 户 输 入的 值 落 在 指 定 的 上 下 限 之 间 。 例 外 是 DDV_MaxChars 函 数 , 它 用 来 验 证 键 入 到编 辑 控 件 或 组 合 框 中 的 字 符 数 不 超 过 给 定 的 最 大 值 。与 表 6-4 中 列 出 的 交 换 函 数不 同 , 验 证 函 数 仅 仅 在 对 话 关 闭 的 时 候 起 作 用 , 而 不 在 它 刚 出 现 的 时 候 起 作 用 。如 果 输 入 到 一 个 控 件 的 值 落 到 了 指 定 的 限 制 之 外 ,那 么 , 该 控 件 的 验 证 函 数 将 显示 一 个 消 息 框 , 以 通 知 用 户 出 了 问 题 。 当 消 息 框 被 关 闭 的 时 候 , 出 问 题 的 控 件 将具 有 一 个 焦 点 , 提 示 用 户 重 新 输 入 数 据 。 除 非 所 有 的 数 据 验 证 函 数 都 满 足 了 , 否则 , 用 户 不 能 够 通 过 单 击 O K 来 关 闭 对 话 。
DoDataExchange 函 数
ClassWizard 把 叫 做 DoDataExchange 的 成 员 函 数 添 加 到 对 话 类 的 CPP 文 件 。 这 个
函 数 包 含 对 话 所 需 要 的 对 数 据 交 换 和 验 证 函 数 的 所 有 调 用 。 例 如 , 对 于 接 受 从 1
到 99 的 整 数 的 单 个 编 辑 控 件 ,ClassWizard 可 以 编 写 不 同 的 DoDataExchange 函 数 :
void CDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDemoDlg) DDX_MinMaxInt(pDX,m_nEditVal, 1, 99);
//}}AFX_DATA_MAP
}
DoDataExchange 是 一 个 完 整 的 函 数 , 并 不 是 你 必 须 进 一 步 添 加 的 存 根 代 码 。 既然 在 对 话 开 始 和 结 束 的 时 候 , 框 架 都 要 调 用 DoDataExchange , 那 么 , 有 时 向 它添 加 初 始 化 和 清 除 代 码 是 很 方 便 的 , 否 则 你 通 常 会 忘 记 该 函 数 的 存 在 。如 果 你 在M ember Variable s( 成 员 变 量 ) 选 项 卡 删 除 了 一 个 变 量 , 那 么 ClassWizard 将 会 在DoDataExchange 函 数 中 删 除 对 该 变 量 任 何 数 据 的 交 换 和 验 证 调 用 。
ClassWizard 和 AppWizard 为 项 目 中 的 每 个 对 话 编 写 DoDataExchange 函 数 ,即 使
对 话 没 有 接 受 用 户 输 入 的 控 件 也 是 如 此 。例 如 ,由 AppWizard 生 成 的 About 框 类具 有 一 个 DoDataExchange 函 数 , 即 使 该 对 话 没 有 任 何 控 件 ( 一 个 图 标 , 两 行 静态 文 字 和 一 个 压 入 式 按 钮 ) 可 以 从 用 户 处 接 收 数 据 。如 果 你 想 让 一 个 控 件 仅 仅 显示 数 据 ,而 不 允 许 用 户 改 变 值 ,那 么 应 该 删 除 ClassWizard 添 加 到 DoDataExchange 的 控 件 的 任 何 DDX/DDV 调 用 。 另 一 个 选 项 是 完 全 删 除 DoDataExchange 函 数 , 我 们 将 要 在 本 章 稍 后 看 到 另 一 个 例 子 。
在 创 建 对 话 的 时 候 ,在 设 计 过 程 的 早 期 , 你 应 该 考 虑 一 下 对 话 的 类 是 如 何 在 对 话数 据 交 换 与 验 证 融 合 在 一 起 的 。在 第 5 章 中 介 绍 过 , 对 话 编 辑 器 允 许 你 通 过 在 控件 的 Properties 框 中 打 开 或 关 闭 合 适 的 复 选 框 来 设 计 每 个 控 件 的 属 性 。 当 为 使 用对 话 数 据 交 换 和 验 证 的 控 件 设 计 属 性 的 时 候 , 请 记 住 以 下 几 点 :
- 对 于 只 接 受 简 单 的 十 进 制 ( 而 不 是 十 六 进 制 ) 的 整 数
的 编 辑 控 件 , 在
Edit Propertie s( 编 辑 属 性 )对 话 的 Style s( 风 格 )选 项 卡 中 设 置 Number
( 数 字 ) 复 选 框 。 这 将 给 这 个 控 件 分 配 一 个 样 式 标 志 ES_NUMBER , 使 它 忽 略 除 从 0 到 9 之 外 的 任 何 字 符 , 其 中 也 包 括 逗 号 和 句 号 。
- 如 果 组 合 框 或 列 表 框 只 接 受 自 由 数 字 数 据 , 那 么 , 请
访 问 该 控 件 的Properties 对 话 , 并 关 闭 它 的 排 序 选 项 。 对 于 组 合 框 和 一 般 的 列 表 框 , 请 清 除 Styles ( 风 格 ) 选 项 卡 中 的 Sort Property ( 排 序 属 性 ) 复 选 框 ; 对 于 列 表 控 件 , 确 保 Styl e( 风 格 ) 选 项 卡 中 的 Sort Selectio n( 排 序 选择 ) 为 None 。 因 为 这 些 控 件 将 根 据 数 字 的 ASCII 值 , 而 不 是 数 字 值 ,
对 数 字 进 行 排 序 , 仅 仅 当 条 目 具 有 固 定 的 数 字 号 码 , 并 且 包 含 有 前 导
0 ( 例 如 001 和 099 ) 时 , 它 们 才 能 正 确 地 排 出 一 个 号 码 列 表 。
-
当 你 创 建 一 组 单 选 按 钮 的 时 候 , 请 为 组 中 的 每 个 按 钮
设 置 Auto 属 性 。这 将 使 得 这 个 单 选 按 钮 成 为 互 斥 的 , 以 便 单 击 一 个 按 钮 将 自 动 清 除 组中 其 他 所 有 的 按 钮 。
-
仅 仅 为 组 中 的 第 一 个 单 选 按 钮 设 置 Group 属 性 , 确 保 组
中 其 他 所 有 的按 钮 按 照 Tab 键 顺 序 跟 在 第 一 个 按 钮 之 后 。 如 果 这 样 做 失 败 了 , 那 么当 用 户 按 箭 头 键 时 , 将 禁 止 对 话 将 焦 点 从 一 个 单 选 按 钮 移 动 到 下 一 个单 选 按 钮 。 另 外 , 还 要 为 紧 跟 在 组 中 最 后 的 单 选 按 钮 之 后 的 那 个 控 件设 置 Group 属 性 。 这 表 示 这 是 前 一 组 的 末 尾 和 另 一 组 的 开 始 。 在 调 试器 中 运 行 该 程 序 将 会 告 诉 你 , 何 时 一 组 单 选 按 钮 不 能 由 Group 属 性 来正 确 地 定 界 , 因 为 当 对 话 出 现 的 时 候 , 调 试 器 将 在 Output 窗 口 中 显 示这 条 消 息 。
Warning: skipping non-radio button in group .(警告 :跳过组中的非单选按钮)
向 项 目 添 加 类
MFC ClassWizard 的 所 有 五 个 选 项 卡 都 具 有 Add Clas s( 添 加 类 ) 按 钮 , 因 为 你 可以 从 对 话 的 任 何 一 个 选 项 卡 中 开 始 一 个 新 类 。 单 击 了 Add Class ( 添 加 类 ) 按 钮
之 后 , 选 中 如 下 两 个 选 项 之 一 :
-
Ne w( 新 建 ): 创 造 包 含 有 由 ClassWizard 生 成 的 骨 干 代 码
的 CPP 文 件和 H 文 件 。
-
From a type library ( 来 自 类 型 库 ): 为 基 于 OLE 类 库 的 一
个 类 创 建 源代 码 。 这 个 类 型 库 可 以 是 一 个 单 独 的 文 件 ( 通 常 具 有 TLB 扩 展 名 ), 或 者 它 可 以 作 为 资 源 数 据 包 含 在 像 动 态 链 接 库 这 样 的 程 序 内 部 。 动 态链 接 库 一 般 具 有 如 下 扩 展 名 : OLB ( 对 象 库 )、 OCX ( ActiveX 控 件 ) 或 DLL 。 例 如 , 选 择 第 8 章 中 介 绍 的 任 何 一 个 ActiveX 控 件 , 都 将 从OCX 文 件 的 类 型 库 信 息 中 生 成 的 项 目 中 添 加 类 源 代 码 。在 你 定 位 并 选中 了 所 需 要 的 类 型 库 文 件 之 后 , 在 类 列 表 中 选 择 一 个 类 , 这 个 类 列 表是 ClassWizard 从 库 中 的 信 息 收 集 保 存 的 , 并 在 Confirm Classes( 确 认 ) 对 话 中 显 示 。 如 果 你 希 望 为 当 前 的 项 目 重 命 名 选 中 的 类 , 那 么 请 在Class Name 控 件 中 输 入 新 的 名 字 。 你 还 可 以 指 定 ClassWizard 所 创 建的 CPP 和 H 文 件 的 名 字 。
两 个 选 项 都 可 以 为 新 类 自 动 更 新 CLW 数 据 库 。 如 果 想 通 过 从 另 一 个 项 目 中 复 制一 个 现 有 的 类 来 创 建 一 个 新 类 ,那 么 可 以 采 用 三 种 不 同 的 方 法 。借 用 现 有 类 的 最直 接 方 法 是 将 源 代 码 复 制 到 你 的 项 目 文 件 夹 , 并 使 用 Add To Project( 添 加 到 项目 中 ) 命 令 , 将 CPP 文 件 添 加 到 项 目 。 在 弹 出 式 次 级 菜 单 中 单 击 File s, 然 后 双击 文 件 列 表 中 该 类 的 CPP 文 件 。 正 如 前 一 章 中 所 提 及 的 , 不 必 要 以 相 同 的 方 法
添 加 头 文 件 , 原 因 是 Visual C++ 是 将 头 文 件 做 为 从 属 文 件 来 识 别 。 第 二 种 方 法 需要 从 Project 菜 单 中 Insert Project Into Workspace ( 插 入 项 目 到 工 作 空 间 ) 命 令 来插 入 现 有 的 项 目 。 然 后 , 你 就 可 以 自 由 地 从 插 入 的 项 目 中 借 用 源 文 件 了 。 第 三 种方 法 是 通 过 Gallery , 我 们 将 在 第 7 章 中 进 行 讨 论 。
你 可 能 不 是 从 类 型 库 中 添 加 一 个 现 有 的 类 , 而 是 更 经 常 地 选 择 New 选 项 , 来 让ClassWizard 启 动 你 想 开 发 的 新 的 派 生 类 。 单 击 New 将 显 示 如 图 6-4 所 示 的 New Class 对 话 框 , 在 这 个 对 话 框 中 , 你 可 以 为 你 的 类 输 入 一 个 名 字 , 然 后 从ClassWizard 支 持 的 MFC 类 中 选 择 它 的 基 。
图 6-4 从 ClassWizard 中调用的 New Class 对话
为 了 命 名 类 源 文 件 , ClassWizard 向 你 所 指 定 的 类 名 添 加 CPP 和 H 文 件 扩 展 , 去掉 任 何 C 前 缀 , 如 果 你 想 采 用 其 他 名 称 , 请 单 击 Change 按 钮 。
D ialog ID 控 件 是 否 在 New Class 对 话 中 处 于 活 动 状 态 取 决 于 所 选 中 的 基 类 。当 你作 为 基 类 从 五 个 MFC 对 话 类( CDialog ,CProperty Page ,CFormView ,CRecordView 或 CDaoRecordView ) 中 进 行 选 择 的 时 候 , Dialog ID 控 件 处 于 激 活 状 态 , 提 示 与新 类 相 关 联 的 对 话 的 资 源 标 识 符 。创 建 基 于 对 话 的 类 的 最 好 方 法 是 ,首 先 在 对 话编 辑 器 中 设 计 和 保 存 对 话 资 源 ,然 后 ,在 编 辑 器 仍 然 处 于 激 活 状 态 且 有 输 入 焦 点的 时 候 , 访 问 ClassWizard , 来 为 对 话 创 建 新 类 。 在 本 章 稍 后 的 例 子 中 , 我 们 将这 样 做 。
Automation 组 框 中 单 选 按 钮 的 外 观 取 决 于 选 中 的 基 类 是 否 支 持 Automation 。当 你选 中 像 CHttpFilter 这 样 的 基 类 的 时 候 , 将 出 现 一 条 十 分 详 细 的 消 息 , 通 知 你Automation 不 是 一 个 选 项 。 不 过 , 对 于 可 察 知 Automation 的 基 类 , Automation 单 选 按 钮 是 启 用 的 。 打 开 该 按 钮 , 将 指 导 ClassWizard 编 写 代 码 来 生 成 源 文 件 , 从 而 使 得 这 个 新 类 成 为 一 个 可 编 程 的 对 象 , 而 且 对 于 像 M icrosoft Excel 这 样 的Automation 客 户 应 用 程 序 来 说 是 可 见 的 。本 书 附 录 B 标 识 了 那 些 MFC 类 可 察 知Automation 。 如 果 你 想 了 解 有 关 Automation 的 更 多 信 息 , 由 David Kruglinski 编著 的 Inside Visual C++ 中 , 专 门 有 一 章 来 讨 论 这 一 主 题 。
单 击 Createable By Type ID( 通 过 类 型 ID 可 创 建 ) 单 选 按 钮 将 生 成 代 码 , 这 些 代码 允 许 其 他 的 ActiveX 应 用 程 序 创 建 你 的 新 类 的 Automation 对 象 。 ClassWizard
自 动 将 项 目 名 和 类 名 组 合 起 来 ,以 形 成 编 辑 控 件 中 所 显 示 的 类 型 标 识 符 , 以 及 一个 用 来 帮 助 确 保 标 识 符 为 独 一 无 二 的 方 案 。这 个 类 型 标 识 符 也 就 是 大 家 所 熟 知 的程 序 设 计 标 识 符 , 它 可 以 被 ActiveX 客 户 应 用 程 序 用 来 指 定 对 象 。 例 如 , 一 个Excel 宏 可 以 创 建 一 个 CNewClass 对 象 :
Set DemoObj=CreatObject ("Demo.NewClass")
添 加 非 MFC 类
ClassWizard 对 话 不 是 向 项 目 添 加 类 的 唯 一 方 法 。 单 击 Insert 菜 单 上 的 New Class 命 令 , 将 显 示 如 图 6-5 所 示 的 对 话 , 它 与 图 6-4 中 的 对 话 共 享 相 同 的 名 字 , 而 且看 起 来 十 分 相 似 。 唯 一 的 不 同 是 , 在 对 话 的 顶 部 多 了 个 Class Type 框 , 它 是 用 来指 示 New Class 命 令 的 双 重 特 性 的 。
对 于 类 的 类 型 , 默 认 选 择 是 MFC Class , 这 将 导 致 对 话 的 行 为 与 图 6-4 中 的 New Class 对 话 一 致 。 选 择 Base Class 控 件 中 的 一 个 基 本 MFC 类 , 并 且 像 以 前 一 样 设置 Automation 单 选 按 钮 。如 果 想 创 建 一 个 基 于 表 单 的 新 类 ,请 在 Class Type 框 中选 择 Form Class , 然 后 选 择 CFormView , CDialog , CRecordView 或CDaoRecordView 的 一 个 基 类 。 对 于 类 的 类 型 , 第 三 个 方 案 是 Generic Class , 它将 导 致 Visual C++ 为 不 是 从 MFC 中 派 生 的 类 生 成 存 根 代 码 。Visual C++ 仅 仅 借 用来 自 ClassWizard 的 技 术 , 如 果 你 愿 意 看 到 New Class 命 令 只 是 作 为 ClassWizard 中 的 另 一 部 分 , 当 然 也 可 以 。 但 是 一 定 要 切 记 , 图 6-4 所 示 的 New Class 对 话 的变 种 仅 仅 可 用 于 从 MFC 派 生 而 来 的 类 , 对 于 它 , 你 总 是 可 以 应 用 ClassWizard
的 全 部 功 能 。 用 New Class 命 令 创 建 常 规 的 非 MFC 的 类 将 生 成 存 根 代 码 , 但 同时 也 舍 弃 了 ClassWizard 的 其 他 功 能 。
图 6-5 通 过 从 Insert 菜单 New Class 命 令 进 行 访 问 的 New Class 对 话
对 话 中 的 Generic Class 设 置 启 用 一 个 列 表 框 ,你 可 以 从 中 为 新 类 选 择 一 个 基 。生成 的 源 代 码 仅 仅 由 用 于 类 构 造 器 和 析 构 器 的 存 根 函 数 组 成 ,这 些 函 数 包 含 在 一 个为 该 类 命 名 的 CPP 文 件 和 H 文 件 之 中 。例 如 ,这 是 New Class 命 令 为 从 CBaseClass 中 派 生 出 来 的 类 写 到 头 文 件 中 的 声 明 。
class CDerivedClass : public CBaseClass
{
public:
CDerivedClass();
virtual ~CDerivedClass();
};
除 了 New Class 命 令 之 外 , Visual C++ 还 提 供 了 ClassWizard 的 其 他 分 支 。我 们 将要 在 下 面 看 到 ,WizardBar 作 为 到 达 ClassWizard 的 侧 门 ,它 通 常 比 主 要 入 口 更 加方 便 。
W izardBa r( 向 导 栏 )
W izardBar 是 一 个 可 停 靠 的 工 具 栏 , 当 你 在 文 本 和 对 话 编 辑 器 中 四 处 移 动 的 时候 , 它 可 以 记 住 插 字 符 的 位 置 或 当 前 选 中 的 部 分 。 无 论 你 当 前 正 在 处 理 的 是 哪一 类 , 该 栏 都 会 连 续 不 断 地 调 整 它 的 外 观 。 例 如 , 打 开 用 于 CMainFrame 类 的 实现 文 件 将 自 动 为 该 类 初 始 化 W izardBar, 提 供 一 种 方 便 的 方 法 迅 速 找 到 成 员 函 数的 定 义 和 声 明 。 和 其 他 任 何 Visual C++ 工 具 栏 一 样 , 你 可 以 通 过 单 击 Tools 菜 单上 的 Customize 命 令 , 并 在 ToolsBar 选 项 中 选 中 合 适 的 复 选 框 来 将 W izardBar 打开 或 关 闭 。
图 6-6 显 示 了 W izardBar 的 类 型 视 图 。
图 6-6 WizardBar
W izardBar 的 三 个 组 合 框 用 于 封 装 在 MFC ClassWizard 对 话 的 M essage Map s( 消息 映 射 )选 项 卡 中 显 示 的 信 息 ,ClassWizard 中 所 做 的 任 何 改 变 都 可 以 在 W izardBar 中 连 续 不 断 地 反 映 出 来 。 表 6-6 说 明 了 W izardBar 的 框 和 按 钮 。
W izardBar 最 右 边 的 箭 头 按 钮 显 示 的 是 图 6-7 中 所 示 的 选 项 的 下 拉 菜 单 。
表 6-6 W izardBar 上 的 控 件
向 导 控 件 说 明
Classes( 类 ) 显 示 编 辑 器 中 当 前 处 于 打 开 状 态 的 类 名 , 并 且
提 供 一 个 项 目 中 所 有 类 的 下 拉 列 表 。 当 既 没 有文 本 编 辑 器 也 没 有 对 话 编 辑 器 具 有 焦 点 的 时候 , 框 中 条 目 是 灰 色 的
Identifiers ( 标 识符 )
列 出 当 前 所 使 用 的 符 号 标 识 符 ( 当 前 类 的 名 字出 现 在 W izardBar 的 Classes 框中 )
Function s( 函 数 ) 包 含 用 于 当 前 类 的 虚 拟 函 数 和 CCmdTarget 的
过 程 名
续 表
Default ( 默 认 ) 单 击 位 于 W izardBar 最 右 端 的 “ 棍 棒 ” 图 标 ,
将 执 行 两 行 W izardBar 菜 单 的 默 认 命 令 。 默 认命 令 取 决 于 当 前 的 支 持 以 及 在 W izardBar 中 选中 的 部 分 。 例 如 , 如 果 类 实 现 文 件 在 文 本 编 辑器 中 处 于 打 开 状 态 , 并 且 插 字 符 在 函 数 块 之内 , 那 么 默 认 的 操 作 将 是 Go To Function Declaration( 转 向 函 数 声 明 ), 即 打 开 类 的 头 文件 ,并 定 位 在 函 数 原 型 中 的 插 字 符 位 置 ,然 后 , 默 认 的 操 作 将 变 为 Go To Function Definition
( 转 向 函 数 定 义 ), 将 插 字 符 发 回 到 实 现 CPP 文 件 , 默 认 操 作 总 是 在 WizardBar 菜 单 上 列 出的 第 一 个 命 令 , 如 图 6-7 所 示
M enu ( 菜 单 ) 显 示 可 用 选 项 的 W izardBar 菜 单 , 将 在 下 面 列
出 的 项 目 符 号 列 表 中 仔 细 说 明
菜 单 的 内 容 反 映 了 当 前 处 于 活 动 状 态 的 文 档 , 因 此 , 当 源 文 档 在 文 本 编 辑 器 中 处于 打 开 状 态 的 时 候 ,像 Go To Next Function 这 样 的 命 令 才 可 用 。在 菜 单 命 令 的 以下说明中,词“ 当 前 ” 指 的 是 W izardBar 中 的 设 置 。例 如 , 当 前 类 是 在 W izardBar 的 Classes 框 中 显 示 的 类 , 如 图 6-6 所 示 。
图 6-7 通 过 单 击 WizardBar 上 的 箭 头 按 钮 显 示 的 WizardBar 菜 单
-
Go To Function Definition ( 转 向 定 义 ): 如 果 必 要 的 话 ,
打 开 源 CPP 文 件 , 并 在 当 前 函 数 的 第 一 行 放 置 插 字 符 , 在 W izardBar 的 Functions 框 中 标 识 。
-
Go To Function Declaration ( 转 向 函 数 声 明 ): 在 当 前 函 数
的 原 型 处 放置 插 字 符 。
-
Add Windows Message Handler( 添 加 窗 口 消 息 处 理 函 数 ): 调
用 New Windows Message Handle r( 新 建 窗 口 消 息 处 理 程 序 ) 对 话 。 在 该 对 话中 , 可 以 快 速 从 CWnd 开 始 , 向 随 后 的 类 中 添 加 存 根 消 息 处 理 程 序 函数。
-
Add Virtual Function( 添 加 虚 拟 函 数 ): 超 越 基 类 的 虚 拟
函 数 。 该 命 令显 示 两 个 列 表 , 一 个 包 含 有 可 以 为 超 越 提 供 的 虚 拟 函 数 , 另 外 一 个 显示 已 被 当 前 类 超 越 的 那 些 函 数 。 这 些 列 表 提 供 了 与 MFC ClassWizard 对 话 中 的 Messages 框 相 同 的 信 息 , 但 更 加 易 于 使 用 , 且 更 加 便 于 浏览。
-
Add Member Functio n( 添 加 成 员 函 数 ): 向 当 前 类 添 加 存
根 成 员 函 数 。像 下 图 如 示 那 样 , 输 入 该 函 数 的 返 回 类 型 、 声 明 和 访 问 标 签 。
Visual C++ 将 这 个 新 函 数 的 声 明 和 定 义 代 码 都 添 加 到 类 源 文 件 。
//In the class header file public:
void NewFunction(int I, Cstring &str);
// In the class CPP implementation file
void CMainFrame::NewFunction(int I, Cstring &str)
{
}
-
Delet e( 删 除 ): 从 类 的 来 源 中 删 除 当 前 函 数 。 在 查 询
确 认 之 后 ,Visual C++ 把 该 函 数 的 声 明 和 注 释 从 实 现 代 码 中 删 除 。 编 辑 器 的 Undo 命 令不 能 恢 复 已 被 删 除 的 函 数 。
-
Go To Class Definition ( 转 到 类 ): 在 当 前 类 的 构 造 器 函
数 的 实 现 代 码处 放 置 插 字 符 。
-
New Clas s( 新 建 类 ):与 Insert 菜 单 上 的 New Class 命 令 是
等 价 的 。
-
New Form ( 新 建 表 单 ): 显 示 New Form 对 话 , 该 对 话 可 用
于 生 成 代表从 CFormView , Cdialog , CRecordView 或 CDaoRecordView 中 派 生的 基 于 表 单 的 新 类 的 源 代 码 。该 操 作 与 从 New Class 对 话 中 选 中 Form
Class 类 型 产 生 的 结 果 相 同 。
-
Go To Next/Previous Functio n( 转 向 下 一 个 / 前 一 个 函 数 ):
在 实 现 文 件中 , 将 插 字 符 向 前 或 向 后 发 送 到 下 一 个 函 数 定 义 。 在 头 文 件 中 , 将 插字 符 发 送 到 邻 近 的 函 数 声 明 。
-
Open Include File ( 打 开 包 括 文 件 ): 扫 描 当 前 文 档 查 找
#include 语 句 , 然 后 展 示 一 个 带 有 包 括 文 件 的 列 表 。 如 果 想 在 文 本 编 辑 器 中 打 开 一 个文 件 , 请 在 列 表 中 双 击 它 的 文 件 名 。
- WizardBar Help ( 向 导 栏 帮 助 ): 在 MSDN Help 窗 口 中 显
示 一 个 题 为“ OverView: WizardBar” 的 话 题 。 从 那 里 , 你 可 以 跳 到 与 W izardBar 有 关 的 其 他 话 题 。
- WizardBar Help ( 向 导 栏 帮 助 ): 在 MSDN Help 窗 口 中 显
W izardBar 提 供 了 到 ClassWizard 的 快 速 访 问 , 是 ClassWizard 对 话 的 替 代 方 法 , 使 用 起 来 很 方 便 。一 旦 你 知 道 了 ClassWizard 的 输 入 与 输 出 ,W izardBar 的 功 能 看上 去 就 很 熟 悉 了 。 尽 管 本 章 将 重 点 放 在 通 过 各 种 对 话 框 来 访 问 ClassWizard 之上 , 该 信 息 同 样 可 以 应 用 到 W izardBar 工 具 。
ClassWizard 如 何 识 别 类
CLW 数 据 库 文 件 是 以 ASCII 文 本 形 式 存 在 的 , 因 此 你 可 能 对 使 用 文 本 编 辑 器 阅
读 它 比 较 感 兴 趣 。 数 据 库 将 项 目 中 的 每 个 类 进 行 分 类 , 并 记 录 该 类 的 基 和 源 文件 。对 话 、菜 单 和 加 速 键 这 样 的 资 源 数 据 ,也 用 它 们 的 标 识 符 在 文 件 中 运 行 分 类 。
为 了 构 造 CLW 数 据 库 文 件 , Visual C++ 扫 描 附 加 在 该 项 目 之 上 的 每 个 源 文 件 , 寻 找 特 殊 的 注 释 行 。在 前 面 的 AppWizard 程 序 中 , 你 已 经 看 到 了 这 些 注 释 ; 它 们以 {/ 或 //} 开 头 , 以 起 到 标 记 声 明 、 消 息 映 射 条 目 和 其 他 与 类 成 员 相 关 的 代 码 的 作用 , 除 了 为 CLW 数 据 库 中 包 括 的 东 西 标 识 类 信 息 之 外 , 注 释 没 有 其 他 的 作 用 。如 果 你 没 有 使 用 ClassWizard 写 一 个 类 ,而 后 来 又 想 使 用 ClassWizard 向 该 类 添 加其 他 的 函 数 或 数 据 , 那 么 你 必 须 包 括 注 释 行 。 否 则 , 注 释 就 不 是 必 要 的 。
每 个 注 释 限 定 符 都 包 含 表 6-7 中 列 出 的 十 三 个 关 键 字 中 的 一 个 。大 多 数 关 键 字 是成 对 使 用 的 , 一 个 关 键 字 用 来 标 记 类 的 头 文 件 中 的 一 条 声 明 , 而 它 的 对 应 物( 带有 _MAP 后 缀 )标 记 的 是 CPP 文 件 中 消 息 映 射 中 的 相 应 条 目 。例 如 ,这 里 是 Visual C++ 如 何 识 别 名 为 CDemoApp 中 消 息 处 理 程 序 函 数 的 例 子 , 其 中 CDemoApp 是从 MFC 的 CWinApp 中 派 生 出 来 的 。在 CPP 实 现 文 件 中 ,特 殊 的 AFX_MSG_MAP 注 释 将 代 表 处 理 程 序 函 数 CDemoApp::OnAppAbout 的 消 息 映 射 条 目 括 了 起 来 , 使 得 该 条 目 可 以 被 ClassWizard 所 识 别 。
BEGIN_MESSAGE_MAP(CDemoApp, CWinApp)
//{{AFX_MSG_MAP(CDemoApp) ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
//}}AFX_MSG_MAP END_MESSAGE_MAP()
表 6-7 ClassWizard 所 需 要 的 注 释 关 键 字
关 键 字 |
文 件 |
说 明 |
---|---|---|
AFX_DATA |
H |
用 于 对 话 数 据 交 换 的 成 员 变 量 声 明 |
AFX_DATA_INIT |
CPP |
对 话 类 的 构 造 器 中 对 话 数 据 交 换 变 |
量 的 初 始 化 |
||
AFZ_DATA_MAP |
CPP |
对 话 类 的 DoDateExchange 函 数 中 的对 话 数 据 交 换 调 用 |
AFX_DISP |
H |
自 动 声 明 |
AFX_DISP_MAP |
CPP |
自 动 映 射 |
AFX_EVENT |
H |
ActiveX 事 件 声 明 |
AFX_EVENT_MAP |
CPP |
ActiveX 事 件 映 射 |
续 表
AFX_FIELD_INIT |
CPP |
初 始 化 记 录 集 类 的 构 造 器 中 的 记 录 字 段 交 换 成 员 变 量 |
---|---|---|
AFX_FIELD_MAP |
CPP |
记 录 类 的 DoFieldExchange 成 员 函 数中 的 记 录 字 段 交 换 调 用 |
AFX_MSG |
H |
在 消 息 映 射 中 出 现 的 函 数 变 量 |
AFX_MSG_MAP |
CPP |
消 息 映 射 条 目 |
AFX_VIRTUAL |
H |
虚 拟 函 数 超 越 的 声 明 |
ClassWizard 还 需 要 读 取 该 函 数 的 原 型 , 因 此 头 文 件 中 的 OnAppAbout 声 明 相 应的 AFX_MSG 注 释 进 行 标 记 :
public:
//{{AFX_MSG(CDemoApp) afx_msg void OnAppAbout();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
有 了 这 条 记 录 在 CLW 数 据 库 中 的 信 息 , ClassWizard 就 可 以 知 道 , CDemoApp 类 包 含 有 一 个 名 为 OnAppAbout 的 成 员 函 数 , 当 程 序 接 收 到 包 含 在W M _ C O M M A N D 消 息 中 的 ID_APP_ABOUT 标 识 符 的 时 候 , 便 调 用 该 成 员 函数 。 函 数 中 的 afx_msg 前 缀 是 为 了 ClassWizard 才 包 括 进 来 的 , 否 则 , 它 是 不 需要 的 。ClassWizard 和 AppWizard 可 以 在 生 成 源 代 码 的 时 候 自 动 添 加 正 确 的 限 定符 注 释 。 但 是 , 如 果 你 想 在 不 是 用 AppWizard 开 始 的 项 目 中 , 使 用 ClassWizard 的 话 ,表 6-7 显 示 了 如 何 转 换 现 有 的 源 文 件 ,使 它 们 可 以 被 ClassWizard 所 识 别 。该 表 说 明 了 由 注 释 关 键 字 所 标 记 的 函 数 和 声 明 的 类 型 , 并 且 指 示 了 关 键 字 在 哪个 源 文 件 中 使 用 。
用 ClassWizard 创 建 对 话 类
在 为 新 的 MFC 程 序 设 计 了 新 的 对 话 资 源 之 后 , 你 必 须 还 提 供 从 CDialog( 或 者 其他 基 于 对 话 的 类 ) 中 派 生 的 类 , 来 显 示 对 话 和 响 应 它 的 消 息 。 通 常 情 况 下 , 在 用对 话 编 辑 器 完 成 之 后 , ClassWizard 是 你 的 下 一 个 逻 辑 步 骤 。 例 如 , 当 我 们 在 第 5 章 中 编 写 MfcTree 程 序 的 时 候 , 就 曾 经 用 过 ClassWizard 。M fcTree 显 示 的 是 一 个包 含 有 一 些 MFC 类 的 树 状 列 表 的 简 单 对 话 。 在 第 5 章 中 , 我 们 编 写 了 一 个 叫 做
CMfcDlg 的 类 来 运 行 这 个 对 话 ,首 先 使 用 文 本 编 辑 器 来 编 写 主 要 的 实 现 文 件 和 头文 件 , 名 字 分 别 为 M fcDlg.cpp 和 M fcDlg.h , 然 后 通 过 从 Insert 菜 单 选 择 Add To Properties 命 令 来 将 这 些 文 件 添 加 到 项 目 中 。这 两 个 步 骤 都 可 以 由 ClassWizard 运行 处 理 。
做 为 例 子 说 明 , 让 我 们 再 次 创 建 主 要 的 M fcDlg.cpp 和 MfcDlg.h 文 件 。 这 次 使 用ClassWizard , 而 不 是 在 文 本 编 辑 器 中 从 零 开 始 编 写 文 件 。 为 了 清 楚 地 了 解ClassWizard 自 动 完 成 的 工 作 , 你 可 能 想 回 顾 一 下 第 5 章 题 为 “ 为 CMfcDlg 对 话类 添 加 源 文 件 ” 一 节 的 内 容 。 该 节 介 绍 了 创 建 M fcTree.exe 所 使 用 的 五 个 步 骤 中的 第 三 步 。
在 开 始 这 个 练 习 的 时 候 , 假 设 M fcTree 的 对 话 刚 刚 创 建 , 并 且 保 存 在 对 话 编 辑 器之 中 。 在 IDD_MFC_DIALOG 资 源 仍 在 对 话 编 辑 器 中 处 于 打 开 状 态 的 时 候 , 请单 击 View 菜 单 上 的 ClassWizard 。 ClassWizard 将 检 测 新 的 对 话 资 源 , 并 且 询 问你 是 否 愿 意 为 它 创 建 一 个 新 类 。
我 们 可 以 向 已 经 存 在 源 代 码 的 类 中 添 加 类 。例 如 ,你 在 对 话 编 辑 器 中 创 建 和 保 存资 源 之 前 ,可 能 已 经 编 写 了 对 话 类 。在 这 种 情 况 下 ,你 应 该 单 击 Select An Existing Class( 选 择 现 有 类 ) 单 选 按 钮 , 将 对 话 附 加 到 类 上 。 并 且 阻 止 ClassWizard 生 成
新 的 CPP 和 H 源 文 件 。 不 过 , 对 于 本 例 , 既 然 C M fcDlg 类 还 没 有 存 在 , 那 么 ,
Create A New Class ( 创 建 新 类 ) 单 选 按 钮 便 是 正 确 的 选 择 。
单 击 O K 按 钮 打 开 相 似 的 New Class 对 话 。 在 Name 框 中 输 入 C M fcDlg , 将 为 新类 取 一 个 名 字 。跳 过 Change 按 钮 ,接 受 ClassWizard 为 源 文 件 建 议 的 MFcDlg.cpp 和 MfcDlg.h 默 认 名 字 。 因 为 它 知 道 我 们 正 在 为 这 个 新 对 话 创 建 一 个 类 , 所 以ClassWizard 已 经 选 中 了 CDialog 作 为 基 类 。 它 还 用 对 话 编 辑 器 写 向 MfcTree.rc 文 件 的 对 话 标 识 符 IDD_MFC_DIALOG ,来 填 充 Dialog ID 框 ,图 6-8 显 示 了 New Class 对 话 框 的 样 子 。
6-8 在 ClassWizard 的 New Class 对话中创建新 CMfcDlg 类
单 击 O K 按 钮 来 关 闭 New Class 对 话 , 并 再 现 如 图 6-9 所 示 的 MFC ClassWizard 对 话 , 这 就 是 你 为 新 的 CMfcDlg 类 生 成 主 体 代 码 的 地 方 。 CMfcDlg 仅 仅 需 要OnInitDialog 函 数 , 它 刚 好 在 IDD_MFC_DIALOG 对 话 出 现 之 前 获 得 控 制 权 。 在Object IDs 框 中 , 选 中 CMfcDlg , 然 后 双 击 Messages 栏 中 的 W M _INITDIALOG 来 添 加 OnInitDialog 函 数 。
图 6-9 向 CMfcDlg 类添加 OnInitDialog 成员函数
ClassWizard 创 建 的 两 个 成 员 函 数 的 名 字 出 现 在 对 话 底 部 的 M ember Functions 框中 。 框 中 选 中 的 项 目 用 来 指 示 当 程 序 接 收 到 WM_INITDIALOG 消 息 的 时 候 , ON_WM_INITDIALOG 消 息 映 射 宏 负 责 对 OnInitDialog 函 数 的 日 常 控 制 。CMfcDlg 树 状 视 图 中 的 项 目 保 持 不 变 ,因 此 ,也 就 不 需 要 DoDataExchange 函 数 。如 果 你 想 删 除 DoDataExchange , 请 在 M ember Functions 框 中 选 中 它 , 并 单 击Delete Function 按 钮 。 不 过 , 这 样 做 只 能 从 M fcDlg.h 头 文 件 中 删 除 函 数 原 型 :
//{{AFX_VIRUAL(CMfcDlg) protected;
virtual void DoDataExchange(CDataExchange* pDX); //DDX/DDV support
//}}AFX_VIRTUAL
DoDataExchange 源 代 码 仍 旧 在 MfcDlg.cpp 文 件 中 存 在 。 原 因 是 ClassWizard 仅仅 删 除 了 注 释 限 定 符 之 内 的 代 码 , 而 从 不 删 除 实 现 代 码 。 一 条 消 息 可 以 提 醒 你 注意 这 个 事 实 :
如 果 单 击 Yes 按 钮 , 就 是 同 意 将 在 文 本 编 辑 器 中 删 除 DoDataExchange 源 代 码 。如 果 你 后 来 想 将 函 数 添 回 到 M fcDlg.cpp 文 件 , 便 会 有 两 次 定 义 DoDataExchange 的 危 险 。 当 ClassWizard 添 加 一 个 新 的 成 员 函 数 的 时 候 , 它 应 首 先 扫 描 文 件 , 看看 函 数 是 否 已 经 存 在 , 它 只 是 编 写 新 的 函 数 外 壳 :
void CMfcDlg::DoDataExchange(CDataExchange* pDX)
{
Cdialog::DaDataExchange(pDX);
}
如 果 删 除 DoDataExchange 的 原 始 实 现 失 败 , 将 会 导 致 编 译 错 误 , 因 为 编 译 器 不能 接 受 同 一 函 数 的 两 个 定 义 。
在 退 出 MFC ClassWizard 对 话 的 时 候 ,ClassWizard 将 向 项 目 添 加 新 的 MfcDlg.cpp 和 MfcDlg.h 文 件 , 这 两 个 文 件 都 包 含 有 用 于 CMfcDlg 类 的 存 根 函 数 。 一 旦 你 向第 5 章 中 介 绍 的 那 样 , 在 类 的 OnInitDialog 函 数 中 添 加 了 代 码 , 这 些 新 文 件 在 功能 上 与 从 头 开 始 编 写 的 文 件 是 等 价 的 , 而 且 , 更 加 易 于 创 建 。 如 果 你 愿 意 比 较 新的 源 代 码 , 可 以 在 配 套 光 盘 的 Chapter.05\ M fcTree 文 件 夹 中 找 到 原 来 的 M fcDlg 源 文 件 。 在 ClassWizard 的 帮 助 下 生 成 的 相 应 的 MfcDlg.cpp 和 M fcDlg.h 文 件 位于 Chapter.06\ M fcTree 文 件 夹 中 。
第 7 章 Ga llery ( 组 件 集 )
Gallery 是 一 类 工 具 箱 , M icrosoft 在 它 里 面 放 置 了 一 类 叫 做 组 件 的 “ 罐 装 代 码 ”, 你 可 以 把 它 们 添 加 到 自 己 的 项 目 中 。 还 可 以 使 用 Gallery 来 保 存 你 以 后 想 再 使 用的 任 何 属 于 自 己 的 类 。 Gallery 保 存 三 种 主 要 类 型 的 组 件 : 源 代 码 , 对 话 资 源 和ActiveX 控 件 。 通 过 Gallery , 你 可 以 为 了 寻 找 某 个 组 件 而 浏 览 自 己 的 硬 盘 或 整 个网 络 , 然 后 单 击 一 下 鼠 标 , 将 它 插 入 到 你 的 项 目 中 。 因 为 组 件 可 以 存 储 在 任 何 地方 , 所 以 Gallery 既 可 以 作 为 个 人 代 码 存 储 库 , 存 储 组 件 供 你 个 人 使 用 , 又 可 以作 为 全 局 性 的 代 码 存 储 库 , 允 许 开 发 网 络 链 向 它 来 共 享 通 用 组 件 集 。
Gallery 提 供 的 预 先 包 装 好 的 组 件 存 储 在 由 Visual C++ 安 装 程 序 创 建 的 两 个 文 件夹 中 。 一 个 文 件 用 于 源 代 码 组 件 , 另 一 个 文 件 夹 用 于 ActiveX 控 件 。 Visual C++ Components 文 件 夹 包 含 有 到 动 态 链 接 库 的 快 捷 方 式 , 它 可 以 自 动 向 项 目 添 加 源代 码 和 资 源 。 第 二 个 文 件 夹 名 字 叫 做 Registered ActiveX Controls , 它 包 含 有 到 在你 的 系 统 上 注 册 的 所 有 ActiveX 控 件 的 快 捷 方 式 链 接 。 有 些 注 册 的 控 件 是 由Visual C++ 经 过 许 可 后 提 供 的 , 因 此 , 你 可 以 在 自 己 的 应 用 程 序 之 中 重 新 分 布 它们 。 有 关 ActiveX 控 件 有 很 多 地 方 值 得 一 提 , 它 们 中 的 大 部 分 不 直 接 附 属 于Gallery, 因 此 ,直 到 本 书 第 四 部 分 , 才 能 涉 及 这 方 面 的 话 题 。本 章 把 重 点 放 在 如 何访 问 Gallery 以 及 创 建 你 自 己 的 可 重 用 的 对 象 集 上 。
对 于 预 包 装 的 组 件 来 说 , Visual C++ 不 是 唯 一 可 提 供 的 资 源 。 许 多 销 售 商 以 源 代码 和 二 进 制 两 种 形 式 提 供 组 件 工 具 , 并 且 在 商 业 期 刊 和 Internet 上 做 广 告 。 预 包装 的 组 件 比 你 自 己 创 建 的 更 加 方 便 ,因 为 它 们 可 以 自 动 实 现 向 项 目 添 加 组 件 的 全部 过 程 。 通 过 操 作 Visual C++ 环 境 加 载 和 运 行 的 可 执 行 库 , 这 些 专 业 组 件 可 以 通过 在 必 要 的 时 候 添 加 函 数 和 #include 语 句 ( 通 常 很 少 或 干 脆 就 没 有 为 你 留 下 编 程工 作 的 地 方 ) 来 插 入 图 形 资 源 , 并 重 写 现 有 的 项 目 文 件 。 预 包 装 组 件 通 常 提 供 有它 们 自 己 的 在 线 帮 助 。
Gallery 在 如 图 7-1 所 示 的 Components And Controls Gallery 对 话 中 显 示 它 的 组件 。当 一 个 C++ 项 目 在 环 境 中 处 于 打 开 状 态 的 时 候 ,可 以 通 过 将 光 标 暂 时 停 留 在Project 菜 单 上 的 Add To Projec t( 添 加 到 项 目 ) 命 令 上 来 访 问 Gallery 对 话 。 该 操作 将 显 示 一 个 二 级 下 拉 式 菜 单 , 你 可 以 从 中 选 择 Components And Contro l( 组 件和 控 件 ) 命 令 。 当 你 从 列 表 中 选 中 一 个 组 件 时 , 如 果 该 对 话 的 M ore Info 按 钮 是启 用 的 , 那 么 该 组 件 便 可 以 通 过 在 线 帮 助 来 描 述 自 己 。 如 果 想 把 一 个 Gallery 组件 插 入 到 项 目 中 , 请 选 中 它 的 图 标 , 并 单 击 Insert 按 钮 。
图 7-1 Gallery 的 Visual C++ 组件文件夹
在 Visual C++ 版 本 4 中 , 如 果 你 总 是 用 AppWizard 创 建 项 目 , Gallery( 就 是 所 熟知 的 Component Gallery) 将 会 变 得 很 拥 挤 。 每 当 AppWizard 执 行 的 时 候 , 它 都 自动 向 Component Gallery 添 加 新 类 , 并 且 安 装 所 有 的 项 目 类 ( 例 如 CMainFrame 和CAboutDlg) 作 为 源 代 码 组 件 。 在 默 认 状 态 下 , ClassWizard 还 向 项 目 分 类 添 加 你所 创 建 的 任 何 新 类 。 清 除 Component Gallery 中 不 想 要 的 附 件 的 责 任 就 交 给 用 户了 , 尽 管 许 多 程 序 员 只 是 忽 略 展 开 的 组 件 列 表 , 或 没 有 注 意 到 AppWizard 和ClassWizard 在 幕 后 做 了 些 什 么 。 整 个 Component Gallery 数 据 库 存 储 在 一 个 叫 做Gallery.dat 的 单 个 文 件 之 中 , 因 此 没 有 方 便 的 方 法 可 以 与 其 他 开 发 者 一 起 共 享 组件 。
尽 管 版 本 6 中 Gallery 的 函 数 没 有 改 变 , 但 它 的 方 法 已 经 得 到 了 很 大 改 进 。Gallery.dat 不 再 存 在 , 它 的 数 据 库 已 被 存 在 于 磁 盘 或 网 络 上 任 何 地 方 的 单 个 组 件文 件 所 取 代 。 AppWizard 和 ClassWizard 都 不 再 向 Gallery 添 加 类 。 正 如 我 们 将 在下 一 章 中 所 看 到 的 ,ActiveX 控 件 可 以 成 为 Gallery 数 据 库 的 一 部 分 ,而 无 需 你 的许 可 , 但 是 , 对 于 其 他 组 件 类 型 则 不 可 以 。 你 必 须 采 用 特 殊 的 步 骤 才 能 把 组 件 添加 到 Gallery , 其 中 包 括 你 想 从 版 本 4 中 继 承 的 任 何 组 件 。 下 一 节 将 解 释 如 何 向Gallery 添 加 新 组 件 , 现 在 , 让 我 们 来 看 一 看 Visual C++ 中 提 供 的 预 包 装 组 件 。
例 子 : 添 加 一 个 属 性 表
第 5 章 介 绍 了 如 何 使 用 编 辑 器 来 创 建 属 性 表 对 话 , 并 将 其 融 入 一 个 程 序 。Gallery
提 供 了 一 个 叫 做 Property Sheet 的 组 件 , 利 用 它 , 工 作 起 来 就 会 更 加 容 易 。 本 节和 下 一 节 将 阐 述 Property Sheet 以 及 Visual C++ 提 供 的 一 些 其 他 组 件 , 首 先 显 示如 何 向 叫 做 Gadgets 的 项 目 添 加 属 性 表 , 然 后 用 从 Gallery 中 借 用 的 更 多 代 码 来充 实 和 完 善 程 序 。 Gadget 作 为 一 个 典 型 的 AppWizard 项 目 启 动 , 然 后 , 随 着 你不 断 地 添 入 组 件 ,它 会 变 得 越 来 越 高 级 。下 面 是 建 立 项 目 并 添 加 第 一 个 组 件 的 步骤 :
-
从 File 菜 单 选 择 New 对 话 ,在 Projects 选 项 卡 中 选 择
AppWizar d( exe ) 图 标 。 键 入 Gadgets 作 为 项 目 名 并 单 击 OK 。
-
当 AppWizard 在 屏 幕 上 依 次 出 现 各 个 步 骤 时 , 在 第 一 步
中 选 中 Single Document 单 选 按 钮 , 并 且 在 第 四 步 中 解 除 对 状 态 栏 、停 靠 工 具 栏 和 打印 支 持 的 选 择 。 在 其 他 步 骤 中 接 受 默 认 的 设 置 。
-
当 AppWizard 完 成 , 而 且 Visual C++ 打 开 项 目 的 时 候 , 从
Project 菜 单中 选 择 Add To Project, 并 单 击 位 于 次 级 菜 单 上 的 Components And Controls 命 令 , 来 显 示 Components And Controls Gallery 对 话 。
-
在 对 话 中 打 开 Visual C++ Components 文 件 夹 , 并 双 击
Property Sheet 组 件 图 标 ( 为 了 找 到 该 图 标 , 你 可 能 不 得 不 从 头 至 尾 滚 动 列 表 。Gallery 出 现 一 个 消 息 框 , 询 问 你 是 否 确 实 想 插 入 这 个 组 件 。
-
Visual C++ 加 载 并 执 行 这 个 组 件 的 可 执 行 库 , 它 将 显 示
一 个 对 话 , 询
问 与 你 想 创 建 的 属 性 表 类 型 有 关 的 各 种 问 题 , 只 需 单 击 Next 按 钮 ,接受 所 有 的 默 认 设 置 即 可 。 完 成 之 后 , 关 闭 Gallery 对 话 。
你 将 会 发 现 , Property Sheet 组 件 已 经 为 新 的 属 性 表 类 的 源 文 件 自 动 放 进 了Gadgets 文 件 夹 。 该 组 件 还 修 改 了 Gadget 项 目 中 四 个 现 有 的 文 件 , Resource.h 文件 包 含 有 属 性 表 类 所 需 要 的 定 义 , Gadgets.rc 文 件 已 用 代 表 两 个 属 性 页 的 脚 本 进行 了 更 新 , M ainFrm.h 和 M ainFrm.cpp 文 件 包 含 有 用 于 新 的 名 为 OnProperties 的函 数 的 新 代 码 。
OnProperties 函 数 中 的“ to do ”注 释 解 释 了 你 必 须 将 该 函 数 连 接 到 消 息 处 理 程 序 , 这 样 , 当 用 户 单 击 菜 单 命 令 的 时 候 , 属 性 表 才 能 显 示 出 来 。 该 操 作 仅 需 要 两 步 :
1 .在 M ainFrm.cpp 中 , 将 代 表 该 函 数 的 条 目 添 加 到 消 息 映 射 。 新 的 映 射条 目 在 这 里 显 示 为 阴 影 , 它 必 须 插 在 ClassWizard 注 释 限 定 符 之 间 :
//{{AFX_MSG_MAP(CMainFrame) ON_COMMAND(IDM_PROPSHEET, OnProperties)
//}}AFX_MSG_MAP
2. 在 Workspace 窗 口 的 ResourceView 窗 格 中 , 展 开 M enu 文 件 夹 , 并 双击 IDR_MAINFRAME 菜 单 编 辑 器 。 编 辑 该 菜 单 系 统 , 使 它 如 下 图 所
示 :
当 你 向 Option 菜 单 添 加 Property Sheet 命 令 的 时 候 ,一 定 要 在 M enu Item Properties
( 菜 单 项 属 性 ) 对 话 中 给 它 一 个 IDM_PROPSHEET 的 标 识 符 值 。 这 与 第 一 步 中添 加 到 消 息 映 射 中 的 阴 影 行 所 使 用 的 标 识 符 是 相 同 的 。
使 用 Build 的 工 具 栏 , 可 以 将 活 动 项 目 配 置 改 为 W in32 Release ,创 建 Gagets.exe , 并 运 行 它 。 从 程 序 的 Option 菜 单 中 选 择 Property Sheet 命 令 , 将 显 示 如 图 7-2 所示 的 属 性 表 。 在 对 话 的 这 两 页 中 , 准 备 使 用 对 话 编 辑 器 向 其 中 添 加 控 件 。 从 开 始到 完 成 , 整 个 操 作 仅 需 要 几 分 钟 。 你 可 以 轻 轻 松 松 地 创 建 属 性 表 , 这 是 前 所 未 有的 。
图 7-2 显 示 有 属 性 表 的 Gadgets 程 序
例 子 : 添 加 初 始 屏 幕 和 时 钟
初 始 屏 幕 是 位 图 图 像 , 它 在 程 序 启 动 的 时 候 出 现 一 会 儿 。 在 加 载 文 件 和 实 现 其 他初 始 化 操 作 的 时 候 ,大的 Windows 程 序 ( 例如 Visual C++ ,甚 至 是 Windows 自 已 ) 通 常 要 在 显 示 一 个 主 窗 口 之 前 出 现 一 个 初 始 屏 幕 。这 不 仅 仅 可 以 在 程 序 忙 的 时 候为 用 户 提 供 一 些 吸 引 人 的 东 西 , 而 且 还 可 以 起 到 表 达 系 统 响 应 的 效 果 。 Gadget
程 序 十 分 小 , 因 此 , 它 不 需 要 初 始 屏 幕 , 但 这 也 没 关 系 。 让 我 们 添 加 一 个 带 有 时钟 的 状 态 栏 。 你 可 能 不 会 想 相 信 , 这 非 常 简 单 。
我 们 所 需 要 的 组 件 叫 做 Splash Screen 和 Status Bar, 在 Gallery 对 话 的 Visual C++ Components 文 件 夹 中 , 它 们 是 用 这 些 大 图 标 标 识 的 。
通 过 双 击 组 件 图 标 可 以 将 每 个 组 件 添 到 打 开 的 Gadgetes 项 目 之 中 。 Status Bar 组件 运 行 了 一 个 对 话 ,让 你 选 择 新 状 态 栏 是 否 显 示 日 期 和 时 间 。如 果 想 在 状 态 栏 中包 括 时 间 ,请 在 第 二 步 中 单 击 Use System Defaul t( 使 用 系 统 默 认 值 )单 选 按 钮 ( 对于 其 他 步 骤 接 受 默 认 设 置 )。 在 关 闭 Gallery 时 , 你 将 会 发 现 创 建 在 最 右 边 带 有 小时 钟 状 态 栏 的 代 码 已 添 加 到 MainFrm.cpp 文 件 之 中 。 你 只 需 将 阴 影 行 添 向M ainFrm.cpp 文 件 的 消 息 映 射 中 即 可 :
//{{AFX_MSG_MAP(CMainFrame) ON_COMMAND( IDM_PROPSHEET, OnProperties ) ON_WM_CREATE ()
//}}AFX_MSG_MAP
Splash Screen 组 件 提 供 了 一 个 名 为 Splsh16.bmp 的 文 件 , 它 包 含 一 个 位 图 图 像 。
对 于 你 自 己 设 计 的 初 始 屏 幕 , 在 图 形 编 辑 器 中 创 建 一 个 新 的 16 色 图 像 , 并 将 其保 存 在 相 同 的 文 件 名 之 下 , 覆 盖 掉 原 来 的 Splash16.bmp 文 件 。 初 始 屏 幕 默 认 的持 续 时 间 是 3/4 秒 (750 毫 秒 ),但 是 ,你 可 以 通 过 在 Splash.cpp 文 件 中 修 改 如 下 代码 来 改 变 它 :
SetTimer(1,750,Null);
如 果 想 看 到 有 效 的 新 组 件 , 请 重 建 Gadgets 程 序 , 并 运 行 它 。 图 7-3 显 示 了 新 程序 的 样 子 。
图 7-3 带 有 新 的 初 始 屏 幕 、 状 态 栏 和 时 钟 的 Gadgets 程序
创 建 自 定 义 的 组 件
Gallery 是 无 限 可 扩 展 的 。 你 可 以 通 过 创 建 自 定 义 的 组 件 ( 例 如 对 话 框 或 新 类 ), 将 它 们 添 加 到 新 的 集 合 中 。 对 于 类 来 说 , 自 定 义 的 组 件 由 源 代 码 组 成 , 通 常 是 单个 的 CPP 实 现 文 件 和 H 头 文 件 。 如 果 这 个 类 是 从 MFC 对 话 类 (CDialog, CFormView, CPropertyPage, CRecordView 或 CDaoReardView )中 派 生 出 来 的 , 那么 , 该 组 件 还 包 括 用 于 该 对 话 的 资 源 数 据 。
应 当 把 你 的 工 作 作 为 一 个 新 组 件 来 保 存 , 理 由 如 下 。 首 先 , Gallery 可 以 做 为 存储 可 重 用 源 代 码 的 仓 库 来 使 用 。当 你 为 一 个 项 目 开 发 一 个 类 ,并 将 其 作 为 一 个 组件 来 保 存 的 时 候 , 你 不 必 为 了 将 该 类 添 加 到 新 项 目 而 搜 索 磁 盘 文 件 来 查 找 源 代码 。 创 建 新 组 件 的 第 二 个 原 因 是 通 过 网 络 链 接 的 开 发 者 的 特 殊 需 要 ,他 们 现 在 可以 向 中 心 组 件“ 银 行 ” 中 添 加 组 件 , 或 从 中 调 用 组 件 。 在 开 发 新 类 之 前 , 你 可 以检 查 一 下 Gallery , 看 看 是 否 有 人 已 经 为 你 做 了 这 项 工 作 。
如 果 想 向 Gallery 添 加 一 个 组 件 , 请 在 Workspace 窗 口 的 窗 格 中 右 击 它 的 类 , 并从 上 下 文 菜 单 中 选 择 Add To Gallery ( 添 加 到 组 件 集 ) 命 令 。 图 7-4 说 明 了 为 名为 CNewComponent 的 类 的 添 加 步 骤 。
如 果 必 要 的 话 , 单 击 Add To Gallery 命 令 将 创 建 一 个 新 的 文 件 夹 。 该 子 文 件 夹 具有 与 项 目 相 同 的 名 字 ,并 且 包 含 新 的 具 有 OGX 扩 展 名 的 组 件 文 件 。OGX 组 件 文件 不 是 指 向 原 始 类 源 代 码 的 指 针 ; 它 包 含 有 定 义 该 类 的 CPP 和 H 文 本 文 件 的 绑
定 副 本 。 如 果 该 类 是 基 于 对 话 的 , 那 么 O G X 文 件 便 存 档 了 代 码 对 话 资 源 脚 本 的一 个 副 本 。 因 为 OGX 文 件 存 档 了 代 码 的 完 整 副 本 , 所 以 , 一 个 组 件 可 以 在 它 的项 目 消 失 后 依 旧 存 在 。 即 使 项 目 被 删 除 或 移 动 了 , Gallery 总 是 可 以 产 生 原 始 的资 源 代 码 。 这 就 意 味 着 , 在 将 组 件 添 加 到 Gallery 时 代 码 的 快 照 便 是 组 件 。 组 件不 是 与 源 代 码 一 起 自 动 更 新 的 ; 如 果 想 更 新 组 件 , 你 必 须 再 次 向 Gallery 添 加 该类 。
图 7-4 向 Gallery 添加一个类
你 所 创 建 的 自 定 义 组 件 有 一 定 的 局 限 。 一 是 对 于 自 定 义 组 件 , Gallery 对 话 中 的More Info 按 钮 是 非 活 动 的 , 因 为 没 有 直 接 的 方 法 添 加 在 线 帮 助 , 来 解 释 该 组 件是 如 何 工 作 的 。 自 定 义 组 件 也 不 能 像 Property Sheet 和 Splash Screen 组 件 所 做 的那 样 , 自 动 修 改 项 目 中 现 有 的 源 文 件 。 要 创 建 适 合 于 软 件 市 场 的 专 业 质 量 的 组件 , 需 要 M icrosoft 的 Component Builder's Kit , 利 用 它 , 可 以 创 建 可 使 用 在 线 帮助 系 统 的 可 执 行 组 件 。 M icrosoft 不 再 为 该 工 具 箱 收 取 费 用 , 但 目 前 只 能 提 供 给软 件 公 司 , 不 能 提 供 给 个 人 。 如 想 申 请 Builder's Kit 的 副 本 , 请 在 你 的 公 司 的 信头 上 向 如 下 地 址 发 送 一 个 请 求 。
Visual C++ Manager Microsoft Corporation One Microsoft Way
Redmond, WA 98052-6399
例 子 : 用 于 目 录 列 表 的 自 定 义 组 件
本 节 说 明 创 建 自 定 义 组 件 的 过 程 , 首 先 规 划 出 一 个 名 为 CDirListCtrl 的 新 类 , 然后 将 它 添 加 到 Gallery 。 CDirListCtrl 是 从 MFC 的 CListCtrl 类 中 派 生 的 , 它 在 列表 视 图 通 用 控 件 中 显 示 目 录 列 表 , 并 附 加 上 帮 助 你 迅 速 区 分 驱 动 器 、文 件 夹 或 文
件 的 小 图 标( 见 图 7-5 )。单 击 列 表 中 的 驱 动 器 或 文 件 夹 将 自 动 改 变 路 径 并 刷 新 列表 。 因 为 CDirListCtrl 不 使 用 D lgDirList API 函 数 , 所 以 , 它 可 以 在 W indows 95 中 正 确 显 示 长 文 件 名 。如 果 这 与 我 们 在 第 5 章 中 为 D irList1 程 序 所 使 用 的 一 些 东西 相 像 , 那 么 你 就 对 了 。 后 一 节 将 显 示 为 了 创 建 叫 做 D irList2 的 程 序 的 新 版 本 而添 加 D irListCtrl 自 定 义 组 件 。
图 7-5 典 型 对 话 框 中 的 CDirListCtrl 列 表 视 图 控 件
列 表 7-1 显 示 了 CDirListCtrl 类 的 源 代 码 , 包 含 在 本 书 配 套 光 盘 Code\Chapter.07\ D irCtrl 文 件 夹 中 的 D irCtrl.h 和 D irCtrl.cpp 文 件 中 。CD .CDirlistCtrl 包 含 五 个 公 共成 员 函 数 , 其 中 有 三 个 在 D irListCtrl 头 文 件 中 声 明 。 在 其 余 两 个 之 中 , Create 用于 建 立 列 表 视 图 控 件 , ShowList 用 于 刷 新 该 控 件 中 的 目 录 列 表 。显 示 的 目 录 路 径存 储 在 私 有 的 StrDirectory 字 符 串 之 中 。 改 变 列 表 是 两 步 过 程 , 在 该 过 程 中 , CDirListCtrl 对 象 的 创 建 者 首 先 调 用 SetPath 函 数 来 改 变 目 录 路 径 , 然 后 调 用
ShowList 来 显 示 新 目 录 。
表 7-1 CDirListCtrl 类 的 源 文 件
DirCtrl.h
// ********************************************************************
//
// DirCtrl.h
//
// ********************************************************************
#define DL_DRIVE 1
#define DL_FOLDER 2
#define DL_FILE 4
#define DL_ALL 7
typedef BOOL (CALLBACK *PCALLBACK)( PWIN32_FIND_DATA );
class CDirListCtrl : public CListCtrl
{
private:
int iListFlags, idcPath;
CString strDirectory, strFilter;
CListBox listDummy;
CImageList imageList;
CDialog* pDialog;
BOOL FindFiles( DWORD dwFlags );
void GetCurrentDirectory ();
PCALLBACK pCallBack;
public:
BOOL ShowList( CString& Filter );
void GetPath( CString& strPath ) { strPath = strDirectory; }
void SetPath( CString& strPath ) { strDirectory = strPath; }
void SetCallBack( PCALLBACK pCB ) { pCallBack = pCB; }
void Create( CDialog* pDlg, LPRECT prect, int idcControl,
int idcStatic, int iFlags=DL_ALL, int idiIcon=0 );
protected:
BOOL GetDirectoryList( int iType );
afx_msg void OnSelChange( NMHDR* pnumhdr, LRESULT* pResult );
DECLARE_MESSAGE_MAP ()
};
DirCtrl.cpp
// ********************************************************************
//
// DirCtrl.cpp
//
// ********************************************************************
#include "afxcmn.h"
#include "dirctrl.h"
#define IDC_DUMMY 48888
void CDirListCtrl::Create( CDialog* pDlg, LPRECT prect, int idcControl,
int idcStatic, int iFlags, int idiIcon )
{
pDialog = pDlg; // Save ptr to dialog object
idcPath = idcStatic; // Save ID of static control
pCallBack = NULL; // Assume no call-back
// Create DirListCtrl control
if (!CreateEx( WS_EX_CLIENTEDGE, WC_LISTVIEW, NULL,
LVS_LIST | LVS_SINGLESEL | LVS_ALIGNLEFT | WS_VISIBLE | WS_CHILD,
WS_VISIBLE | WS_CHILD,prect->left,prect->top,
prect->left, prect->top, prect->right, prect->bottom,
pDialog->m_hWnd, (HMENU) idcControl ))
{
MessageBox( "Failed to create DirListCtrl" );
return; } // Associate "file", "folder", and "drive" icons with DirListCtrl control imageList.Create( 16, 16, TRUE, 1, 0 ); if (idiIcon) { |
||||
---|---|---|---|---|
imageList.Add( AfxGetApp()->LoadIcon( idiIcon ) |
); |
// Floppy |
||
imageList.Add( AfxGetApp()->LoadIcon( idiIcon + |
1 |
) ); |
// Hard |
|
imageList.Add( AfxGetApp()->LoadIcon( idiIcon + |
2 |
) ); |
// CD-ROM |
|
imageList.Add( AfxGetApp()->LoadIcon( idiIcon + |
3 |
) ); |
// Folder |
|
imageList.Add( AfxGetApp()->LoadIcon( idiIcon + |
4 |
) ); |
// File |
|
} |
SetImageList( &imageList, LVSIL_SMALL );
// Create dummy list box
CRect rectDummy;
rectDummy.SetRectEmpty ();
listDummy.Create( WS_CHILD | LBS_SORT, rectDummy, pDialog, IDC_DUMMY );
// Start with current directory
GetCurrentDirectory ();
iListFlags = iFlags;
}
BOOL CDirListCtrl::ShowList( CString& Filter )
{
static int iType[3] = { DL_DRIVE, DL_FOLDER, DL_FILE };
BOOL bRetCode = FALSE;
int i, j, n, nIcon, nItem = 0;
UINT uType;
PSTR pItem = new char[MAX_PATH];
char szRoot[] = {"x:\\\0"}-->;
if (Filter.IsEmpty ())
strFilter = "*.*";
else
{
strFilter = Filter;
strFilter.TrimLeft (); // Remove any leading
if (strFilter.GetAt( 0 ) == '\\') // white spaces or
{ // backslash
strFilter.SetAt( 0, ' ' );
strFilter.TrimLeft ();
}
}
// Update static control and empty the list
pDialog->SetDlgItemText( idcPath, strDirectory );
DeleteAllItems ();
// Display directory list in this order: drives, folders, files
for (n=0, j=DL_DRIVE; n < 3; n++, j <<= 1)
{
if ((iListFlags & j))
{
if (GetDirectoryList( iType[n] ))
{
bRetCode = TRUE;
// Copy list from dummy box to list view control
i = 0;
while (listDummy.SendMessage( LB_GETTEXT, i++,
(LPARAM) pItem ) != LB_ERR)
{
if (lstrcmp( pItem, "." ) &&
lstrcmp( pItem, ".." ))
{
// Determine which icon the listed item
// should have:floppy, hard disk, etc.
switch (j)
{
case DL_DRIVE:
szRoot[0] = *pItem;
nIcon = 1;
uType = ::GetDriveType( szRoot );
if (uType == DRIVE_REMOVABLE)
nIcon = 0;
if (uType == DRIVE_CDROM)
nIcon = 2;
break;
case DL_FOLDER:
nIcon = 3;
break;
default:
nIcon = 4;
}
InsertItem( nItem, pItem, nIcon );
SetItemData( nItem++, iType[n] );
}
}
}
}
}
delete [] pItem; // Clean up
return bRetCode;
}
BEGIN_MESSAGE_MAP (CDirListCtrl, CListCtrl)
ON_NOTIFY_REFLECT (LVN_ITEMCHANGED, OnSelChange)
END_MESSAGE_MAP ()
void CDirListCtrl::OnSelChange( NMHDR* pnumhdr, LRESULT* pResult )
{
NM_LISTVIEW* pnmlv = (NM_LISTVIEW*) pnumhdr;
// Get item selected in list view
if ((pnmlv->uNewState) & LVIS_FOCUSED)
{
// Is it a drive, folder, or file?
int iType = GetItemData( pnmlv->iItem );
if (iType != DL_FILE) // Ignore it if it's a file
{
CString strItem = GetItemText( pnmlv->iItem, 0 );
// If drive selected, replace directory
if (iType == DL_DRIVE)
strDirectory = strItem; // Directory = "d:"
// If folder selected, append it to current path
else
strDirectory += strItem; // Append string "subdir"
strDirectory += "\\"; // In either case, append '\'
if (!ShowList( strFilter )) // New directory listing
{
// If error, reset to current directory
GetCurrentDirectory ();
strFilter.Empty ();
ShowList( strFilter );
}
}
}
*pResult = 0;
}
BOOL CDirListCtrl::GetDirectoryList( int iType )
{
DWORD dwDrives;
char szDrive[] = "A:";
BOOL bRet;
// Empty the dummy list box
listDummy.SendMessage( LB_RESETCONTENT, 0, 0 );
switch (iType)
{
case DL_DRIVE:
dwDrives = ::GetLogicalDrives ();
for (; dwDrives && szDrive[0] <= 'Z'; ++szDrive[0])
{
if (dwDrives & 1)
listDummy.SendMessage( LB_ADDSTRING, 0,
(LPARAM) szDrive );
dwDrives >>= 1;
}
bRet = TRUE;
break;
case DL_FOLDER:
bRet = FindFiles( FILE_ATTRIBUTE_DIRECTORY );
break;
case DL_FILE:
bRet = FindFiles( 0L );
break;
}
return bRet;
}
BOOL CDirListCtrl::FindFiles( DWORD dwFlags )
{
WIN32_FIND_DATA fd;
HANDLE hFind;
CString str = "*.*";
BOOL bOkay;
if (dwFlags == 0)
str = strFilter;
hFind = ::FindFirstFile( strDirectory + str, &fd );
if (hFind == INVALID_HANDLE_VALUE)
return FALSE;
while (TRUE)
{
if (dwFlags == (fd.dwFileAttributes &
FILE_ATTRIBUTE_DIRECTORY))
{
bOkay = (pCallBack) ? pCallBack( &fd ) : TRUE;
if (bOkay)
listDummy.SendMessage( LB_ADDSTRING, 0, (LPARAM) fd.cFileName );
}
if (!::FindNextFile( hFind, &fd ))
break;
}
::FindClose( hFind );
return TRUE;
}
void CDirListCtrl::GetCurrentDirectory ()
{
PTSTR pDir = new char[MAX_PATH];
仅 仅 为 了 创 建 控 件 而 调 用 一 次 的 Create 函 数 , 在 D irCtrl 头 文 件 中 , 其 原 型 为 :
void Create( CDialog* pDlg, LPRECT prect, int idcControl, int idcStatic, int iFlags=DL_ALL, int idiIcon=0 );
表 7-1 解 释 了 该 函 数 的 六 个 参 数 。
调 用 者 可 以 在 它 的 资 源 代 码 中 最 多 提 供 五 个 图 标 图 像 , 每 个 16 像 素 形 成 一 个 正方 形 , 它 们 代 表 了 在 列 表 视 图 控 件 中 显 示 的 各 种 驱 动 器 类 型 和 文 件 名 。 图 7-5 显示 了 可 能 的 图 标 图 像 , 它 们 包 括 软 盘 驱 动 器 、 硬 盘 、 CD-ROM 驱 动 器 、 文 件 、文 件 夹 以 及 代 表 文 件 的 小 钻 石 形 状 。Create 函 数 通 过 调 用 CImageList::Add 函 数 ,
可 以 将 每 个 图 标 附 属 到 控 件 , 由 idiIcon 参 数 标 识 以 软 盘 驱 动 器 图 标 作 为 开 始 。因 此 idiIcon+1 代 表 硬 盘 图 像 的 标 识 符 ;idiIcon+2 是 代 表 CD-ROM 驱 动 器 图 像 的标 识 符 ; 等 等 。 图 标 是 可 选 的 , 也 可 以 不 使 用 它 。
表 7-1 Create 函 数 的 参 数
参 数 说 明
pDlg 用 于 包 含 对 话 框 的 this 指 针
prect 指 向 包 含 在 对 话 窗 口 内 列 表 视 图 控 制 的 维 数 的
RECT 结 构
idcControl 列 表 视 图 控 件 的 标 识 符
idcStatic 对 话 中 静 态 控 件 的 标 识 符 。 ShowList 函 数 将 当 前 的目 录 路 径 写 到 idcStatic 控 件
续 表
iFlags 在 D irCtrl.h 中 定 义 的 位 标 志 , 由 它 来 确 定 目 录 所 列出 的 内 容 。 值 可 以 是 DL_DRIVE, DL_FOLDER 和DL_FILE 的 任 意 组 合 ,默 认 的 DL_ALL 值 包 括 列 表中 所 有 的 三 种 类 型
idiIcon 用 于 在 目 录 列 表 中 显 示 的 五 个 图 标 中 的 第 一 个 标 识符 值
Create 函 数 在 退 出 之 前 调 用 CListBox::Create ,来 建 立 一 个 名 为 listDummy 的 不 可见 的 列 表 框 控 件 。 listDummy 列 表 框 从 来 都 不 显 示 , 它 仅 仅 作 为 组 成 目 录 列 表 的文 件 名 的 中 间 存 储 仓 库 。FindFiles 函 数 在 目 录 中 定 位 的 每 个 文 件 夹 的 名 字 被 添 加到 listDummy 列 表 框 。 既 然 该 列 表 框 是 用 LBS_SORT 标 志 创 建 的 , 那 么 , 当 它接 收 到 每 个 文 件 和 文 件 夹 名 字 的 时 候 , 它 会 自 动 将 它 的 字 符 集 进 行 分 类 。 当ShowList 函 数 从 列 表 框 中 展 开 字 符 串 的 时 候 ,该 列 表 框 将 该 按 字 母 顺 序 一 个 接 一个 地 传 送 字 符 。
SetCallBack 内 嵌 函 数 用 于 取 得 一 个 可 选 的 回 调 例 程 的 地 址 。如 果 PCallBack 地 址为 非 空 , 那 么 , FindFiles 函 数 就 假 定 回 调 例 程 存 在 , 并 在 将 文 件 名 添 加 到listDummy 列 表 框 之 前 , 为 每 个 文 件 调 用 它 :
bOkey = (pCallBack) ? pCallBack(&fd):TRUE; if(bOkey)
listDummy.SendMessage(LB_ADDSTRING, 0, (LPARAM))fd.cFileNAme;
通 过 从 回 调 例 程 中 返 回 TRUE 或 FALSE , CDirListCtrl 对 象 的 创 建 者 可 以 接 受和 拒 绝 任 何 文 件 。 在 本 章 稍 后 , 我 们 将 看 到 DirList2 程 序 是 如 何 利 用 该 项 功 能 来为 目 录 列 表 中 所 显 示 的 文 件 打 开 窗 口 的 。
创 建 CDirListCtrl 类
在 作 为 组 件 添 加 CDirListCtrl 之 前 , 我 们 需 要 一 个 临 时 项 目 来 包 含 源 文 件 。 这 是因 为 Workspace 窗 口 的 ClassView 窗 格 只 能 在 打 开 的 项 目 中 才 能 访 问 。 因 此 , 当你 想 添 加 到 Gallery 的 类 作 为 不 属 于 项 目 的 源 代 码 存 在 时 , 创 建 一 个 临 时 类 是 很有 必 要 的 。 一 旦 该 类 已 被 添 加 到 Gallery , 你 就 可 以 删 除 这 个 临 时 项 目 了 。 项 目名 无 关 紧 要 。
你 可 以 用 两 种 方 法 创 建 一 个 临 时 项 目 来 包 含 现 有 的 类 。 第 一 种 方 法 依 赖 于AppWizard 。在 File 菜 单 上 单 击 New ,在 Projects 选 项 卡 中 选 择 MFC AppWizard (exe) 图 标 ,键 入 项 目 名 ( 下 面 所 概 括 的 步 骤 假 定 项 目 名 为 D irCtrl) 。单 击 AppWizard 中 的 Finish 按 钮 来 接 受 所 有 的 默 认 设 置 ,这 并 不 重 要 的 原 因 是 , 我 们 将 抛 弃 所 有的 生 成 文 件 。
为 包 含 组 件 类 而 创 建 临 时 项 目 的 第 二 种 方 法 不 依 赖 于 AppWizard 。这 样 一 个 项 目仅 仅 需 要 一 个 与 项 目 同 名 的 存 根 RC 文 件 。 甚 至 这 个 RC 文 件 可 以 是 空 的 。 如 果想 创 建 这 个 项 目 , 请 在 New 对 话 中 的 Projects 选 项 卡 中 选 中 Win32 Application 图 标 ( 而 不 是 AppWizard 图标 ), 给 项 目 取 一 个 名 字 ( 例 如 D irCtrl) , 然 后 单 击 O K 。在 该 向 导 的 下 一 步 , 接 受 指 定 空 项 目 的 默 认 设 置 , 单 击 Finish 按钮。下一步,使用 文 本 编 辑 器 来 创 建 一 个 空 的 RC 文 件 , 并 将 其 保 存 到 D irCtrl 项 目 文 件 夹 。 在新 项 目 处 于 打 开 状 态 的 时 候 , 从 Project 菜 单 选 择 Add To Project 命 令 , 并 单 击次 级 菜 单 上 的 File s。在 Insert Files Into Project 对 话 中 双 击 存 根 RC 文 件 , 将 其 添加 到 项 目 , 这 就 是 启 用 ClassWizard 所 需 要 做 的 所 有 工 作 , 现 在 可 以 通 过 View 菜 单 上 的 ClassWizard 命 令 访 问 ClassWizard 了 。当 调 用 ClassWizard 的 时 候 ,Visual C++ 将 检 测 到 用 于 该 项 目 的 CLW 文 件 不 存 在 , 并 提 供 它 以 创 建 一 个 新 文 件 。 你必 须 单 击 Ye s,并 在 随 后 出 现 的 Select Source File s( 选 择 源 文 件 )对 话 中 单 击 O K 来 继 续 MFC ClassWizard 对 话 。
无 论 使 用 哪 一 种 方 法 来 创 建 新 项 目 , 都 要 单 击 MFC ClassWizard 对 话 中 的 Add Clas s( 添 加 类 )按 钮 ,然 后 选 择 New ,来 调 用 如 图 6-4 所 示 的 New Class 的 对 话 。键 入 CDirListCtrl 作 为 类 名 , 选 择 CListCtrl 作 为 基 类 。 单 击 Change 按 钮 , 将 所生 成 的 源 文 件 重 命 名 为 DirCtrl.h 和 DirlCtrl.CPP 。当 你 关 闭 ClassWizard 对 话 的 时候 , Visual C++ 将 编 写 用 于 新 CDirListCtrl 类 的 存 根 代 码 , 并 且 将 文 件 自 动 添 加到 项 目 中 。
第 二 步 是 为 新 类 提 供 源 代 码 。 将 D irCtrl.cpp 和 D irCtrl.h 文 件 从 本 书 配 套 光 盘 的
Code\Chapter.07\Dirctrl 文 件 夹 复 制 到 DirCtrl 项 目 文 件 夹 ,覆 盖 掉 ClassWizard 刚刚 创 建 的 存 根 文 件 。 还 将 文 件 D irCtrl.rco, Floppy.ico, HardDisk.ico, CD-ROM.ico,
Folder.ico 和 File.ico 复 制 到 项 目 文 件 夹 , 以 后 将 需 要 这 些 文 件 。创 建 CDirListCtrl 组 件
CDirListCtrl 目 前 是 一 个 正 在 开 发 的 类 , 还 不 是 已 完 成 的 和 可 以 使 用 的 组 件 。 展现 项 目 的 ClassView 窗 格 , 并 单 击 类 列 表 中 的 CDirListCtrl, 然 后 从 如 图 7-4 所 示的 上 下 文 菜 单 中 选 择 Add To Gallery 命 令 。 Visual C++ 把 D irCtrl.cpp 和 D irCtrl.h 组 成 一 个 名 为 D irListCtrl.ogx 的 单 一 文 件 ,并 将 这 个 OGX 文 件 存 储 在 名 为 DirCtrl 的 新 Gallery 文 件 夹 中 。 下 面 几 段 将 详 细 介 绐 这 个 新 的 Gallery 文件夹,因此,不要 将 它 与 原 来 的 D irCtrl 项 目 文 件 夹 弄 混 了 。
打 开 Gallery 中 的 D irCtrl 文 件 夹 看 看 这 个 新 组 件 ,它 是 以 大 图 标 视 图 的 形 式 出 现的 。
它 需 要 做 一 些 额 外 的 工 作 , 但 你 可 以 将 它 这 个 组 件 的 外 观 再 装 饰 一 下 。第 一 步 是将 O G X 文 件 移 出 D irCtrl 文 件 夹 , 并 且 用 快 捷 方 式 文 件 来 代 替 它 。 右 击 新 的D irListCtrl.ogx 图 标 , 并 从 上 下 文 菜 单 中 选 择 Cut 命 令 。 通 过 右 击 大 列 表 框 的 任何 空 白 区 域 , 并 选 择 New 命令,在 Gallery 对 话 的 文 件 夹 中 创 建 一 个 新 的 子 文 件夹 ,为 新 文 件 夹 取 一 个 像 OGX Files 这 样 的 一 般 性 的 名 字 ,然 后 ,将 D irListCtrl.ogx 文 件 粘 贴 进 这 个 新 文 件 夹 。右击 DirListCtrl.ogx 图 标 ,从 上 下 文 菜 单 中 选 择 Create Shortcu t( 创 建 快 捷 方 式 ) 命 令 , 然 后 剪 切 该 快 捷 方 式 文 件 , 并 将 其 粘 贴 回 原 来的 DirCtrl 文 件 夹 。
我 们 就 要 完 成 了 。 这 时 候 , 原 来 的 OGX 文 件 已 被 移 到 了 一 个 叫 做 OGX Files 的文 件 夹 中 , 并 且 为 D irCtrl 文 件 夹 中 的 一 个 快 捷 方 式 所 取 代 。 最 后 一 步 是 改 进D irCtrl 文 件 夹 中 快 捷 方 式 图 标 的 外 观 。 通 过 右 击 该 图 标 , 并 选 择 Renam e, 为 快捷 方 式 图 标 提 供 一 个 更 具 说 明 性 的 名 字 ( 例如 Directory List) 。 右 击 D irectory List
图 标 , 选 择 Properties, 然 后 单 击 Properties 对 话 Shortcut 选 项 卡 中 的 Change Icon
( 更 改 图 标 )按 钮 。输 入( 或 浏 览 )到 你 以 前 曾 经 从 配 套 光 盘 中 复 制 的 DirCtrl.ico 文 件 的 路 径 。 当 你 单 击 O K 关 闭 Properties 对 话 的 时 候 , 组 件 现 在 在 DirCtrl 文 件中 就 应 该 像 这 个 样 子 。
我 们 只 做 了 很 少 的 工 作 , 就 使 组 件 的 外 观 比 我 们 开 始 的 时 候 要 好 。 如 果 你 肯 付 出努 力 , 还 可 以 把 所 有 的 新 组 件 文 件 都 放 入 OGX Files 文 件 夹 , 按 照 相 同 的 方 法 用快 捷 方 式 来 代 替 它 们 。
不 幸 的 是 , Visual C++ 没 有 提 供 简 单 的 方 法 来 将 说 明 附 加 到 类 组 件 上 , 在 OGX 文 件 和 它 的 快 捷 方 式 中 均 不 可 以 。只 能 用 文 件 名 来 向 其 他 开 发 者 提 供 有 关 组 件 目的 的 必 要 信 息 。 创 建 一 个 可 以 描 述 自 己 的 组 件 , 需 要 前 面 提 到 的 Component Builder's Kit 。图 7-1 显 示 了 当 Dialog 栏 组 件 被 选 中 的 时 候 ,第 一 条 说 明 是 如 何 出现 在 Gallery 之 中 的 。尽 管 已 超 出 了 本 章 的 范 围 ,但 使 用 Builder's Kit 创 建 D irectory
List 组 件 ,允 许 我 们 在 DIR 图 标 在 对 话 中 被 选 中 的 时 候 ,附 加 上 一 条 类 似 的 说 明 :
Display a sorted directory listing in a list view control. Complete with icons representing drives, folders, and files.
退 出 Gallery 之 后 , 你 可 以 通 过 在 Gallery 对 话 中 显 示 D irCtrl 文 件 夹 , 并 双 击 代表 D irectory List 组 件 的 快 捷 方 式 , 来 将 CDirListCtrl 类 添 加 向 任 何 打 开 的 项 目 。既 然 组 件 已 被 安 装 到 Gallery 之 中 , D irCtrl 项 目 就 已 经 实 现 了 它 的 目 的 , 不 再 需要 它 了 。 D irListCtrl.ogx 包 含 有 类 源 代 码 , 因 此 你 可 以 安 全 地 关 闭 这 个 项 目 , 并且 删 除 原 来 的 DirCtrl.cpp 和 D irCtrl.h 文 件 , 以 及 DirCtrl 项 目 文 件 夹 中 的 其 他 文件 。 不 过 , 不 要 删 除 以 前 从 光 盘 中 复 制 的 ICO 文 件 。D irectory List 快 捷 方 式 链 接指 向 包 含 有 代 表 组 件 的 DIR 图 标 的 D irCtrl.ico 文 件 。 当 你 将 新 CDirListCtrl 类 插入 项 目 的 时 候 , 它 可 能 需 要 部 分 或 全 部 保 留 文 件 , 例 如 HardDisk.ico 和Folder.ico 。 下 节 将 用 一 个 名 为 D irList2 的 范 例 程 序 来 说 明 D irectory List 组 件 。
例 子 :D irList2 程 序
你 可 能 会 回 想 起 第 5 章 中 介 绍 的 DirList1 程 序 , 它 使 用 了 D lgDirList API 函 数 来在 列 表 框 控 件 中 显 示 目 录 列 表 。 该 列 表 不 仅 在 外 观 上 很 平 淡 , 而 且 难 以 阅 读 , 因为 DlgDirList 不 能 在 W indows 95 中 识 别 长 文 件 名 ,所 以 ,它 只 能 在 W indows NT 中 显 示 长 文 件 名 。 这 里 所 展 示 的 D irList2 程 序 通 过 融 入 新 的 D ireCtory List 组 件
克 服 了 这 些 不 足 之 处 。
如 图 7-6 所 示 的 D irlist2 程 序 与 D irlist1 一 样 , 是 基 于 对 话 的 , 它 使 用 属 性 表 与 用户 进 行 交 互 。 除 了 D irectory List 控 件 所 提 供 的 吸 引 人 的 目 录 列 表 之 外 , DirList2
还 利 用 了 属 性 表 的 Date 和 Size 选 项 卡 , 允 许 用 户 按 照 文 件 大 小 或 日 期 对 列 表 进行 过 滤 。例 如 ,程 序 可 以 只 显 示 在 最 后 一 日 中 创 建 容 量 为 5 到 10KB 之 间 的 文 件 。使 用 前 面 所 介 绍 的 CDirListCtrl 回 调 功 能 可 以 实 现 其 他 过 滤 。
图 7-6 DirList2 程 序
为 使 我 们 添 加 的 内 容 比 较 少 , D irList2 程 序 使 用 了 与 D irList1 程 序 相 同 的Resource.h 文 件 和 相 同 的 RC 文 件 。 这 些 文 件 的 内 容 在 第 5 章 中 已 经 列 出 。 如 果你 愿 意 自 己 独 立 创 建 DirList2 程 序 , 并 且 不 执 行 Setup 程 序 来 从 配 套 光 盘 上 安 装范 例 项 目 ; 请 单 击 File 菜 单 上 的 New , 并 选 中 Projects 选 项 卡 。 因 为 D irList2 不是 AppWizard 程 序 , 所 以 , 请 单 击 W in32 Application 来 创 建 该 项 目 。 在 该 向 导的 对 话 出 现 时 , 输 入 项 目 名 , 并 接 受 默 认 的 设 置 。 在 Visual C++ 创 建 了 空 项 目 之后 , 单 击 Project 菜 单 上 的 Settings。在 Project Settings 对 话 的 General 选 项 卡 中 , 选 择 选 项 , Use MFC In A Shared DLL ( 在 共 享 的 DLL 中 使 用 MFC )。
将 文 件 DirList2.cpp, DirList2.h, DirList2.rc 和 Resource.h 从 本 书 配 套 光 盘 的Code\Chapter.07\DirList2 文 件 夹 复 制 到 项 目 文 件 夹 。 还 要 把 DirList.ico 文 件 复 制到 DirList2\Res 子 文 件 夹 , 以 便 D irList2 有 一 个 应 用 程 序 图 标 。 通 过 从 Project 菜单 选 择 Add To Project, 然 后 从 次 级 菜 单 中 选 择 Files 命 令 , 来 将 D irList2.cpp 和D irList2.rc 文 件 附 加 到 项 目 上 。
因 为 DirList2 程 序 利 用 了 新 的 CDirListCtrl 类 , 所 以 还 需 要 几 个 文 件 。 当 然 , 这是 练 习 的 整 个 目 的 : 既 然 类 已 经 安 装 在 Gallery 之 中 了 , 那 么 , 添 加 用 于CDirListCtrl 的 源 文 件 就 是 一 件 很 容 易 的 工 作 了 。 通 过 再 次 从 Project 菜 单 中 选 择Add To Projec t, 并 且 单 击 Components And Controls , 可 以 打 开 Gallery 对 话 。 在Gallery 的 D irCtrl 文 件 夹 中 , 双 击 代 表 新 Directory List 组 件 的 图 标 。 源 文 件D irCtrl.cpp 和 D irctrl.h 自 动 从 D irListCtrl.ogx 组 件 文 件 中 展 开 并 添 加 到 项 目 中 。
不 幸 的 是 , Gallery 不 能 够 提 供 CDirListCtrl 在 目 录 列 表 中 显 示 图 标 所 需 要 的 ICO 文 件 。 除 了 通 过 使 用 M icrosoft 的 Bulder's Kit 创 建 该 组 件 之 外 , 没 有 办 法 将 ICO 文 件 与 OGX 文 件 中 的 源 代 码 捆 绑 起 来 , 因 此 , 必 须 在 一 步 中 将 所 有 必 要 的 文 件传 送 给 项 目 。 组 件 的 用 户 必 须 手 工 复 制 ICO 文 件 , D irList2 只 需 要 驱 动 器 和 文 件夹 图 标 , 它 们 包 含 在 位 于 以 前 创 建 的 D irCtrl 项 目 文 件 夹 的 Floppy.ico, HardDisk.ico, CD-ROM.ico 和 Folder.ico 文 件 之 中 。 请 将 这 四 个 文 件 复 制 到D irList2\Res 文 件 夹 。
这 是 额 外 的 步 骤 ,它 必 须 为 D irectory List 这 样 的 自 定 义 组 件 进 行 存 档 。既 然 自 定义 组 件 不 能 在 Gallery 对 话 中 提 供 在 线 帮 助 , 那 么 , 组 件 提 供 文 档 的 最 好 办 法 就是 通 过 在 CPP 文 件 的 开 头 包 括 一 块 注 释 。对 于 Directory List ,注 释 应 该 满 足 使 用该 组 件 的 任 何 项 目 的 四 个 需 要 :
-
ICO 文 件 必 须 被 复 制 到 项 目 的 Res 的 文 件 夹 。
-
RC 文 件 必 须 包 括 在 控 件 中 用 于 每 个 图 标 的 链 接 。
IDI_FLOPPY |
ICON |
"res\\Floppy.ico" |
---|---|---|
IDI_HARDDISK |
ICON |
"res\\HardDisk.ico" |
IDI_CD_ROM |
ICON |
"res\\CD-ROM.ico" |
IDI_FOLDER |
ICON |
"res\\Folder.ico" |
IDI_FILE |
ICON |
"res\\File" |
-
标 识 符 IDI_FLOPPY,IDI_HARDDISK,IDI_CD-ROM,IDI_FOLDER
和IDI_FILE 必 须 在 项 目 的 Resource.h 文 件 中 定 义 。 IDI_FLOPPY 可 以 是任 何 值 ; 其 余 的 标 识 符 值 必 须 依 给 定 的 顺 序 依 次 增 加 。
-
所 有 使 用 类 的 源 文 件 必 须 包 含 如 下 一 行 。
# include "dirctrl.h"
D irList2 的 操 作 基 本 上 与 D irList1 相 同 , 除 了 CPagel 类 包 括 了 一 个 叫 作CheckDateSize 的 新 成 员 函 数 之 外 , CheckDateSize 是 一 个 通 过 调 用CDirListCtrl::SetCallBack 进 行 注 册 的 回 调 函 数 。正 如 在 源 代 码 的 注 解 中 所 说 明 的那 样 , CDirListCtrl::findFiles 为 它 想 添 加 到 目 录 列 表 的 每 个 文 件 名 调 用 这 个 回 调函 数 , 为 该 回 调 函 数 分 配 一 个 指 向 W IN32_FIND_FILE 结 构 的 指 针 , 该 结 构 包 含
有 与 该 文 件 有 关 的 信 息 。 CheckDateSize 用 于 决 定 文 件 确 认 用 户 在 Size 和 Date
页 中 所 设 置 的 过 滤 器 , 并 返 回 一 个 值 TRUE 或 FALSE , 允 许 或 不 允 许 该 文 件 。
修 改 后 的 源 代 码 列 在 下 面 。 没 有 包 括 D irList.rc 和 Resoure.h 文 件 , 原 因 是 它 们 与第 5 章 中 的 只 有 细 微 的 差 别 , 只 是 融 入 了 代 表 图 标 资 源 IDI_FLOPPY, IDI_HARDISK, IDI_CD-ROM 和 IDI_FOLDER 的 几 行 , 因 为 程 序 在 没 有 目 标 标记 的 列 表 中 留 下 了 文 件 名 , 所 以 没 有 定 义 IDI_FILE 。 你 可 以 在 本 书 配 套 光 盘 的Code\Chapter.07\DirList2 子 文 件 夹 中 找 到 所 有 的 文 件 。
列 表 7-2 用 于 DirList1 程 序 的 源 文 件
class CDirListApp : public CWinApp
{
public:
BOOL InitInstance ();
};
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
};
class CPage2; // Forward reference
class CPage3;
///////////////////////////////////////////////////////////////////////
// CPage1 property page
class CPage1 : public CPropertyPage
{
private:
BOOL bEditChange;
CDirListCtrl dirlist;
CString strFilter, strOldFilter;
static CPage2* pDate;
static CPage3* pSize;
static BOOL CALLBACK CheckDateSize( PWIN32_FIND_DATA pfd );
public:
CPage1 () : CPropertyPage( IDD_PAGE1 ) {}
protected:
virtual void DoDataExchange( CDataExchange* pDX );
virtual BOOL OnInitDialog ();
virtual BOOL OnSetActive ();
afx_msg void OnUp1Level ();
afx_msg void OnEditGainFocus ();
afx_msg void OnEditChanging ();
afx_msg void OnEditLoseFocus ();
DECLARE_MESSAGE_MAP ()
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// CPage2 property page
class CPage2 : public CPropertyPage
{
public:
int nAnyDate, PrevDays, PrevMonths;
Ctime timeMin, timeMax;
CPage2 () : CPropertyPage( IDD_PAGE2 ) {}
protected:
virtual void DoDataExchange( CDataExchange* pDX );
virtual BOOL OnInitDialog ();
};
///////////////////////////////////////////////////////////////////////
// CPage3 property page
class CPage3 : public CPropertyPage
{
public:
int nAnySize;
DWORD MinSize, MaxSize;
CPage3 () : CPropertyPage( IDD_PAGE3 ) {}
protected:
virtual void DoDataExchange( CDataExchange* pDX );
virtual BOOL OnInitDialog ();
};
///////////////////////////////////////////////////////////////////////
// CListSheet
class CListSheet : public CPropertySheet
{
public:
CPage1 page1;
CPage2 page2;
CPage3 page3;
CListSheet( LPCTSTR szCaption );
protected:
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand( UINT nID, LPARAM lParam );
DECLARE_MESSAGE_MAP()
};
DisList2.cpp
// ********************************************************************
//
// DirList2.cpp
//
// ********************************************************************
#include "afxwin.h"
#include "afxdlgs.h"
#include "afxcmn.h"
#include "resource.h"
#include "dirctrl.h"
#include "dirlist2.h"
CDirListApp DirListApp;
BOOL CDirListApp::InitInstance ()
{
CListSheet sh( "Directory List" ); // Create property sheet object
sh.DoModal (); // and display dialog
return FALSE; // Return FALSE to exit DirList2
}
CAboutDlg::CAboutDlg() : CDialog( IDD_ABOUTBOX )
{
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CListSheet property sheet
CListSheet::CListSheet( LPCTSTR szCaption ) :
CPropertySheet( szCaption )
{
AddPage( &page1 );
AddPage( &page2 );
AddPage( &page3 );
}
BEGIN_MESSAGE_MAP (CListSheet, CPropertySheet)
ON_WM_SYSCOMMAND()
END_MESSAGE_MAP()
BOOL CListSheet::OnInitDialog()
{
CButton* button;
CPropertySheet::OnInitDialog();
// Add "About..." menu item to system menu
CMenu* pSysMenu = GetSystemMenu( FALSE );
CString str;
str.LoadString( IDD_ABOUTBOX );
pSysMenu->AppendMenu( MF_SEPARATOR );
pSysMenu->AppendMenu( MF_STRING, IDD_ABOUTBOX, str );
// Remove Apply and Cancel buttons and rename OK button
button = (CButton *) GetDlgItem( ID_APPLY_NOW );
button->DestroyWindow();
button = (CButton *) GetDlgItem( IDCANCEL );
button->DestroyWindow();
button = (CButton *) GetDlgItem( IDOK );
button->SetWindowText( "Close" );
// Set the 16-by-16 image (see closing remarks in Chapter 5)
HICON hIcon = (HICON) ::LoadImage( DirListApp.m_hInstance,
MAKEINTRESOURCE( IDI_APPICON ),
IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR );
SetIcon( hIcon, FALSE );
// Activate OnInitDialog for each page to init member variables
SetActivePage( 2 );
SetActivePage( 1 );
SetActivePage( 0 );
return TRUE;
}
void CListSheet::OnSysCommand( UINT nID, LPARAM lParam )
{
if (nID == IDD_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CPropertySheet::OnSysCommand( nID, lParam );
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// CPage1 property page
CPage2* CPage1::pDate; // Static ptrs to Date and
CPage3* CPage1::pSize; // Size property pages
BOOL CPage1::OnInitDialog ()
{
RECT rect = { 15, 60, 390, 102 }; // Dimensions of DirCtrl ctrl
strFilter = "*.*";
bEditChange = FALSE;
pDate = (CPage2*) ((CListSheet*) GetParent())->GetPage( 1 );
pSize = (CPage3*) ((CListSheet*) GetParent())->GetPage( 2 );
dirlist.Create( this, &rect, IDC_DIRCTRL, IDC_DIRPATH, DL_ALL, IDI_FLOPPY );
dirlist.SetCallBack( &CheckDateSize );
return CDialog::OnInitDialog ();
}
BOOL CPage1::OnSetActive ()
{
dirlist.ShowList( strFilter );
return CPropertyPage::OnSetActive ();
}
BEGIN_MESSAGE_MAP ( CPage1, CPropertyPage )
ON_EN_SETFOCUS ( IDC_EDIT1, OnEditGainFocus )
ON_EN_CHANGE ( IDC_EDIT1, OnEditChanging )
ON_EN_KILLFOCUS ( IDC_EDIT1, OnEditLoseFocus )
ON_BN_CLICKED ( IDC_BUTTON1, OnUp1Level )
END_MESSAGE_MAP ()
// These three functions simply ensure that when the user types in another
// filter string (such as "*.txt"), the directory listing is automatically
// updated to reflect the change.
//
void CPage1::OnEditGainFocus ()
{
GetDlgItemText( IDC_EDIT1, strOldFilter );
}
void CPage1::OnEditChanging ()
{
bEditChange = TRUE;
}
void CPage1::OnEditLoseFocus ()
{
if (bEditChange)
{
bEditChange = FALSE;
UpdateData( TRUE );
// If user enters a new filter string, update the directory list
if (strFilter != strOldFilter)
{
dirlist.ShowList( strFilter );
strOldFilter = strFilter;
}
}
}
void CPage1::OnUp1Level ()
{
CString strPath;
// If Enter pressed in edit control, refresh list
if (GetFocus() == GetDlgItem( IDC_EDIT1 ))
OnEditLoseFocus ();
// Else go up one directory level
else
{
dirlist.GetPath( strPath );
// When strPath == "d:\", we're already at root
if (strPath.Right( 2 ) != ":\\")
{
// Remove '\' at end of string
strPath.GetBufferSetLength( strPath.GetLength() - 1 );
strPath.ReleaseBuffer ();
// Find last '\' and truncate strPath string
int cLastSlash = strPath.ReverseFind( '\\' );
if (cLastSlash != -1)
{
strPath.GetBufferSetLength( cLastSlash + 1 );
strPath.ReleaseBuffer ();
dirlist.SetPath( strPath );
dirlist.ShowList( strFilter );
}
}
}
}
// Each time it finds a file that is a candidate for inclusion in the
// directory list, CDirListCtrl::FindFiles calls this static callback
//
BOOL CPage1::CheckDateSize( PWIN32_FIND_DATA pfd )
{
// Accept all subdirectories regardless of date/size criteria
if (pfd->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
return TRUE;
// If options set in Date page, filter files by date criteria
if (pDate->nAnyDate)
{
CTime timeFile( pfd->ftLastWriteTime );
if (pDate->nAnyDate == 1)
{
// Reject file not dated within specified min/max period
if (timeFile <= pDate->timeMin || timeFile > pDate->timeMax)
return FALSE;
}
else
{
CTime timeNow = CTime::GetCurrentTime();
CTimeSpan timeAge( timeNow.GetTime() - timeFile.GetTime() );
// Reject file older than specified number of months
if (pDate->nAnyDate == 2 && pDate->PrevMonths)
if (timeAge.GetDays()/30 >= pDate->PrevMonths)
return FALSE;
// Reject file older than specified number of days
if (pDate->nAnyDate == 3 && pDate->PrevDays)
if (timeAge.GetDays() >= pDate->PrevDays)
return FALSE;
}
}
// If options set in Size page, filter files by size criteria
if (pSize->nAnySize)
{
if (pSize->MinSize && pfd->nFileSizeLow < pSize->MinSize*1024)
return FALSE;
if (pSize->MaxSize && pfd->nFileSizeLow > pSize->MaxSize*1024)
return FALSE;
}
return TRUE;
}
void CPage1::DoDataExchange( CDataExchange* pDX )
{
CPropertyPage::DoDataExchange( pDX );
DDX_Text( pDX, IDC_EDIT1, strFilter );
DDV_MaxChars( pDX, strFilter, 128 );
}
///////////////////////////////////////////////////////////////////////
// CPage2 property page
BOOL CPage2::OnInitDialog ()
{
CSpinButtonCtrl* spin;
// Initialize variables
nAnyDate = 0;
PrevDays = 1;
PrevMonths = 1;
timeMin = 0;
timeMax = CTime::GetCurrentTime();
// Set limits of spin buttons
spin = (CSpinButtonCtrl *) GetDlgItem( IDC_SPIN1 );
spin->SetRange( 1, 100 ); // Within x months
spin = (CSpinButtonCtrl *) GetDlgItem( IDC_SPIN2 );
spin->SetRange( 1, 365 ); // Within x days
return CDialog::OnInitDialog ();
}
void CPage2::DoDataExchange( CDataExchange* pDX )
{
CPropertyPage::DoDataExchange( pDX );
DDX_DateTimeCtrl( pDX, IDC_DATETIME1, timeMin);
DDX_DateTimeCtrl( pDX, IDC_DATETIME2, timeMax);
DDX_Radio( pDX, IDC_RADIO1, nAnyDate );
DDX_Text( pDX, IDC_EDIT1, PrevMonths );
DDX_Text( pDX, IDC_EDIT2, PrevDays );
}
///////////////////////////////////////////////////////////////////////////////////////////////////////
// CPage3 property page
BOOL CPage3::OnInitDialog ()
{
CSpinButtonCtrl* spin;
// Initialize variables
nAnySize = 0;
MinSize = 0;
MaxSize = 100;
// Set limits of spin buttons
spin = (CSpinButtonCtrl *) GetDlgItem( IDC_SPIN1 );
spin->SetRange( 0, 9999 ); // Min size
spin = (CSpinButtonCtrl *) GetDlgItem( IDC_SPIN2 );
spin->SetRange( 1, 9999 ); // Max size
return CDialog::OnInitDialog ();
}
void CPage3::DoDataExchange( CDataExchange* pDX )
{
CPropertyPage::DoDataExchange( pDX );
DDX_Radio( pDX, IDC_RADIO1, nAnySize );