12.07.2015 Views

Lazarus - 错误提示:发生了异常

Lazarus - 错误提示:发生了异常

Lazarus - 错误提示:发生了异常

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

封 面LZF<strong>Lazarus</strong>+ZeosDBO+FireBird 开 发 者 指南孙 晓 刚编 著2012 年 8 月 第 一 版2012 年 10 月 第 四 版2013 年 4 月 第 五 版


关 于 作 者本 书 作 者 , 多 年 从 事 基 于 Pascal 系 开 发 工 具 的 软 件 开 发 工 作 , 对 C,PHP,Java等 均 有 不 同 程 度 掌 握 。 喜 欢 接 触 新 鲜 事 物 , 热 爱 软 件 开 发 工 作 。 现 就 职 于 四 川 某软 件 公 司 。 参 与 或 独 立 开 发 了 文 档 管 理 , 短 信 发 送 , 商 业 系 统 等 多 种 不 同 种 类 的软 件 系 统 , 其 中 有 Browser 模 式 , 也 有 Native 模 式 。 对 软 件 开 发 工 作 有 一 定 的 独到 见 解 和 实 际 动 手 能 力 。 业 余 时 间 喜 欢 玩 游 戏 , 陪 儿 子 玩 耍 。本 书 的 例 子 都 是 作 者 亲 自 编 写 demo 验 证 通 过 的 , 有 不 足 之 处 还 请 指 正 。您 可 以 如 下 方 式 联 系 作 者 。论 坛 :http://www.FPCcn.comID: stevenQQ: 1565498246


现 在 从 事 云 端 数 据 库 研 发 并 且 领 导 Firebird 数 据 库 的 开 发 。 因 此 , 实 际 上Firebird 数 据 库 引 擎 从 1984 年 就 开 始 商 用 , 有 大 量 用 户 使 用 过 , 经 过 多 年 名 称 变化 , 他 是 开 源 版 本 的 名 称 , 从 1.0 开 始 就 有 大 量 用 户 使 用 , 主 要 的 用 户 在 欧 美 ,俄 罗 斯 。 因 为 中 文 资 料 比 较 少 , 这 个 优 秀 的 开 发 工 具 在 国 内 许 多 人 并 不 认 识 。 现在 发 展 到 了 2.5 版 本 , 可 以 支 持 多 处 理 器 , 大 量 客 户 端 连 接 , 是 一 款 高 性 能 的 数据 库 引 擎 。 另 外 3.0 正 在 开 发 中 。 关 于 Firebird 的 TB 级 的 测 试 可 以 看 http://www.ibaid.com/articles/item104。关 于 Firebird 的 历 史 可 以 看 " 浴 火 重 生 的 Firebird",firebird.net.cn 有 此 文 , 已 经 收 录 到 附 录 , 版 权 归 原 作 者 所 有 。ZeosDBO 是 连 接 FireBird 和 <strong>Lazarus</strong> 之 间 的 桥 梁 , 是 lazarus 的 开 源 数 据 库访 问 组 件 , 非 常 优 秀 , 可 以 访 问 大 多 数 数 据 库 , 他 也 支 持 Delphi, 并 支 持 大 多 数 常见 数 据 库 。本 书 适 合 的 读 者 是 具 备 一 定 的 Pascal 语 言 基 础 ,SQL 语 言 基 础 的 程 序 员 或编 程 爱 好 者 。选 择 这 三 种 套 件 的 关 键 是 , 三 者 均 免 费 , 跨 平 台 , 统 称 为 LZF, 下 面 是 这 三种 开 发 套 件 的 优 点 列 表 。项 目 <strong>Lazarus</strong> Firebid ZeosDBO价 格 免 费 免 费 免 费使 用 协 议 GPLv2 IPL GPLv2跨 平 台 性 多 种 平 台 多 种 平 台 多 种 平 台当 前 版 本 1.0 2.5.1 7.0.0.10stable特 色 极 像 Delphi稳 定已 经 包 含 chm 帮 助轻 量 , 高 效 , 完 整特 有 MGA 多 代 体 系唯 一 单 文 件 实 现 日 志唯 一 实 现 嵌 入 式 支 持跨 库 , 跨 操 作 系统 , 跨 语 言(delphi,,lazarus,.net)触 发 器 , 存 储 过 程 的数 据 库第 三 方 支持许 多 控 件 在 转 移中Ibexpert,FlameRobin,Maestro 等 许 多 管 理 界面 , 多 种 访 问 库 。EhLib 等 多 种 库 支持 , 完 全 兼 容 原 其他 Dataset用 户 使 用情 况大 量 商 业 程 序 正在 使 用 , 有 图 有 真许 多 商 业 应 用 程 序 ,秘 密 在 使 用 。许 多 用 户 使 用 , 从比 较 老 的 版 本 开


相 。 始 。这 么 强 大 的 开 发 系 统 , 您 还 犹 豫 什 么 ? 跟 我 一 起 来 学 习 吧 。


第 〇 章 <strong>Lazarus</strong> 在 Windows 的 安 装今 天 <strong>Lazarus</strong> 1.0RC2 终 于 发 布 了 。 什 么 ? 你 不 知 道 <strong>Lazarus</strong> 是 什 么 ? 那 让 我来 给 你 讲 解 一 下 吧 。<strong>Lazarus</strong> 就 是 号 称 软 件 开 发 界 的 少 男 少 女 无 敌 杀 手 。<strong>Lazarus</strong> 是 新 一 代 软 件 开 发 环 境 , 他 有 什 么 优 秀 的 地 方 呢 :1. 采 用 所 见 所 得 的 软 件 界 面 设 计 器 。2. 事 件 驱 动 的 软 件 开 发 方 法 。3. 基 于 freepascal 这 个 非 常 成 熟 的 编 译 器 。4. 内 置 gnu debuger 这 个 强 大 的 调 试 器 。5. 完 全 支 持 对 象 Pascal 语 法 , 几 乎 全 兼 容 Delphi。6. 内 置 原 生 同 为 开 源 软 件 的 Mysql,Firebird 数 据 库 连 接 组 件 。7. 集 成 chm 格 式 帮 助 文 件 , 绝 对 划 时 代 , 日 常 开 发 最 常 用 的 功 能 , 选 中 TForm按 F1 试 试 。 不 需 要 自 己 再 手 工 将 此 插 件 集 成 。 并 且 不 再 手 动 下 载 chm( 这 是 我前 几 天 还 在 搞 的 事 )。 一 个 新 手 最 怕 什 么 ? 最 怕 没 有 资 料 , 新 手 不 用 F1, 就 像 老 鼠没 大 米 。8. IDE 插 件 , 控 件 均 编 译 安 装 , 和 linux 一 样 , 追 求 稳 定 性 , 确 实 很 稳 定 。9. 中 文 等 多 国 语 言 的 支 持 。10. 内 置 CVS, 多 人 协 作 很 方 便 ;11. FPDOC 内 置 , 从 此 编 写 文 档 不 求 人 ;12. 内 置 JEDI 代 码 格 式 化 ,Ctrl+D 搞 定 代 码 美 化 ;13. 包 安 装 更 方 便 ;14. 支 持 从 delphi 代 码 自 动 转 换 到 lazarus, 如 果 无 法 转 换 的 部 分 , 会 用 注 释 标记 出 来 。15. 还 集 成 了 许 多 专 家 工 具 , 比 如 写 注 释 , 比 较 文 件 ;16. 支 持 代 码 ,lfm 文 件 导 出 为 html, 而 且 是 语 法 高 亮 的 ;17. 许 多 地 方 支 持 过 滤 器 , 比 如 查 找 组 件 , 组 件 安 装 ;18. 支 持 属 性 编 辑 收 藏 功 能 , 从 此 设 置 属 性 , 不 需 要 大 海 捞 针 ;


19. 更 加 合 理 的 菜 单 划 分 ;20. 许 多 演 示 代 码 , 直 接 就 可 以 拿 来 用 ;21. 跨 平 台 , 支 持 Wintel 组 合 ,AMD CPU 优 化 ,IOS ,Android ,Wince,Linux,几 乎 所 有 系 统 都 支 持 。22. 如 今 的 主 流 , 将 来 的 栋 梁 ;C/S 快 速 开 发 方 面 无 软 件 能 出 Delphi 左 右 ,而 如 今 要 变 成 在 多 平 台 RAD 方 面 , 无 软 件 能 出 <strong>Lazarus</strong> 左 右 ; 必 将 对 Linux 桌面 版 ,Android,WinCE 系 等 的 应 用 普 及 有 着 深 远 的 影 响 。下 面 我 们 来 看 lazarus 是 如 何 安 装 的 。首 先 当 然 你 必 须 要 有 一 台 电 脑 , 什 么 ? 你 想 往 您 的 平 板 电 脑 安 装 , 还 是 请 您打 住 吧 。然 后 您 需 要 下 载 <strong>Lazarus</strong> 1.0RC2 , 就 下 载 Windwos 32 位 版 。之 后 需 要 执 行 这 个 下 载 下 来 的 安 装 包 , 迎 来 第 一 个 画 面 :我 们 可 以 看 到 <strong>Lazarus</strong> 是 基 于 Free Pascal 这 个 项 目 的 ,IDE 本 身 是 用 非 IDE编 辑 器 ,Object Pascal 语 法 ,GNU Free pascal 编 译 器 编 译 的 。单 击 下 一 步 , 显 示 :


这 里 设 置 安 装 的 目 录 , 我 们 一 般 不 安 装 到 C, 因 为 为 了 防 止 系 统 被 重 安 装 ,掉 了 我 们 的 安 装 。我 们 安 装 在 D:lazarus102rc 或 者 d:\lazarus1, 名 字 随 便 你 的 喜 好 。关 键 是 这 个 磁 盘 空 间 怎 么 也 要 留 个 1GB 可 用 空 间 吧 , 虽 然 显 示 的 是 需 要723.8MB, 但 是 难 免 要 重 新 编 译 , 安 装 新 控 件 等 等 , 需 要 更 多 剩 余 可 用 空 间 。然 后 我 们 下 一 步 ,


这 里 的 意 思 是 你 的 电 脑 有 老 版 本 , 是 否 卸 载 , 提 示 注 意 ,lazarus 不 支 持 多 版本 共 存 。 由 于 我 自 己 做 了 多 版 本 共 存 的 工 作 , 所 以 不 理 他 , 直 接 Next,然 后 这 里 显 示 的 是 三 大 内 容 ,1.<strong>Lazarus</strong> 支 持 QT 类 库 开 发 ;2. 如 其 他 任 何 开发 工 具 ,<strong>Lazarus</strong> 1.0RC2 终 于 集 成 了 chm 离 线 帮 助 。 也 就 是 说 你 没 有 网 络 的 情


况 下 编 程 查 资 料 , 也 行 了 , 而 且 这 些 资 料 的 质 量 也 很 不 错 ;3. 在 注 册 表 里 面 添 加 扩展 名 相 关 的 信 息 ;这 个 的 意 思 是 lazarus 在 开 始 菜 单 里 面 的 文 件 夹 , 就 是 大 分 类 菜 单 啦 。直 接 Next 到 下 一 步 。


Next,这 个 意 思 创 建 桌 面 图 标 和 , 删 除 上 一 个 版 本 的 用 户 配 置 文 件 , 不 管 , 直 接这 个 的 意 思 是 准 备 好 了 , 就 直 接 安 装 , 直 接 install,一 会 儿 就 完 成 了 ,


然 后 我 们 将 其 中 lazarus.exe运 行 , 并 在 新 的 Form 的 代 码 编 辑 框 里 面 选 中Tform , 按 F1 功 能 键 , 帮 助 就 出 现 了 。然 后 , 我 们 讲 一 下 <strong>Lazarus</strong> 多 版 本 共 存 是 怎 么 回 事 。由 于 <strong>Lazarus</strong> 没 有 考 虑 在 一 个 电 脑 安 装 多 个 不 同 版 本 。 所 以 其 注 册 表 信 息 等可 能 导 致 冲 突 。 解 决 方 法 有 几 个 :


安 装 CodeTyphon, 这 个 套 件 集 成 了 各 个 版 本 , 并 且 互 不 冲 突 ;用 某 些 人 写 的 小 工 具 ;监 视 注 册 表 , 并 且 每 安 装 一 个 , 导 出 其 注 册 信 息 , 然 后 把 C:\Documents andSettings\Administrator\Local Settings\Application Data\lazarus 这 个 配 置 文 件 目 录 复制 到 安 装 目 录 , 假 如 你 的 登 录 用 户 名 不 同 比 如 jack, 换 前 面 相 应 的 地 方 , 比 如C:\Documents and Settings\jack\Local Settings\Application Data\lazarus。最 后 , 用 批 处 理 执 行 每 个 版 本 , 先 自 动 导 入 注 册 表 信 息 , 然 后 用 参 数 指 定 IDE的 主 参 数 放 在 哪 里 , 就 像 下 面 这 样 :reg import lazarus102rc.reg..\lazarus.exe --primary-config-path=.\config好 了 , 我 们 来 看 软 件 的 定 义 :软 件 == 程 序 + 文 档现 在 两 者 都 有 了 , 您 还 等 什 么 呢 ?勒 吃 够 !!! 够 ! 够 ! 够 !


第 一 章 Hello,World.<strong>Lazarus</strong> 从 2010 年 左 右 进 入 一 个 高 速 发 展 期 , 以 前 使 用 总 是 局 限 于 硬 件 速 度 ,随 着 现 在 硬 件 速 度 的 提 升 , 他 自 身 的 代 码 优 化 , 技 术 的 进 步 , 终 于 发 展 到 一 个 稳定 版 本 , 一 般 来 说 , 开 源 软 件 的 1.0 往 往 已 经 非 常 成 熟 。 网 络 上 有 大 量 用 户 讨 论使 用 心 得 , 并 且 互 相 交 换 技 术 文 档 。我 们 知 道 当 前 最 流 行 的 几 大 开 发 技 术 有 :1.PHP 胜 在 简 单 , 使 用 者 众 多 , 资 料 丰 富 ;2.JAVA 胜 在 跨 平 台 , 能 完 成 前 端 , 后 端 功 能 ;3.Flex, 胜 在 代 码 简 洁 , 可 实 现 丰 富 的 RIA;4.iOS,Android 开 发 , 移 动 用 户 群 的 庞 大 ;5.Delphi, 最 快 的 RAD, 最 优 美 的 语 法 , 数 据 结 构 , 算 法 的 基 础 语 言 ;6.Mysql 胜 在 对 php 的 结 合 , 以 及 社 区 开 发 的 多 种 特 性 ;我 们 再 来 看 他 们 的 缺 点 :1.PHP 不 容 易 实 现 客 户 端 应 用 , 客 户 端 应 用 永 远 有 大 需 求 ;2.JAVA 太 跨 平 台 , 比 本 地 化 Native 代 码 速 度 慢 , 无 法 实 现 小 应 用 ;3.Flex 已 经 放 弃 linux 平 台 , 跨 平 台 特 性 正 在 丧 失 ;4.iOS 不 允 许 非 ObjectC 应 用 ,Android 依 靠 java, 高 性 能 应 用 要 用 JNI;5.Delphi, 只 支 持 Windows 平 台 , 现 在 添 加 了 iOS, 可 是 还 不 成 熟 ;6.Mysql 的 缺 点 也 很 明 显 , 内 部 引 擎 太 多 , 特 别 是 isam 引 擎 的 多 文 件 , 特 别容 易 损 坏 。各 种 开 发 工 具 和 语 言 都 有 其 侧 重 点 , 说 不 上 谁 最 好 , 我 们 开 发 的 时 候 ,要 根 据 项 目 的 特 点 , 选 择 相 应 的 语 言 和 开 发 工 具 。项 目 特 点 项 目 大 小 语 言 和 工 具轻 量 级 Web 型 大 、 中 、 小 PHP+Mysql,asp大 中 型 WEB 大 、 中 Php,c#,Java嵌 入 式 中 , 小 Java,C富 媒 体 , 页 游 中 , 小 Flex,HTML5


苹 果 系 列 中 , 小 objectcAndroid 系 列 中 , 小 Java底 层 , 高 性 能 大 , 中 , 小 C,C++,Pascal客 户 端 快 速 应 用 大 , 中 , 小 Delphi,<strong>Lazarus</strong>高 性 能 数 据 库 大 , 中 Oracle,DB2易 用 数 据 库 中 , 小 Mssql免 费 , 易 用 数 据 库 中 , 小 Firebird,mysql,postgresql计 算 机 编 程 语 言 发 展 历 史起 源 于 BCPL语 言 , 然 后 是 B语 言开 关 编 程汇 编 语 言分 化起 源 于 算 法 语 言中 级 语 言 C 语 言 代 表特 点 : 接 近 硬 件 , 符 号 化1972 年 推 出高 级 语 言 Pascal 代 表特 点 : 接 近 自 然 语 言1970 年 推 出同 一 个 系 列 的 语 言 , 面 向 对 象Java,Php,C++,C#特 点 : 框 架 , 封 装 , 库后 继 同 一 系 列 语 言 , 面 向 对 象 :<strong>Lazarus</strong>,Delphi,VP特 点 : 框 架 , 封 装 , 库现 在 这 几 类 语 言 都 并 行 存 在 。而 且 编 程 语 言 呈 现 出 : 编 译 型 语 言 脚 本 化 ( 各 种 脚 本 引 擎 比 如 Remobject), 脚本 语 言 编 译 化 (JIT 技 术 ), 专 业 化 (Lisp,Lua), 跨 平 台 性 (Pascal,Java), 跨 编 程 语 言(.Net), 弱 类 型 化 ( 脚 本 引 擎 ), 异 构 平 台 (Java For Android,JavaME), 并 行 化 (Erlang),非 结 构 化 ( 面 向 对 象 等 ) 的 特 点 。而 相 应 的 软 件 开 发 方 法 也 呈 现 出 : 企 业 化 , 专 业 中 间 件 , 专 业 开 发 平 台 的 特点 。现 在 软 件 开 发 领 域 存 在 几 种 跨 平 台 库 , 特 别 是 对 界 面 跨 平 台 开 发 的 有 :IUP --Portable User Interface 基 于 C 语 言 , 只 支 持 界 面 跨 平 台 , 少 量 其 他 库 ,


数 据 库 访 问 库 缺 乏 , 需 要 C 语 言 ADO 库 , Boost 等 库 配 合 ;WxWideget -- 基 于 C 语 言 , 只 支 持 界 面 跨 平 台 , 少 量 其 他 库 , 数 据 库 访 问 库缺 乏 , 自 带 的 数 据 库 访 问 接 口 不 完 善 。Qt -- 最 成 熟 的 跨 平 台 库 , 商 业 库 转 到 LGPL 的 , 采 用 回 调 函 数 机 制 进 行 事 件分 发 ,<strong>Lazarus</strong>支 持 了 一 部 分 , 特 别 是 界 面 部 分 , 需 要 带 运 行 库 。LCL-- 跨 多 种 平 台 , Windows CE ,Linux ,Windows , 除 了 界 面 外 还 有 许 多 其 他库FireMonkey -- Delphi XE 系 列 提 供 的 商 业 开 发 库我 们 可 以 看 到 后 两 种 都 是 支 持 WYSWYG 的 所 见 所 得 的 , 相 对 来 说 学 习 起 来比 较 容 易 。 也 更 加 全 面 。Gtk-- 主 要 还 是 界 面 库 , 依 赖 包 比 较 多 。比 较 了 这 些 , 那 么 lazarus 使 用 在 什 么 领 域 ?1. 除 B/S 模 式 ( 可 以 写 插 件 ),RAD, 多 媒 体 , 文 字 处 理 , 游 戏 等 各 个 领 域 ;2. 打 算 编 写 跨 平 台 应 用 ,windows,linux,iOS,WinCE, 单 片 机 都 可 以 用 lazaru......... 不 再 一 一 列 举 。哪 里 下 载 ?<strong>Lazarus</strong> 可 以 在 http://lazarus.freepascal.orgZeosLib 可 以 在 http://www.zeoslib.sourceforge.netFireBird 可 以 在 http://www.firebirdsql.net我 们 下 载 <strong>Lazarus</strong> 1.0 ,FireBird 2.5.1 分 别 安 装 ,( 安 装 方 法 就 略 过 ), 我 们 后 面来 说 zeoslib 的 安 装 .安 装 完 毕 后 打 开 <strong>Lazarus</strong>, 会 自 动 新 建 一 个 工 程 , 我 们 拖 动 standard 组 件 面板 上 的 Tlabel 组 件 , 放 在 form1 上 , 并 将 其 caption 设 置 为 Hello,world. 然 后 按键 盘 上 F9, 就 可 以 看 到 我 们 的 成 果 。


我 们 可 以 看 到 , 开 发 环 境 布 置 非 常 合 理 , 是 不 是 觉 得 眼 熟 呢 ?那 么 我 们 下 一 章 来 学 习 FireBird 数 据 库 的 基 本 操 作 吧 。


第 二 章 Hello,Firebird.首 先 我 们 需 要 创 建 一 个 数 据 库 , 假 设 我 们 的 数 据 库 引 擎 FireBird 安 装 为 默 认的 。 我 们 来 用 IBexpert 连 接 数 据 库 . 首 先 运 行 IBexpert, 选 择 菜 单 Database->CreateDatabase, 在 出 现 的 窗 口 填ServerRemoteServer Name 127.0.0.1protocolDatabaseUser Nametcp/ipd:\demo.fdbsysdbaPassword masterkey ( 这 是 初 始 密 码 , 以 后 可 以 修 改 )如 图然 后 点 击 OK.然 后 将 其 注 册 到 Ibexpert 里 面 进 行 管 理 。 如 图


然 后 我 们 在 主 界 面 选 择 菜 单 ,Database -> New Table , 在 上 面 表 名 栏 输 入tabel1, 然 后 在 下 面 添 加 2 个 字 段 . 如 图然 后 我 们关 闭 这 个 表 。 自 动 就 会 提 示 是 否 保 存 , 我 们 点 击 commit 提 交 到 数 据 库 。


然 后 我 们 回 到 <strong>Lazarus</strong> 去 。 我 们 来 创 建 一 个 新 的 <strong>Lazarus</strong> 工 程 来 保 存 我 们 的新 程 序 。选 择 菜 单 Project-> New Project , 我 们 看 到 在 弹 出 的 窗 口 上 有 多 个 我 们 可 以创 建 lazarus 应 用 ,FreePascal 应 用 , 单 独 的 LPR 主 程 序 ( 比 如 写 DLL) , 甚 至Apache 等 插 件 也 会 出 现 在 这 里 ( 根 据 你 安 装 的 第 三 方 组 件 ). 我 们 选 择 默 认 的Application , 然 后 点 击 OK. 一 个 新 的 应 用 模 板 出 现 了 , 我 们 将 他 保 存 。我 们 随 便 加 点 数 据 。我 们 在 保 存 位 置 看 一 下发 现 有 多 个 文 件 , 分 别 什 么 意 思 呢 ?


LPRLPILPS-- lazarus 的 主 程 序-- XML 格 式 编 译 配 置 等 信 息-- XML 维 持 单 元 名 称 等 信 息RES -- 资 源 文 件LFM -- Form 格 式 和 delphi DFM 一 样PAS -- Pascal 单 元 文 件然 后 我 们 在 新 form 放 几 个 控 件一 个 TIBConnection名 字 IBConnection1属 性DatabaseNameD:\DEMO.FDBHostName 127.0.0.1PasswordUserNamemasterkeysysdba然 后 令 connected 为 true放 一 个 TSQLTransaction, 使 其 active 为 true一 个 dataset , 类 是 TSQLQuery 名 字 SQLQuery1属 性DatabaseTransactionSqlActiveIBConnection1SQLTransaction1select * from table1true一 个 datasource 控 件 , 名 字 默 认 datasource1Datasetsqlquery1再 添 加 datagrid , 属 性 datasource 为 datasource1一 个 按 钮 , 双 击 按 钮 , 代 码 是sqlquery1.Active:=true;


然 后 我 们 等 什 么 ? F9 啊 。现 在 你 已 经 会 用 <strong>Lazarus</strong> 编 写 一 个 最 简 单 的 Firebird 数 据 库 程 序 了 。但 是 , 我 们 难 免 会 用 到 多 个 数 据 库 , 比 如 跨 库 操 作 , 有 过 ADO 编 程 的 同 学也 许 有 体 会 , 当 我 们 用 不 同 数 据 库 连 接 组 件 , 多 少 会 有 不 同 之 处 , 特 别 是 要 移 植一 个 程 序 到 另 外 一 个 数 据 库 , 将 会 十 分 困 难 。 有 没 有 一 个 组 件 可 以 兼 容 所 有 数 据库 , 改 一 下 属 性 就 转 换 数 据 库 了 呢 ? 有 ,ZeosLib 就 是 这 样 一 个 组 件 , 将 来 你 的 软件 要 升 级 为 网 络 版 , 或 改 数 据 库 引 擎 , 只 需 要 修 改 几 个 属 性 。下 一 章 我 们 就 来 见 识 一 下 这 个 控 件 的 魅 力 。


第 三 章 Hello,ZEOSDBO首 先 我 们 需 要 安 装 ZEOSDBO, 我 们 选 择 稳 定 版 (Stable) 7.0.0.10 解 压 缩 放 在某 个 位 置 , 比 如 lazarus 安 装 目 录 的 components 下 面 , 在 lazarus 版 本 , 这 个 控 件不 需 要 安 装 其 他 lpk, 只 安 装 其 中 一 个 zcomponent.lpk 就 可 以 了 。我 们 在 lazarus 菜 单 选 择 package->open package file(*.lpk) , 然 后 找 到 我 们 的zcomponent.lpk , 注 意 ,lazarus 的 控 件 安 装 最 好 一 个 一 个 的 安 装 , 如 果 安 装 失 败 ,我 们 还 可 以 回 到 老 版 本 , 默 认 自 动 重 新 编 译 IDE 时 , 会 保 留 一 个 老 版 本lazarus.old.exe。 而 lazarus 的 控 件 安 装 也 非 常 简 单 , 不 需 要 设 置 各 种 路 径 , 就 在打 开 的 窗 口 , 点 击 编 译 (compile), 然 后 选 择 user>> 这 个 按 钮 , 下 面 菜 单 ,install ,会 提 示 我 们 是 否 重 新 编 译 IDE, 一 路 选 择 yes, 编 译 完 毕 ,IDE 会 自 动 重 新 启 动 , 我们 就 可 以 在 组 件 面 板 看 见 Zeos 组 件 。 如 图注 意 有 的 组 件 可 能 需 要 修 改 一 下 源 码 , 对 于 老 程 序 员 来 说 不 是 问 题 , 这 个 组件 就 需 要 修 改 , 修 改 一 点 点 。 否 则 调 用 存 储 过 程 会 出 错 。 修 改 zstoredprocedure.pasTZAbstractCallableStatement(CallableStatement).RegisterParamType( I+1,ord(Params[I].ParamType) );修 改 为//TZAbstractCallableStatement(CallableStatement)CallableStatement.RegisterParamType( I+1, //ord(Params[I].ParamType) );Ord(ConvertDatasetToDbcType(Params[I].DataType)));// 不 直 接 取 paramType,而 是 按 老 的 6.6.6 的 方 式 , 或 者 像 上 面 一 行 这 样 转 换 , 红 色 部 分 是 错 误 的好 了 , 控 件 安 装 完 毕 。 我 们 就 开 始 我 们 的 新 探 索 吧 。首 先 我 们 新 建 一 个 工 程 ,demo3.拖 一 个 控 件 tzconnection , 名 zconnection1, 属 性 设 置 为 :Databased:\demo.fdbHostname 127.0.0.1


PasswordUsernameProtocolmasterkeysysdbafirebird-2.0Port 3050TransactiontiReadCommitted如 图 , 你 可 以 看 到 许 多 数 据 库 都 支 持 , 而 且 里 面 代 码 确 实 写 得 很 漂 亮 , 底 层全 部 使 用 接 口 , 实 现 对 多 种 数 据 库 的 支 持 , 真 正 写 得 好 , 如 果 要 好 好 掌 握 这 门 语言 的 精 髓 , 可 以 看 LCL 的 代 码 , 里 面 很 多 地 方 用 包 含 文 件 , 实 现 不 同 平 台 的 支持 , 还 有 大 量 设 计 模 式 (Design Pattern) 的 应 用 , 而 ZeosDBO 是 另 外 一 个 极 品 ,


是 接 口 (Interface) 的 最 典 型 应 用 , 我 们 可 以 学 习 研 究 他 。提 示 没 有 dll. 我 们 将 firebird 数 据 库 连 接 dll ,fbclient.dll 放 在 应 用 一 起 。一 个 TZquery , 名 称 zquery1 属 性ConnectionSqlconnection1select * from table1一 个 datasource , 名 datasource1 属 性DatasetZQuery1一 个 Dbgrid , 属 性Datasourcedatasourc1一 个 Button , 代 码zquery1.Active := true;然 后 F9 吧我 们 可 以 看 到控 制 。我 们 可 以 看 到 , 没 有 事 务 控 制 控 件 ,ZEOSDBO 会 自 动 为 其 创 建 默 认 的 事 务


本 章 你 已 经 学 会 使 用 ZeosDBO 连 接 数 据 库 ,zeosDBO 还 有 一 个 别 名ZeosLIB。 下 一 章 我 们 来 看 zeosDBO 如 何 实 现 交 叉 表 。


第 四 章 交 叉 表有 时 我 们 需 要 将 数 据 行 列 互 换 , 这 就 是 所 谓 中 国 式 报 表 , 可 是 不 在 报 表 里 面 ,我 们 当 如 何 实 现 ? 我 们 知 道 在 mssql 可 以 用 exec 执 行 动 态 sql 语 句 , 而 firebird下 也 能 实 现 , 我 们 暂 且 不 讨 论 这 种 实 现 , 我 们 讨 论 用 lazarus 自 身 实 现 , 更 利 于学 习 些 东 西 , 并 且 不 同 数 据 库 其 实 都 可 以 使 用 此 算 法 。 比 如 下 表 :studentScoreId name subject score---------------------------------1 张 三 语 文 782 张 三 数 学 803 李 四 语 文 824 李 四 数 学 88----------------------------------转 换 成 这 种 表 格------------------------------姓 名 语 文 数 学张 三 78 80李 四 82 88-------------------------------将 一 维 的 数 据 转 换 成 了 二 维 逻 辑 数 据 。此 函 数 参 数 1 源 数 据 , 参 数 2 目 标 数 据 集 参 数 3 动 态 列 字 段 参 数 4 行 字段 参 数 5 数 据 单 元 字 段function CreateCrossTable(SourceDataset:TDataset;ResultDataset:TMemDataset;TitleField, RowField, DataField: string): tdataset;vartmpDataset: Tdataset;


tempStrings: TStrings;rowval, colval, dataval: string;i, j: integer;found:boolean;beginResult := nil;if (TitleField = '') or (RowField = '') or (DataField = '') thenraise Exception.Create('All Field not be NULL!') //3 个 参 数 都 必 须 正 确elsebeginif (TitleField = RowField) or (TitleField = DataField) or(RowField = DataField) thenraise Exception.Create('All Field not be Equals!') // 动 态 列 字 段 不 能 ?? 行 字 段 ,数 据 字 段 相 同else if (SourceDataset.FieldByName(TitleField).DataType = ftString) or(SourceDataset.FieldByName(TitleField).DataType ftWideString) or(SourceDataset.FieldByName(TitleField).DataType ftFixedChar) or(SourceDataset.FieldByName(TitleField).DataType ftMemo) or(SourceDataset.FieldByName(TitleField).DataType ftFmtMemo) then// 复 合 上 面 2 个 条 件 后 , 条 ??, 动 态 列 字 段 必 须 ?? 字 符 串 类 ??begintrytempStrings := TStringList.Create;// 复 制 数 据 ??tmpDataset := SourceDataset;// 用 这 个 临 时 数 据 集 / 引 用 指 针 ? 复 制 结 构 , 免 得 改 变 源 数 据 集 的 bookmark??tmpDataset.First;for i := 0 to tmpDataset.RecordCount - 1 dobegin


动 态 列 值 不 能 是 空 , 不 能 是 NULL??if (varisnull(SourceDataset.FieldValues[TitleField]) = False) and(SourceDataset.FieldValues[TitleField] '') thenif tempStrings.IndexOf(SourceDataset.FieldValues[TitleField]) = -1 then// 查 找 不 重 复 的 字 段 名 表begintempStrings.Add(SourceDataset.FieldValues[TitleField]);// 还 没 有 这 些 字 段 在 不 重 复 的 字 段 名 表 , 就 添 加end;tmpDataset.Next;end;// 生 成 动 态 列 标 题 =================================//ResultDataset := TMemDataset.Create(nil);ResultDataset.FieldDefs.Add(RowField, ftstring, 50, False); // 添 加 一 个 行 字 段for i := 0 to tempStrings.Count - 1 dobeginwith ResultDataset.FieldDefs dobeginAdd(tempStrings.Strings[i], ftInteger, 0, False); // 交 叉 ?? 动 态 列 字 段end;end;// 合 计 字 段//ResultDataset.FieldDefs.Add('SumField', ftInteger, 0, False);//ResultDataset.Open;// 复 制 ===============================================ResultDataset.CreateTable;// .CreateDataSet;ResultDataset.Open;// 填 数 据 到 返 回 数 据 ??=================tmpDataset.First;for i := 0 to tmpDataset.RecordCount - 1 do


eginrowval := SourceDataset.FieldByName(RowField).AsString; // 行 字 段 ??colval := SourceDataset.FieldByName(TitleField).AsString; // 列 字 段 ??dataval := SourceDataset.FieldByName(datafield).AsString; // 单 元 ??if dataval = '' thendataval := '0'; // 空 值 处 ??// 根 据 行 字 ?? 定 位 比 如 张 三//if ResultDataset.Locate(RowField, rowval, [loPartialKey]) then//locate 有 bug?// 用 此 替 代 代 码ResultDataset.First;found := false;while not resultdataset.EOF dobeginif resultdataset.fieldbyname(rowfield).AsString = rowval thenbeginfound := true;break;end;resultdataset.next;end;if found then//if ResultDataset.Locate(RowField, rowval, [loPartialKey]) thenbegin// 已 经 有 此 行 , 就 编 ??ResultDataset.Edit;// 根 据 动 态 列 名 , 填 写 单 元 格 ??ResultDataset.FieldByName(colval).AsString := dataval;// 合 计 ??//ResultDataset.FieldByName('SumField').AsInteger :=


ResultDataset.FieldByName('SumField').AsInteger + StrToInt(dataval);ResultDataset.Post; // 保 存 到 内 存 数 据 集endelsebegin// 还 没 有 这 ??ResultDataset.Append;// 添 加// 填 写 行 的 ??ResultDataset.FieldByName(RowField).AsString := rowval;// 再 填 写 动 态 列 的 ??for j := 1 to ResultDataset.Fields.Count - 1 doResultDataset.Fields[j].AsCurrency := 0;ResultDataset.FieldByName(colval).AsString := dataval;// 新 行 不 用 合 计//ResultDataset.FieldByName('SumField').AsString := dataval;ResultDataset.Post; // 保 存end;tmpDataset.Next;end;//Result := ResultDataset;// 生 成 交 叉 表 数 据 集tempStrings.Free;exceptend;endelseraise Exception.Create('TitleField Must be of Type String!');end;end;


我 们 可 以 看 到 , 其 实 交 叉 报 表 实 现 方 法 也 是 类 似 的 , 只 是 比 较 通 用 一 些 。<strong>Lazarus</strong> 难 免 还 有 一 些 bug, 或 者 我 们 理 解 不 同 的 地 方 , 我 们 可 以 硬 写 代 码 避 免 。如 上 面 locate 无 法 实 现 , 我 们 自 己 写 代 码 也 就 几 句 。当 我 们 使 用 别 人 的 代 码 的 时 候 , 发 现 有 问 题 , 我 们 可 以 静 下 来 自 己 解 决 , 而不 是 喷 , 喷 没 有 什 么 用 , 有 许 多 用 户 正 是 在 使 用 的 时 候 提 交 了 bug 给 lazarus 组织 , 才 使 得 lazarus 发 展 得 越 来 越 好 。当 我 们 编 写 数 据 库 程 序 的 时 候 , 尽 量 使 用 与 数 据 库 扩 展 特 性 无 关 的 写 法 , 这样 在 数 据 库 移 植 的 时 候 , 可 以 很 快 完 成 。下 一 章 , 我 们 来 学 习 基 本 的 CRUD 吧 。


第 五 章 CRUD什 么 是 CRUD? 就 是 Create + Read + Update +Delete 。 是 某 语 言 创 造 的 大量 术 语 的 一 个 , 其 实 <strong>Lazarus</strong> 做 这 些 简 直 是 小 Case。对 于 某 些 语 言 , 他 们 提 出 CRUD 这 个 概 念 , 为 什 么 呢 ? 这 些 语 言 一 般 是 没有 指 针 , 表 达 复 杂 数 据 能 力 不 足 , 所 以 提 出 分 层 概 念 , 我 们 来 看 看 这 些 概 念 :VO---- Value Object 负 责 保 存 数 据 的 对 象 。 相 当 于 lazarus 的 Type Record写 代 码MVC ---- Modal View Control 其 实 相 当 于 Dataset + Form + Control + 自DAO--- Data Access Object 相 当 于 Dataset + connection, 或 者ZEOSDBO 等 ;那 些 概 念 的 提 出 , 是 因 为 :1. 将 程 序 编 写 划 分 更 细 , 维 护 更 方 便 ;2. 语 言 特 性 难 于 实 现 一 些 复 杂 数 据 , 比 如 内 存 表 ;3. 实 现 数 据 库 无 关 性 , 实 现 快 速 移 植 , 而 ZEOSDBO 就 相 当 于 DAO 层 ;而 lazarus 这 样 的 开 发 方 式 可 以 实 现 这 些 概 念 , 但 没 有 多 少 必 要 。 首 先 是 因为 LCL,FCL 这 样 的 库 已 经 非 常 优 秀 , 而 且 如 dataset,memdataset 这 样 的 数 据 结 构已 经 能 够 表 达 足 够 强 大 的 功 能 。 所 以 我 们 还 是 坚 持 原 生 的 开 发 方 法 。 当 然 以 后 也可 以 研 究 一 下 那 些 分 层 方 法 , 可 以 参 考 Jazz ,EMvc 等 代 码 。 不 过 那 些 东 西 作 为研 究 还 行 , 实 际 用 , 相 当 于 脱 了 裤 子 放 屁 。 因 为 <strong>Lazarus</strong> 本 身 设 计 为 快 速 开 发 工具 , 所 见 所 得 是 最 大 的 卖 点 , 如 果 你 非 要 那 么 做 , 就 好 比 买 个 大 厦 只 住 一 间 , 浪费 大 量 的 资 源 。我 们 来 看 一 下 CRUD 的 具 体 操 作 吧 。我 们 新 建 一 个 工 程 demo5, 四 个 按 钮 , 代 码 如 下 :procedure TForm1.Button1Click(Sender: TObject);beginzquery1.close;zquery1.sql.text := 'select * from table1';


zquery1.open;end;procedure TForm1.Button2Click(Sender: TObject);beginzquery1.close;zquery1.sql.text := 'insert into table1(id,cname)values(99,' +quotedstr(utf8toansi(' 你 好 ')) + ')';zquery1.execsql;end;procedure TForm1.Button3Click(Sender: TObject);beginzquery1.close;zquery1.sql.text := 'update table1 set cname=''hello,it is me '' where id=1';zquery1.execsql;end;procedure TForm1.Button4Click(Sender: TObject);beginzquery1.close;zquery1.sql.text := 'delete from table1 where id=99';zquery1.open;end;


我 们 可 以 发 现 Datagrid 里 面 有 乱 码 , 并 且 插 入 数 据 的 地 方 还 使 用 了 数 据 转换 utf8toansi 函 数 。我 们 下 一 章 来 处 理 这 个 问 题 。


第 六 章 乱 码 问 题乱 码 问 题 一 直 困 扰 许 多 同 学 , 毕 竟 此 软 件 是 基 于 英 语 内 核 , 和 其 他 软 件 一 样会 遇 到 国 际 化 , 本 地 化 问 题 。新 建 一 个 数 据 库 , 选 择 字 符 编 码 为 UTF-8, 然 后 我 们 把 第 5 章 的 代 码 中 插 入语 句 的 值 不 要 转 化 编 码 , 因 为 lazarus 的 编 辑 控 件 是 synEdit, 输 入 的 信 息 就 是 utf-8编 码 。 然 后 我 们 运 行 新 的 demo, 看 效 果 如 下 图 。<strong>Lazarus</strong> 控 件 大 多 兼 容 UTF-8, 所 以 我 们 只 需 要 注 意 数 据 存 取 , 其 他 计 算 的时 候 都 需 要 注 意 。


第 七 章 POS-- 卖 场 终 端 系 统 的 demo对 于 商 场 终 端 系 统 , 涉 及 到 销 售 , 打 印 , 钱 箱 等 控 制 , 我 们 这 个 demo 暂 时只 涉 及 打 印 小 票 和 销 售 。 销 售 终 端 处 一 般 不 好 操 作 鼠 标 , 所 以 我 们 将 起 作 为 一 个单 独 的 模 态 窗 口 。 并 且 只 给 一 个 输 入 控 件 , 操 作 完 全 是 使 用 键 盘 。我 们 将 需 要 一 个 商 品 资 料 表 goods, 一 个 销 售 流 水 表 sales。字 段 类 型 说 明IdIntegerBarcode Varchar(20) 条 码Sale_price Numeric(19,2) 售 价Goods_name Varcha(50) 品 名Vip_price Numeric(19,2) 会 员 价 格有 两 个 地 方 可 以 实 现 输 入 的 字 符 拦 截 ,1 个 是 edit 的 onkeyup, 一 个 是 form的 onkeyup, 据 此 可 以 将 其 中 字 符 作 为 快 捷 键 。实 际 信 息 可 以 从 edit1.text 取 。然 后 我 们 将 在 用 户 按 下 回 车 , 自 动 添 加 一 条 数 量 为 1 的 销 售 记 录 。用 户 输 入 数 字 然 后 按 数 量 键 q, 实 现 最 后 一 条 销 售 数 量 的 变 化 。用 户 输 入 数 字 然 后 按 单 价 快 捷 键 d, 实 现 销 售 单 价 的 变 化 。用 户 输 入 f 或 者 输 入 数 字 再 按 f 实 现 付 款 。我 们 只 演 示 这 么 多 , 真 实 的 系 统 还 需 要 考 虑 断 网 , 数 据 保 存 本 地 , 发 送 到 服务 器 等 各 种 情 况 的 处 理 。我 们 看 到 , 使 用 了 vk_Q 这 样 的 宏 定 义 , 必 须 在 uses 里 面 引 用 lcltype.pp 这个 单 元 文 件 。Stringgrid 包 括 了 一 个 属 性 , 就 是 columns, 定 义 了 各 个 列 的 标 题 。 并 且 可 以设 置 各 个 列 的 图 标 。我 们 看 看 我 们 的 成 果 。


本 章 我 们 学 习 了 lazarus 下 的 增 强 型 的 stringgrid 使 用 , 以 及 onkeyup 事 件 的处 理 程 序 。 下 一 章 我 们 来 看 日 常 生 活 中 的 单 据 的 处 理 方 式 。


第 八 章 主 细 表我 们 来 编 写 一 个 出 库 处 理 程 序 。首 先 , 我 们 建 一 个 数 据 库 demo-stock.fdb 。 包 含 3 张 表 goods , sales ,sales_item, 结 构 如 下 。goods字 段 类 型 说 明IdIntegerBarcode Varchar(20) 条 码Sale_price Numeric(19,2) 售 价Goods_name Varcha(50) 品 名Vip_price Numeric(19,2) 会 员 价 格sales字 段 类 型 说 明IdIntegerBill_no Varchar(20) 销 售 单 号Sale_date date 销 售 日 期remark Varcha(50) 备 注stat Int 是 否 生 效Sales_item字 段 类 型 说 明IdIntegerSales_id Integer 前 面 单 头 idGoods_id Integer 商 品 的 idReal_price Numeric(19,2) 实 际 价 格qty Numeric(19,2) 数 量我 们 可 以 看 出 , 对 于 明 细 表 来 说 , 和 商 品 表 是 一 对 多 的 关 系 。在 firebird 里 面 , 如 果 存 在 多 重 级 联 的 master -> detail 关 系 的 dataset, 可 以 采


用 主 表 使 用 自 动 编 号 字 段 , 细 表 采 用 非 自 动 编 号 , 那 么 有 的 同 学 可 能 会 问 , 如 果你 的 主 表 id 自 动 编 号 了 , 在 你 的 细 表 的 表 里 面 作 为 关 联 id, 细 表 如 何 自 动 获 取 ? 没错 , 这 就 是 我 们 要 讲 的 内 容 。首 先 是 确 保 明 细 表 可 以 得 到 主 表 自 动 产 生 的 ID, 那 么 我 们 只 需 要 在 明 细 表 获得 焦 点 的 时 候 保 存 主 表 数 据 。有 的 同 学 会 问 : 这 样 不 能 保 证 事 务 完 整 性 啊 , 主 表 保 存 了 , 从 表 用 户 不 填 不是 会 导 致 许 多 垃 圾 ? 请 问 , 如 果 用 户 保 存 一 个 空 的 主 表 , 我 们 能 完 全 控 制 他 吗 ?诚 然 , 我 们 可 以 通 过 缓 存 保 存 用 户 数 据 , 再 批 量 提 交 主 表 和 从 表 所 有 数 据 ( 比 如用 临 时 表 和 内 存 表 ), 将 其 包 裹 在 事 务 里 面 。 事 务 是 完 整 了 , 可 是 , 我 们 的 额 外工 作 也 太 多 了 。我 们 完 全 可 以 通 过 主 表 的 状 态 字 段 stat 控 制 本 张 表 单 是 否 生 效 , 一 旦 生 效 就不 能 再 更 改 , 否 则 用 户 怎 么 添 加 , 删 除 都 可 以 。 就 可 以 保 证 整 张 表 单 的 完 整 性 了 。可 能 你 会 说 , 怎 么 控 制 多 用 户 并 发 , 别 人 无 法 修 改 我 正 在 操 作 的 表 单 ? 这 就 是 用户 操 作 的 问 题 了 , 用 户 在 确 定 整 张 表 单 生 效 前 , 应 该 保 证 这 张 表 是 自 己 生 成 的 。你 也 可 以 通 过 自 定 义 的 锁 定 策 略 来 确 保 只 有 一 个 人 修 改 当 前 这 张 表 。


第 九 章 IBExpert作 为 Firebird 下 最 成 功 的 商 业 数 据 库 工 具 ,IBExpret 支 持 了 Firebird 数 据 库 开发 的 方 方 面 面 , 是 最 正 宗 的 工 具 。 当 然 基 于 费 用 考 虑 , 你 也 可 以 用 flameRobin这 些 工 具 。 一 个 好 的 工 具 可 以 大 大 提 升 生 产 率 。IBExpet 任 何 一 款 其 他 数 据 库 管理 工 具 的 。他 可 以 实 现 建 库 , 表 , 域 , 备 份 , 用 户 , 角 色 , 触 发 器 , 存 储 过 程 , 用 户 函数 声 明 , 数 据 编 辑 , 键 , 索 引 等 等 全 部 功 能 , 甚 至 于 监 控 firebird 底 层 api 调 用 ,从 而 发 现 用 户 程 序 访 问 数 据 库 的 SQL 语 句 跟 踪 分 析 (Firebird3.0 将 支 持 这 些 api而 不 用 通 过 拦 截 了 )。 而 做 到 这 一 切 , 却 是 一 个 应 用 程 序 实 现 的 , 这 个 程 序 的 数据 库 访 问 组 件 , 使 用 的 是 fibplus 这 个 强 大 的 组 件 , 当 然 这 个 组 件 对 于 firebird 是十 分 强 大 , 但 不 跨 库 。 他 还 使 用 了 ICS 网 络 组 件 , MWEdit, DevExpress ,FastReport,IBQuery, TNTWare 等 等 非 常 多 的 第 三 方 租 件 。 可 以 说 是 第 三 方 组 件 使 用 的 集 大成 者 。甚 至 于 数 据 库 设 计 器 也 包 含 其 中 ( 个 人 版 没 有 )。我 们 来 看 几 个 重 点 的 地 方 。有 三 个 菜 单 是 主 要 的 ,Database, Tools ,Services 分 别 是Database 对 用 户 表 , 视 图 , 域 , 触 发 器 , 存 储 过 程 等 进 行 新 建 , 编 辑 , 修改 , 删 除 等 操 作 。Tools 菜 单 包 含 , 脚 本 执 行 , 数 据 分 析 , 报 表 , 表 比 较 , 库 比 较 ,SQL 监 视 ,测 试 数 据 生 成 等 等 。Services 是 备 份 数 据 库 , 有 效 性 验 证 , 统 计 状 态 , 网 络 状 态 等 功 能 。


如 图 所 示 , 其 功 能 超 乎 想 想 。IBexpert 的 使 用 流 程 是 新 建 数 据 库 或 者 注 册 原 来 的 数 据 库 到 此 管 理 器 配 置里 面 ; 然 后 就 可 以 对 数 据 库 进 行 建 表 , 修 改 等 操 作 。


第 十 章 好 大 的 EXE<strong>Lazarus</strong> 编 译 出 来 的 EXE 很 大 , 的 确 , 但 是 当 你 稍 微 处 理 一 下 , 发 现 他 却 是那 么 可 爱 。比 如fpc\2.6.0\bin\i386-win32\strip.exe lazarus.exe就 可 以 直 接 将 <strong>Lazarus</strong>.exe 新 版 本 从 100MB , 降 到 10 多 MB.而 一 般 的 自 写 程 序 在 2MB 左 右 。还 是 可 以 接 受 的 吧 , 如 果 用 UPX 压 缩 一 下 , 可 以 达 到 1MB 左 右 了 。我 将 一 个 4.4MB 的 程 序 压 缩 到 了 1.25MB。 可 以 了 吧 ?


第 十 一 章 <strong>Lazarus</strong> 绿 化<strong>Lazarus</strong> 默 认 安 装 , 是 不 支 持 多 版 本 并 存 的 , 而 且 写 注 册 表 , 我 们 怎 么 实 现复 制 就 可 以 用 呢 ?第 一 章 导 出 注 册 表 信 息 , 可 以 用 监 视 软 件 看 写 了 哪 些 ;第 二 章 复 制 C:\Documents and Settings\Administrator\LocalSettings\Application Data\lazarus 这 个 目 录 到 安 装 目 录 。第 三 章 写 这 样 一 个 批 处 理 , 来 执 行 启 动 lazarusreg import lazarus102rc.reg..\lazarus.exe --primary-config-path=.\config这 样 , 你 的 lazarus 就 可 以 带 到 任 何 地 方 去 用 了 。


第 十 二 章 FireBird 的 分 发FireBird 本 身 有 安 装 包 , 和 用 户 自 定 义 安 装 两 种 部 署 模 式 , 你 有 没 有 见 过 大型 数 据 库 可 以 由 软 件 设 计 者 自 定 义 安 装 的 , 没 错 ,Firebird 就 是 这 样 的 , 他 的 理念 就 是 用 户 零 管 理 。将 Firebird 的 ZIP 包 解 压 缩 , 将 其 BAT 文 件 看 会 , 然 后 根 据 需 要 选 择 你 的部 署 模 式 和 需 要 哪 些 文 件 , 如 果 要 支 持 中 文 , 必 须 要 Intl 这 个 下 级 目 录 。INTL 目 录放 FBIntl.DLLFBClient.dll你 的 库你 的 软 件上 面 是 嵌 入 式 版 本 需 要 的 全 部 。当 然 你 也 可 以 考 虑 将 其 全 部 打 包 给 客 户 , 也 没 有 多 大 。


第 十 三 章 Firebird 在 其 他 编 程 语 言 应 用FireBird 的 Java 支 持 接 口 ,JayBird ,PHP 就 不 用 说 了 , 很 早 就 支 持 。还 支 持 ODBC,Python,.NET。其 他 一 些 工 具 可 以 在 www.ibphoneix.com/download/tools 里 面 去 看 看 。基 本 上 大 多 数 语 言 都 支 持 了 。ODBC 的 连 接 串Driver=Firebird/InterBase(r) driver;Uid=SYSDBA;Pwd=masterkey;dbname=d:\firebird\examples\test.fdb;Java 的 例 子String Driver = "org.firebirdsql.jdbc.FBDriver";String URL ="jdbc:firebirdsql:localhost/3050:D:\\Demo.FDB";//embeddedString Username = "SYSDBA";String Password = "masterkey";Connection con;Statement sql;ResultSet rs;try{Class.forName(Driver);}catch (ClassNotFoundException e){JOptionPane.showMessageDialog(null, e.toString(), " 错 误 ",JOptionPane.INFORMATION_MESSAGE);}try{


con = DriverManager.getConnection(URL,Username,Password);sql = con.createStatement();rs = sql.executeQuery("SELECT * FROM table1");rs.close();}catch(SQLException e1){JOptionPane.showMessageDialog(null, e1.toString(), " 错 误 ",JOptionPane.INFORMATION_MESSAGE);}


第 十 四 章 <strong>Lazarus</strong> 在 其 他 操 作 系 统 平 台 的应 用Windows CE 系 可 以 用 KOL-CE, 进 一 步 缩 小 EXE 尺 寸 , 用 LCL 也 可 以 。Android 系 , 目 前 JNI 接 口 部 分 转 换 中 。单 片 机 AVR 系 , 可 用 。Linux 系 统 , 支 持 良 好 。IOS 系 列 , 可 用 ;


第 十 五 章 我 想 换 个 数 据 库没 错 , 换 数 据 库 就 像 换 衣 服 , 你 只 需 要 将 ZConnection 的 Protocol 换 一 个 ,再 将 username,password 等 改 一 下 , 如 果 你 的 程 序 简 直 没 有 任 何 数 据 库 相 关 特 性的 代 码 的 话 , 直 接 F9 吧 。


第 十 六 章 我 想 开 发 一 个 组 件比 如 我 想 给 Tedit 扩 展 一 个 Value 属 性 .首 先 ,Package->New Component, 会 询 问 你 组 件 放 在 哪 个 包 ? 我 们 选 择 默 认的 Create New Package, 会 新 建 包 。然 后 叫 你 保 存 这 个 包 的 文 件 Lpk, 保 存 到 我 们 自 己 的 位 置 , 名 字 myeditlaz然 后 问 你 新 组 件 的 祖 父 是 谁 (New Component 标 签 页 )?选 择 TEdit可 以 给 他 一 个 PNG 图 标 ,Create 吧 。然 后 我 们 在Private 节 添 加FValue:String;procedure SetValue(AValue:String);functionGetValue:String;Published 节 添 加property Value :string read GetValue write Setvalue;然 后 我 们 Ctrl + Shift + C , 自 动 生 成 Setter ,Getter 框 架 , 然 后 我 们 填 写 代 码


procedure TMyEdit.SetValue(AValue: String);beginif Fvalue AValue then Fvalue := AValue;end;function TMyEdit.GetValue: String;beginresult := FValue;end;保 存 , 然 后 在 我 们 的 新 控 件 包 面 板 , 点 击 Compiler. 然 后 你 就 Install 吧 。恭 喜 , 你 的 首 个 控 件 完 成 。要 知 道 , 这 个 控 件 不 是 那 么 无 用 。


第 十 七 章 lazarus 的 报 表<strong>Lazarus</strong> 的 报 表 是 LazReport , 来 自 出 名 的 FastReport 最 后 的 GPL 的freereport2.33 版 本 。默 认 没 有 安 装 。如 何 安 装 ?Package ->Open Package File -> 选 择 安 装 目 录 下 components 下 的 lazReport目 录 下 的 Source 下 的 lazreport.lpk.然 后 compile , 然 后 选 择 use -> install。稍 微 等 一 会 , 提 示 , 回 答 YES.再 等 一 会 儿 ,<strong>Lazarus</strong> 会 把 自 己 编 译 。 这 是 为 了 以 后 使 用 的 稳 定 性 。然 后 会 自 动 重 新 启 动 IDE。 这 是 因 为 有 startlazarus.exe 的 存 在 , 所 以 才 能 自动 编 译 自 己 , 自 己 启 动 自 己 。看 图 :接 下 来 是 发 挥 时 间 , 您 就 爽 吧 !!!


第 十 八 章 lazarus 的 网 络 通 信 库<strong>Lazarus</strong> 跨 平 台 网 络 库 lnet。另 外 一 个 就 是 Indy 了 。我 最 喜 欢 的 ICS 由 于 只 支 持 Win 平 台 , 没 有 这 方 面 的 Port.我 们 可 以 下 载 lnet 的 0.6.6 , 跨 平 台 性 比 较 好 。只 有 有 限 的 几 个 协 议 支 持 ,TCP,UDP,TelNet,Ftp Client ,HTTP client,HTTPserver,SMTP client.Demo 会 提 示 没 有 找 到 OpenSSL, 删 除 SSL 组 件 , 再 编 译 , 如 图 , 一 个 打开 Host 模 式 , 一 个 connect, 可 以 send.如 果 觉 得 不 够 用 , 可 以 选 择 Indy。


第 十 九 章 CodeTyphon简 称 是 CT, 这 是 什 么 ?PHP 有 许 多 套 件 ,LAMP 等 等 。CT 也 是 <strong>Lazarus</strong> 的 一个 套 件 , 他 集 成 了 <strong>Lazarus</strong> 几 乎 所 有 平 台 的 功 能 , 跨 平 台 编 译 都 支 持 。 下 载 他 ,你 就 不 用 下 载 <strong>Lazarus</strong> 的 其 他 版 本 , 当 你 的 工 作 需 要 在 多 种 平 台 做 , 并 且 要 保 证是 同 一 版 本 代 码 , 可 以 考 虑 这 个 集 成 版 本 。不 过 大 多 数 情 况 下 , 你 需 要 编 译 出 你 自 己 需 要 的 那 些 版 本 。 否 则 就 他 那 400多 MB 的 包 是 放 不 下 的 。


第 二 十 章 我 想 改 变 IDE 的 风 格选 择 菜 单 Package ->install /uninstall packge , 选 择 easydock , 点 击 按 钮 installselection, 然 后 save an rebuild IDE.下 一 步 骤 ,continue.然 后 我 们 抓 住 “ 把 手 ” 就 可 以 将 消 息 窗 口 , 组 件 属 性 窗 口 , 代 码 窗口 ,CodeExplorer 等 任 意 组 合 。怎 么 样 , 方 便 吧 ?


第 二 十 一 章 调 试 程 序<strong>Lazarus</strong> 默 认 的 调 试 器 是 GNU Debuger , 非 常 不 错 的 调 试 器 , 有 时 候 这 个 设 置丢 失 了 , 我 们 需 要 设 置 正 确 , 否 则 无 法 调 试 。 菜 单 Tools->Options然 后 我 们 在 自 己 的 代 码 行 号 左 边 点 击 鼠 标 , 然 后 会 看 到 一 个 ? 如 图然 后 我 们 用 F9,F8,F7,F4 等 快 捷 键 进 行 调 试 ;


第 二 十 二 章 JSON 库 使 用<strong>Lazarus</strong> 自 带 了 一 个 JSON 可 视 化 编 辑 工 具 ,Tools\jsonviewer他 使 用 了 jsonparser.pp 这 个 单 元 , 也 使 用 了 fpJSON 这 个 单 元 ;这 个 工 具 对 我 们 其 他 语 言 的 开 发 者 来 说 也 是 一 个 福 音 , 我 们 可 以 将 此 工 具 生成 的 JSON 字 符 串 复 制 到 剪 贴 板 , 也 可 以 复 制 其 他 脚 本 语 言 的 JSON 数 据 过 来 进 行分 析 ;语 法 如FRoot:=TJSONObject.Create;P:=TJSONParser.Create(Clipboard.AsText);D:=TJSONBoolean.Create(Value);


第 二 十 三 章 XML 处 理我 们 来 看 demo 源 码 , 在 D:\lazarus102RC\examples\xmlreader\Usese 单 元 DOM, XMLReadprivateFDoc: TXMLDocument;// 文 档 对 象 类procedure TXMLRederForm.BitBtn1Click(Sender: TObject);beginif Assigned(FDoc) then// 如 果 已 经 加 载 过 , 释 放FreeAndNil(FDoc);if FileExistsUTF8(FileNameEdit1.FileName) then // 文 件 是 否 存 在 , 指 定 参 数 为utf8ReadXMLFile(FDoc, UTF8ToSys(FileNameEdit1.FileName));// 读 xml 文 件if Assigned(FDoc) then // 成 功ParseDoc; // 解 析 到 界 面end;// 解 析 到 控 件 显 示 的 过 程procedure TXMLRederForm.ParseDoc;procedure DoFill(AOwner:TTreeNode; Node:TDOMNode);


vari: integer;AItem:TTreeNode;beginif not Assigned(Node) then exit; //xml dom 对 象 空 , 返 回for i:=0 to Node.ChildNodes.Count - 1 do // 多 少 个 子 借 点beginAItem:=TreeView1.Items.AddChild(AOwner, Node.ChildNodes[i].NodeName);// 添 加 名 称 节 点 到 树AItem.Data:=Node.ChildNodes[i]; // 树 节 点 附 加 数 据 为 dom 对 象 节 点 指 针if not Assigned(TreeView1.Selected) thenTreeView1.Selected:=AItem;// 选 中 当 前 节 点DoFill(AItem, Node.ChildNodes[i]); // 递 归 填 充 树end;end;beginTreeView1.Selected:=nil;TreeView1.Items.BeginUpdate;TreeView1.Items.Clear;DoFill(nil, FDoc); // 呼 叫 过 程 内 嵌 过 程TreeView1.Items.EndUpdate;TreeView1Click(nil);end;


第 二 十 四 章 脚 本 语 言支 持 <strong>Lazarus</strong> 的 脚 本 语 言 有 很 多 个PaxScript, Pascal 语 法 ;CopyRight, 收 费 ;BESEN ,Javascript 语 法 ; copyright; 免 费 ;SEIIPascal 语 法 /Object Pascal 语 法 , 免 费 ,LGPL;RealThinClient 组 件 也 自 带 脚 本 ;Remobject Pascal Script 其 实 也 不 错 。


第 二 十 五 章 感 知 控 件 的 CRUD如 图 :我 们 只 要 将 数 据 库 的 字 符 集 设 置 为 UTF-8, 那 么 用 感 知 控 件 也 是 很 方 便 的 ,分 别 是 :procedure TForm1.Button5Click(Sender: TObject);beginzquery1.refresh;end;procedure TForm1.Button6Click(Sender: TObject);beginzquery1.append;end;procedure TForm1.Button7Click(Sender: TObject);beginzquery1.edit;end;procedure TForm1.Button8Click(Sender: TObject);


eginzquery1.post;end;procedure TForm1.Button9Click(Sender: TObject);beginzquery1.delete;end;由 于 底 层 自 动 在1. 输 入 的 时 候 将 ansi/ 本 地 代 码 页 转 换 到 了 unicode, 再 转 换 到 了 UTF-82. 显 示 的 时 候 将 UTF-8 转 换 到 了 unicode 进 行 显 示 , 所 以 能 支 持 国 家 强 制 标准GB18038 , 所 以 你 可 以 宣 告 你 的 软 件 支 持 GB18030如 下 图 , 显 示 了 此 标 准 最 后 一 个 汉 字注 意 在 windows xp 系 统 下 安 装 支 持 包 , 其 实 只 要 其 中 的 字 体 , 不 需 要 1,2,4字 节 显 示 的 api那 么 我 们 来 看 报 表 是 否 支 持 呢 ?Form 上 添 加 组 件


然 后 设 计 报 表 格 式预 览 效 果 , 我 们 可 以 看 到 也 是 支 持 的 。


注 意 , 字 体 处 都 要 设 置 为 " 宋 体 -18030"当 然 也 可 以 是 其 他 GB18030 字 体 。


第 二 十 六 章 嵌 入 web 浏 览 器<strong>Lazarus</strong> 支 持 IE 浏 览 器 的 嵌 入 , 同 时 也 支 持 Chrome 浏 览 器 嵌 入 。 我 们 来看 看 从 底 层 重 写 的 浏 览 器 , 不 依 赖 任 何 浏 览 器 的 实 现 ,THTMLPortTHTMLPort。此 控 件 作 者 L. David Baldwin at http://www.pbear.com/支 持 特 性 :.CSS.Frames.Bitmap,JPG,GIF,PNG大 HTML 文 件表 格表 单字 体背 景格 式 化 打 印查 找复 制 到 剪 贴 板上 下 标甚 至 支 持 midi 播 放安 装 方 法很 简 单 , 首 先 解 压 缩 我 们 下 载 的 压 缩 包 。然 后 在 lazarus,Package->Open package , 打 开 thtmlport\package\htmlcomp.lpkUse ->install重 新 编 译 IDE, 不 用 特 别 的 其 他 设 置 。我 们 新 建 一 个 项 目 ,窗 体 上 放 一 个 按 钮 , 一 个 htmlviewer 组 件 , 按 钮 代 码procedure TForm1.Button3Click(Sender: TObject);


var s:string;begins := 'Hello';update;htmlviewer1.LoadFromString(s);//OpenDialog1.Execute;// htmlviewer1.LoadFromFile(OpenDialog1.Filename);end;就 是 这 么 简 单 , 当 然 他 也 支 持 从 文 件 加 载 , 从 流 加 载 。 想 像 一 下 , 我 们 可 以用 来 做 什 么 ?


第 二 十 七 章 图 表图 表图 表 是 非 常 重 要 的 功 能 , 这 个 图 标 基 本 上 是 TChart 的 移 植 版 本 。


第 二 十 八 章 单 元 测 试软 件 测 试 对 于 软 件 开 发 来 说 是 非 常 重 要 的 , 但 是 除 了 我 们 编 写 代 码 的 时 候 的测 试 , 还 需 要 更 加 专 业 的 测 试 。测 试 方 法 不 外 乎 几 种 :1. 纯 人 工 测 试 : 乱 操 作 , 真 实 操 作 模 拟 ;2. 自 动 测 试 , 不 好 支 持 人 工 判 断 处 ;3. 软 件 模 拟 人 工 测 试 , 支 持 人 工 测 试 操 作 记 录 , 但 对 单 元 测 试 支 持 不 足 ;所 以 各 种 测 试 方 法 都 有 各 自 优 点 , 通 常 我 们 看 一 个 软 件 、 组 件 是 否 健 壮 , 就可 以 看 看 他 的 单 元 测 试 情 况 如 何 , 测 试 数 据 编 写 得 如 何 。我 们 来 看 看 <strong>Lazarus</strong> 提 供 的 测 试 方 法 ;首 先 新 建 一 个 工 程 ;选 择 fpcunit test application.然 后 在 模 板 代 码 里 面 TestHookUp 里 面 添 加 代 码 ,procedure TTestCase1.TestHookUp;begin//Fail('Write your own test');AssertTrue(' 测 试 1',1+1 = 2);AssertTrue(' 测 试 2',1+1 = 3);AssertEquals(' 测 试 3',1+1,2);AssertEquals(' 测 试 4',1+1,3);end;然 后 我 们 ,F9 执 行在 新 出 来 界 面 上 run all test当 然 这 个 测 试 几 乎 无 用 , 实 际 测 试 需 要 创 建 自 己 的 对 象 , 自 己 的 函 数 测 试 等 。


第 二 十 九 章 报 表 输 出 为 PDF 文 件PowerPDF 可 以 创 建 pdf 文 件 。对 象 的 包 含 结 构 是TPRPageTPRLayoutPanelTPRTextTPRRectTPREcllipseTPRImageTPRJpegImage页 面 对 象布 局 对 象文 字 对 象矩 形椭 圆 形图 像JPEG 图 像然 后 在 你 需 要 生 成 的 地 方 , 用 这 样 的 代 码 保 存 生 成 PDF 文 件if SaveDialog1.Execute then // 执 行 文 件 保 存 对 话 框with PReport1 dobeginFileName := SaveDialog1.FileName;// 文 件 名 给 TPReportBeginDoc;// 开 始 绘 制end;Print(PRPage1); // 输 出 1 页 , 也 可 以 输 出 多 页EndDoc;// 完 毕


第 三 十 章脚 本 编 辑 器脚 本 编 辑 器 , 用 synEdit 比 较 好 , 默 认 支 持 了 许 多 语 法 , 但 是 对 中 文 支 持 有 点问 题 , 参 考 46 章 。我 们 来 实 现 一 个 简 单 的 pascal 脚 本 编 辑 器 。1.project->new project 菜 单 ,ok, 新 建 application, 保 存 。2. 在 form 上 添 加 一 个 opendialog , 一 个 synedit, 一 个 高 亮 解 析 器SynFreePascalSyn1, 一 个 mainmenu,, 然 synedit 的 highlighter 属 性 为SynFreePascalSyn13.4. 编 辑 主 菜 单 , 在 一 个 菜 单 项 上 用 鼠 标 右 键 可 以 看 到 有 添 加 同 级 菜 单 和 子 菜单 , 还 有 立 即 创 建 菜 单 的 click 事 件 处 理 程 序 。5.new 菜 单 事 件 里 面Synedit1.text :='' ;6.Open 菜 单 脚 本 。if opendialog1.Execute thenbeginsynedit1.Lines.LoadFromFile(opendialog1.FileName);end;7.Exit 菜 单 事 件Close8. F9 调 试 起 来


第 三 十 一 章 跨 平 台 游 戏 开 发 引 擎下 面 我 们 来 隆 重 介 绍 一 个 跨 平 台 游 戏 开 发 引 擎 Zengl, 这 个 引 擎 支 持硬 件 加 速 接 口 :OpenGL,DirectX操 作 系 统 :Linux ,Windows 32/64 ,Android 6 ,iOS。编 程 语 言 :delphi ,lazarus,c/c++是 一 个 2D 引 擎 。安 装此 组 件 不 用 安 装 , 是 代 码 化 的 。只 需 要 设 置 。由 于 其 他 版 本 有 升 级 包 ,monoxxx , Directx 版 本 , 完 全 版 本 , 所 以我 们 要 注 意 选 择 , 我 们 下 载 完 全 版 本zengl-src-0.3.1.7z解 压 缩 。新 建 工 程 , 给 我 们 的 工 程 一 个 搜 索 路 径 ;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\headers\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\extra\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\src\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\lib\jpeg\$(TargetCPU)-$(TargetOS)\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\lib\msvcrt\$(TargetCPU)\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\lib\ogg\$(TargetCPU)-$(TargetOS)\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\lib\zlib\$(TargetCPU)-$(TargetOS)\;D:\lazarus102RC\lazaruscomponents\zengl-src-0.3.1\lib\zip\$(TargetCPU)-$(TargetOS)\;D:\lazarus102RC\lazaruscomponents\zenglsrc-0.3.1\lib\theora\$(TargetCPU)-$(TargetOS)\


注 意 每 行 前 面 加 上 自 己 的 路 径然 后 开 始 我 们 的 第 一 个 应 用 吧 。program demo01;{$R *.res}//Define compilation mode (comment to use so/dll/dylib):{$DEFINE STATIC}//This add the ZenGL units.uses{$IFNDEF STATIC}zglHeader{$ELSE}zgl_main,zgl_screen,zgl_window,zgl_timers,zgl_utils{$ENDIF};//Variables like in a standard pascal program:varDirApp: String;DirHome : String;//Procedures to add code:procedure Init;begin// Here can be loading of main resources.end;procedure Draw;begin// Here "draw" anything.end;procedure Update( dt : Double );begin// This function is the best way to implement smooth moving of something,


ecause timers are restricted by FPS.end;procedure Timer;begin// Caption will show the frames per second.wnd_SetCaption( '01 - Initialization[ FPS: ' +u_IntToStr( zgl_Get( RENDER_FPS ) ) + ' ]' );end;procedure Quit;begin//end;//Here start the program:Begin{$IFNDEF STATIC}zglLoad( libZenGL );{$ENDIF}// For loading/creating your own options/profiles/etc. you can get path to userhome// directory, or to executable file(not works for GNU/Linux).//DirApp := u_CopyStr( PChar( zgl_Get( DIRECTORY_APPLICATION ) ) );//DirHome := u_CopyStr( PChar( zgl_Get( DIRECTORY_HOME ) ) );// Create a timer with interval 1000ms.timer_Add( @Timer, 1000 );// Register the procedure, that will be executed after ZenGL initialization.zgl_Reg( SYS_LOAD, @Init );// Register the render procedure.zgl_Reg( SYS_DRAW, @Draw );// Register the procedure, that will get delta time between the frames.zgl_Reg( SYS_UPDATE, @Update );// Register the procedure, that will be executed after ZenGL shutdown.


zgl_Reg( SYS_EXIT, @Quit );// Enable using of UTF-8, because this unit saved in UTF-8 encoding and hereused// string variables.// zgl_Enable( APP_USE_UTF8 );// Set the caption of the window.wnd_SetCaption( '01 - Initialization' );// Allow to show the mouse cursor.wnd_ShowCursor( TRUE );// Set screen options.scr_SetOptions( 800, 600, REFRESH_MAXIMUM, FALSE, FALSE );// Initialize ZenGL.zgl_Init();End.//Resulting Code//The result is a template for ZenGL projects:这 只 是 一 个 黑 屏 幕 , 什 么 也 没 有 。下 面 就 是 学 习 其 demo 下 的 具 体 例 子 了 。我 们 打 开 一 个 产 生 大 量 精 灵 的 例 子 , 看 看 效 果 :


可 以 看 到 5000 个 精 灵 , 达 到 25fps, 并 且 只 用 了 18MB 内 存 。系 统 还 一 点 都 不 卡 。测 试 最 大 可 以 生 成 1 万 个 精 灵 。机 器 是 AMD APU-300 1.6GB 内 存 。


第 三 十 二 章 DataModule 成 也 萧 何 败 也 萧何许 多 程 序 员 喜 欢 将 DataModule 作 为 数 据 库 连 接 , 查 询 组 件 的 集 中 地 。 殊 不知 , 这 样 正 犯 了 编 程 的 大 忌 。 当 A 单 元 改 变 了 该 DataModule 中 某 个 query 状 态 ,会 影 响 到 B 单 元 。 除 非 非 常 有 必 要 的 地 方 , 否 则 不 要 这 样 做 。说 简 单 点 ,DataModule 就 是 整 个 软 件 的 全 局 变 量 , 我 们 最 好 是 将 必 须 作 为全 局 变 量 的 connection, 配 置 文 件 信 息 放 这 里 , 其 他 全 部 应 该 放 在 各 个 Unit 去 ,没 错 , 可 能 你 的 程 序 里 面 会 Query 比 较 多 , 但 是 , 这 样 做 达 到 了 " 信 息 隐 藏 " 的 目 的 ,我 们 这 个 开 发 环 境 是 RAD 的 风 格 , 所 以 connection 放 全 局 有 必 要 , 这 样 , 我 们在 设 计 期 可 以 方 便 设 计 我 们 的 Form.当 然 你 也 可 以 将 这 个 各 个 单 元 的 数 据 库 连 接 , 用 参 数 传 递 进 去 。 达 到 模 块 之间 最 大 解 耦 。 不 过 会 牺 牲 设 计 期 无 法 所 见 所 得 设 计 的 特 性 。


第 三 十 三 章 单 元 风 格我 们 知 道 ,<strong>Lazarus</strong> 默 认 会 给 我 们 的 单 元 一 个 变 量 声 明 节 。 在 implemetation 前面 ,注 意 , 这 个 地 方 的 变 量 是 单 元 变 量 , 是 全 局 的 , 如 果 引 用 这 个 单 元 , 就 可 以修 改 他 。 所 以 是 不 安 全 的 。我 们 应 该 将 他 删 除 , 在 调 用 方 声 明 并 且 使 用 这 个 变 量 , 完 毕 后 也 在 调 用 方 释放 。比 如 :VaraForm :TFrmMyForm;BeginAform := TFrmMyForm.create(application);TryAForm.showModal;FinallyAform.free;End;End;不 然 我 们 的 这 个 地 方 释 放 了 , 可 是 可 能 在 别 的 地 方 还 要 用 到 , 就 可 能 出 错 。也 就 是 将 一 个 Form 作 为 一 个 类 , 而 不 是 一 个 类 与 变 量 混 杂 的 单 元 。同 时 , 我 们 的 单 元 应 该 以 小 写 字 母 u 开 头 , 而 Form 类 用 Tfrm 开 头 ,DataModule 应 用 Tdm 开 头 ,dm 单 元 可 以 保 留 这 个 单 元 变 量 , 因 为 我 们 会 将 他 作为 我 们 的 唯 一 全 局 变 量 和 全 局 单 元 。


第 三 十 四 章 命 名一 个 好 的 名 字 决 定 一 个 人 的 一 生 , 比 如小 明 , 狗 蛋 , 王 大 , 张 三 , 不 是 一个 好 名 字 。 而 杰 克 , 鲍 勃 , 轻 舞 飞 扬 , 李 逍 遥 等 是 多 么 诗 意 的 名 字 。同 理 , 你 的 软 件 如 果 有 N 百 个 Unit,N 百 个 Form, 如 果 没 有 一 个 个 好 名 字 ,是 很 想 让 人 想 KO 的 。比 如 一 个 工 程 , 销 售 管 理 , 有uPurchse== > TFrmPurchaseuSale --> TfrmSale他 们 的 按 钮 有btnAdd ,btnDelete,btnEdit,btnPrint怎 么 样 , 一 看 就 知 道 他 们 是 做 什 么 的 了 吧 ?有 的 同 学 说 , 我 的 E 文 不 好 。 那 么 可 以 用 这 个 风 格 :uCaiGouD--> TckCaiGouDuXiaoShou --> TckXiaoShouanZengJia, anShanChu ,anBianJi ,anDaYin什 么 , 你 觉 得 比 较 别 扭 , 那 么 你 用 这 样 的 风 格 吧Unit1 -> TForm1Unit2 -> TForm2Button1,Button2,Button3,Button4或 者uCG.pasTFormCG....酷 吧 , 可 能 您 后 期 维 护 只 能 “ 哭 ”, 而 不 是 酷 了 。同 样 , 这 个 风 格 可 以 用 在 我 们 的 各 个 方 面 , 比 如 文 件 夹 啊 , 数 据 库 啊 , 字 段名 啊 , 你 儿 子 的 名 字 啊 。


第 三 十 五 章 数 据 库 设 计你 可 能 会 说 , 数 据 库 设 计 有 什 么 大 不 了 的 , 很 简 单 啊 。 如 果 一 个 软 件 将PrimaryKey 让 用 户 编 辑 , 结 果 会 怎 样 -- :-( 结 果 导 致 数 据 不 一 致 。 数 据 库 设 计 不好 , 还 做 什 么 数 据 库 呢 ?好 的 数 据 库 设 计 可 以 省 钱 , 省 到 就 是 赚 到 。几 个 基 本 原 则 :1. 尽 量 减 少 冗 余 ;比 如 销 售 单 , 应 该 按 我 们 日 常 见 的 单 据 逻 辑 , 分 为 表 头 + 表 尾 1 个 表 , 表 体 1个 表 ,1 个 主 键 进 行 关 联 ;2. 好 的 名 字 ;见 前 一 章 ;3. 适 当 考 虑 扩 展 ;比 如 预 留 几 个 字 段 ; 再 比 如 人 名 字 段 考 虑 20 以 上 宽 度 , 否 则 存 如 “ 张 三 的女 儿 ” 这 样 的 名 字 , 就 会 超 长 ;4. 考 虑 数 据 规 模 ;比 如 一 张 销 售 单 , 格 式 : 年 月 日 + 3 位 序 号 , 可 是 客 户 有 天 开 单 超 过 万 张 了 ,麻 烦 了 吧 ;5. 尽 量 不 使 用 数 据 库 特 有 特 性 ;比 如 time 字 段 ,date 字 段 就 不 太 通 用 , 又 比 如 CLSID。6. 尽 量 不 使 用 游 标 ;我 开 发 的 某 系 统 , 有 天 崩 溃 了 , 发 现 是 因 为 使 用 游 标 计 算 超 过 1 小 时 , 太 慢 ,优 化 不 使 用 游 标 后 , 达 到 N 分 钟 (N


9. 防 止 空 值 扩 散 ;这 就 需 要 在 SQL 查 询 里 使 用 ISNULL;10. 默 认 值 , 默 认 值 规 则 , 可 以 减 少 空 值 扩 散 的 处 理 , 比 如 数 字 类 型 , 默 认为 0, 而 日 期 类 型 , 默 认 为 当 时 , 这 样 当 插 入 语 句 , 没 有 包 含 插 入 这 个 字 段 的 时候 , 能 够 得 到 一 个 初 始 值 , 可 以 防 止 程 序 里 面 得 到 null 值 , 在 比 较 , 显 示 , 转 换的 时 候 出 错 。11. 适 当 的 索 引 , 当 你 的 数 据 里 面 包 含 大 量 的 记 录 的 时 候 , 索 引 就 显 得 非 常重 要 , 索 引 的 创 建 , 需 要 根 据 查 询 的 语 句 来 进 行 , 有 的 字 段 非 关 键 字 段 , 索 引 就不 是 那 么 必 要 , 一 般 说 来 where , 和 join 语 句 里 面 包 含 的 字 段 都 应 该 建 立 索 引 。


第 三 十 六 章 <strong>Lazarus</strong> 和 Delphi 的 异 同<strong>Lazarus</strong> 在 语 法 上 非 常 接 近 Delphi 7, 也 添 加 了 一 些 Delphi2010 的 特 性 。语 法 上 更 加 严 格 一 些 ;1. 给 事 件 挂 接 处 理 程 序 , 需 要 地 址 操 作 符 @2. 支 持 += -= /= *= 复 合 赋 值 运 算3. 默 认 字 符 集 是 UTF-8, 而 不 是 UCS-24.<strong>Lazarus</strong> 增 加 了 常 量 的 数 据 表 示 方 法 , %xxx 表 示 二 进 制 数 据 ,$xxx 表 示16 进 制 ,&xxx 表 示 八 进 制 ; xE/eyyy.zz 表 示 科 学 计 数 ; 十 进 制 还 是 老 样 子 ;5.<strong>Lazarus</strong> 默 认 不 支 持 Goto 语 句 , 如 果 要 支 持 , 需 要 {$GOTO ON}6.<strong>Lazarus</strong> 的 字 符 串 默 认 是 '' 引 起 来 的 , 或 者 混 合 # 开 头 的 非 打 印 字 符 , 还 有 就是 Unicode( 默 认 utf-8 字 符 ), 比 如 下 面 的 汉 字 是 utf8'Hello '#13#10' 大 家 好 吗 ?'7. 新 版 本 增 加 了 64 位 常 量 定 义 , 比 如 :Const ainteger=1423424234234234234;8. 默 认 在 freepascal 模 式 ,integer 是 映 射 到 smallint 的 , 只 有 ObjFPC 模 式/Application 模 式 是 longint,cardinal 是 longword 的 映 射 。9. 增 加 了 bytebool,wordbool,longbool, 非 0 表 示 真 , 怎 么 样 , 我 们 也 可 以 使 用c 的 特 性 ;10. 子 界 类 型 , 同 样 支 持 十 六 进 制 ,2 进 制 ,8 进 制 , 比 如type t=$800..$F000;type tt=%10..%100110;11. 增 加 了 comp 数 据 类 型 , 是 用 64 位 int 表 达 的 浮 点 数 ; 货 币 类 型 表 示-922337203685477.5808 .. 922337203685477.580792 万 亿 , 能 够 表 达 大 多 数 需 求12. 字 符 类 型 , 可 以 用 #12 表 达 , 也 可 以 用 脱 字 符 (^) ^G 就 表 示 第 7 个 ascii字 符 , 只 能 使 用 26 个 ;


13. 字 符 串 类 型 有 shortstring ,string,ansistring,unicodestring,widestringWidestring 用 于 OLE/COM, 没 有 引 用 计 数 , 只 有 NULL 结 束 , 并 保 存widechar;而 unicodestring 用 ansistring 技 术 , 有 引 用 计 数 ; 转 换 类 型 的 时 候 , 结 束 字符 是 两 个 #0, 而 不 是 ansistring 的 #0 一 个 .14. 给 一 个 事 件 句 柄 赋 值 , 必 须 使 用 @, 在 delphi 不 用 , 如 果 使 用 -MDelphi 或-MTP 开 关 也 可 以 达 到 兼 容 的 效 果 ;15. 同 样 lazarus 也 支 持 变 体 类 型 , 主 要 用 于 支 持 OLE/COM ,COBRA 数 据 库等VarW : Variant;V : String;beginW:=CreateOleObject(’Word.Application’);V:=W.Application.Version;Writeln(’Installed version of MS Word is : ’,V);end;16. 新 增 支 持 线 程 变 量 , 默 认 在 线 程 里 面 的 局 部 变 量 是 线 程 变 量 ; 全 局 变 量 也可 以 设 置 为 线 程 变 量 , 如 ;Threadvar :Test1:integer;17. 增 加 严 格 的 private, 不 能 被 任 何 其 他 类 , 或 子 孙 类 修 改 ; 即 使 在 同 一 个单 元 ;Strict PrivateAa:integer;TODO


第 三 十 七 章 Free Spider 开 发 Web 后 端Web 后 端 , 不 是 脚 本 语 言 的 天 下 , 如 果 你 的 老 板 要 求 代 码 必 须 编 译 , 并 且 难于 反 编 译 , 怎 么 办 ? 要 求 后 台 功 能 很 强 大 , 怎 么 办 ?可 以 使 用 Free Spider 作 为 后 端 。 由 于 是 编 译 型 的 , 其 速 度 无 可 比 拟 。Spider意 思 是 蜘 蛛 。最 新 版 可 以 在 http://code.sd/freespider 找 到作 者 Motaz Abdel Azeem协 议 :LGPL跨 平 台 ,Linux,Windows,Mac 均 支 持 。支 持 CGI,Apache 模 块 二 种 工 作 模 式 。首 先 我 们 安 装 其 包 , 然 后 , 我 们 在 <strong>Lazarus</strong> 新 建 工 程 ,project ->New project - >出 现 模 版 。1. 我 们 选 FreeSpider Web Applicaton;2. 把 TSpiderCGI 放 到 datamodule , 名 字 SpiderCGI13. 设 置 datamodule onCreate 代 码SpiderCGI1.Execute;4. 设 置 SpiderCGI1 代 码 ;Response.ContentType:= 'text/html; charset=UTF­8';Response.Add('Hello world');5. 编 译 , 复 制 到 你 的 http 服 务 器 的 CGI-BIN 目 录6. 浏 览 器 里 面 访 问http://localhost/cgi-bin/first.exe


第 三 十 八 章 <strong>Lazarus</strong> 的 synedit 编 译如 果 我 们 要 编 写 基 于 synEdit 的 程 序 , 并 且 调 试 组 件 , 我 们 发 现 lazarus 自 带的 synEdit, 编 译 出 错 , 原 来 是 synEdit 支 持 的 utf-8, 而 代 码 里 面 的 synexporthtml.pas里 面 包 含 了 Latin-1, 超 过 128 的 字 符 , 是 单 字 符 , 所 以 synEdit 认 为 他 是 半 个 汉字 , 或 者 叫 做 1/3 个 UTF-8 字 符 。 所 以 出 错 , 贴 上 我 们 修 改 的 :unit SynExportHTML;{$I synedit.inc}interfaceusesClasses,{$IFDEF SYN_CLX}Qt,QGraphics,{$ELSE}{$IFDEF SYN_LAZARUS}LCLIntf, LCLType, Graphics, ClipBrd,{$ELSE}Windows,Graphics,{$ENDIF}{$ENDIF}SynEditExport;typeTHTMLFontSize = (fs01, fs02, fs03, fs04, fs05, fs06, fs07, fsDefault);//eb 2000-10-12TSynExporterHTML = class(TSynCustomExporter)privatefFontSize: THTMLFontSize;


function ColorToHTML(AColor: TColor): string;protectedfCreateHTMLFragment: boolean;procedure FormatAfterLastAttribute; override;procedure FormatAttributeDone(BackgroundChanged, ForegroundChanged:boolean;FontStylesChanged: TFontStyles); override;procedure FormatAttributeInit(BackgroundChanged, ForegroundChanged:boolean;FontStylesChanged: TFontStyles); override;{begin}//mh 2000-10-10procedure FormatBeforeFirstAttribute(BackgroundChanged,ForegroundChanged: boolean; FontStylesChanged: TFontStyles); override;{end}//mh 2000-10-10procedure FormatNewLine; override;function GetFooter: string; override;function GetFormatName: string; override;function GetHeader: string; override;publicconstructor Create(AOwner: TComponent); override;publishedproperty Color;property CreateHTMLFragment: boolean read fCreateHTMLFragmentwrite fCreateHTMLFragment default FALSE;property DefaultFilter;property Font;property Highlighter;property HTMLFontSize: THTMLFontSize read fFontSize write fFontSize;


eb 2000-10-12property Title;property UseBackground;end;implementationusesSysUtils,SynEditStrConst;{ TSynExporterHTML }constructor TSynExporterHTML.Create(AOwner: TComponent);constCF_HTML = 'HTML Format';begininherited Create(AOwner);{**************}{$IFNDEF SYN_CLX}fClipboardFormat := RegisterClipboardFormat(CF_HTML);{$ENDIF}fFontSize := fs03;fDefaultFilter := SYNS_FilterHTML;// setup array of chars to be replacedfReplaceReserved['&'] := '&amp;';// by sxg chinese 2012-9-6 lazarus ide usedutf-8 ,can not edit latin-1fReplaceReserved[''] := '&gt;';fReplaceReserved['"'] := '&quot;';fReplaceReserved[#153] := '&trade;'; // TM 注 册 商 标单 字 节 , 本 来 有 一 种 是2 字 节fReplaceReserved[#169] := '&copy;';fReplaceReserved[#174] := '&reg;';


有 序fReplaceReserved[#192] := '&Agrave;';fReplaceReserved[#193] := '&Aacute;';fReplaceReserved[#194] := '&Acirc;';// 有 一 个 小 写 &acirc #226fReplaceReserved[#195] := '&Atilde;';fReplaceReserved[#196] := '&Auml;';fReplaceReserved[#197] := '&Aring;';fReplaceReserved[#198] := '&AElig;';fReplaceReserved[#199] := '&Ccedil;';fReplaceReserved[#200] := '&Egrave;';fReplaceReserved[#201] := '&Eacute;';fReplaceReserved[#202] := '&Ecirc;';fReplaceReserved[#203] := '&Euml;';fReplaceReserved[#204] := '&Igrave;';fReplaceReserved[#205] := '&Iacute;';fReplaceReserved[#206] := '&Icirc;';fReplaceReserved[#207] := '&Iuml;';fReplaceReserved[#208] := '&ETH;';fReplaceReserved[#209] := '&Ntilde;';fReplaceReserved[#210] := '&Ograve;';fReplaceReserved[#211] := '&Oacute;';fReplaceReserved[#212] := '&Ocirc;';fReplaceReserved[#213] := '&Otilde;';fReplaceReserved[#214] := '&Ouml;';// 缺 215fReplaceReserved[#216] := '&Oslash;';fReplaceReserved[#217] := '&Ugrave;';fReplaceReserved[#218] := '&Uacute;';fReplaceReserved[#219] := '&Ucirc;';fReplaceReserved[#220] := '&Uuml;';


fReplaceReserved[#221] := '&Yacute;';fReplaceReserved[#222] := '&THORN;';fReplaceReserved[#223] := '&szlig;';fReplaceReserved[#224] := '&agrave;';fReplaceReserved[#225] := '&aacute;';fReplaceReserved[#226] := '&acirc;';fReplaceReserved[#227] := '&atilde;';fReplaceReserved[#228] := '&auml;';fReplaceReserved[#229] := '&aring;';fReplaceReserved[#230] := '&aelig;';fReplaceReserved[#231] := '&ccedil;';fReplaceReserved[#232] := '&egrave;';fReplaceReserved[#233] := '&eacute;';fReplaceReserved[#234] := '&ecirc;';fReplaceReserved[#235] := '&euml;';fReplaceReserved[#236] := '&igrave;';fReplaceReserved[#237] := '&iacute;';fReplaceReserved[#238] := '&icirc;';fReplaceReserved[#239] := '&iuml;';fReplaceReserved[#240] := '&eth;';fReplaceReserved[#241] := '&ntilde;';fReplaceReserved[#242] := '&ograve;';fReplaceReserved[#243] := '&oacute;';fReplaceReserved[#244] := '&ocirc;';fReplaceReserved[#245] := '&otilde;';fReplaceReserved[#246] := '&ouml;';//#247 &dividefReplaceReserved[#248] := '&oslash;';fReplaceReserved[#249] := '&ugrave;';fReplaceReserved[#250] := '&uacute;';


fReplaceReserved[#251] := '&ucirc;';fReplaceReserved[#252] := '&uuml;';fReplaceReserved[#253] := '&yacute;';fReplaceReserved[#254] := '&thorn;';fReplaceReserved[#255] := '&yuml;';//fReplaceReserved[#161] := '&iexcl;';fReplaceReserved[#162] := '&cent;';fReplaceReserved[#163] := '&pound;';fReplaceReserved[#164] := '&curren;';fReplaceReserved[#165] := '&yen;';fReplaceReserved[#166] := '&brvbar;';fReplaceReserved[#167] := '&sect;';fReplaceReserved[#168] := '&uml;';//169 &copy;fReplaceReserved[#170] := '&ordf;';fReplaceReserved[#171] := '&laquo;';//172 &not;fReplaceReserved[#173] := '&shy;';//174 &regfReplaceReserved[#175] := '&macr;';fReplaceReserved[#176] := '&deg;';fReplaceReserved[#177] := '&plusmn;';fReplaceReserved[#178] := '&sup2;';fReplaceReserved[#179] := '&sup3;';fReplaceReserved[#180] := '&acute;';fReplaceReserved[#181] := '&micro;';//182 parafReplaceReserved[#183] := '&middot;';fReplaceReserved[#184] := '&cedil;';


fReplaceReserved[#185] := '&sup1;';fReplaceReserved[#186] := '&ordm;';fReplaceReserved[#187] := '&raquo;';fReplaceReserved[#188] := '&frac14;';fReplaceReserved[#189] := '&frac12;';fReplaceReserved[#190] := '&frac34;';fReplaceReserved[#191] := '&iquest;';//fReplaceReserved[#215] := '&times;';fReplaceReserved[#247] := '&divide';fReplaceReserved[#128] := '&euro;'; //#128end;function TSynExporterHTML.ColorToHTML(AColor: TColor): string;varRGBColor: TColorRef;RGBValue: byte;constDigits: array[0..15] of char = '0123456789ABCDEF';beginRGBColor := ColorToRGB(AColor);Result := '"#000000"';{****************}{$IFNDEF SYN_CLX}RGBValue := GetRValue(RGBColor);{$ENDIF}if RGBValue > 0 then beginResult[3] := Digits[RGBValue shr 4];Result[4] := Digits[RGBValue and 15];end;{****************}


{$IFNDEF SYN_CLX}RGBValue := GetGValue(RGBColor);{$ENDIF}if RGBValue > 0 then beginResult[5] := Digits[RGBValue shr 4];Result[6] := Digits[RGBValue and 15];end;{****************}{$IFNDEF SYN_CLX}RGBValue := GetBValue(RGBColor);{$ENDIF}if RGBValue > 0 then beginResult[7] := Digits[RGBValue shr 4];Result[8] := Digits[RGBValue and 15];end;end;procedure TSynExporterHTML.FormatAfterLastAttribute;beginif fsStrikeout in fLastStyle thenAddData('');if fsUnderline in fLastStyle thenAddData('');if fsItalic in fLastStyle thenAddData('');if fsBold in fLastStyle thenAddData('');if fLastFG fFont.Color thenAddData('');if UseBackground and (fLastBG fBackgroundColor) thenAddData('');


end;procedure TSynExporterHTML.FormatAttributeDone(BackgroundChanged,ForegroundChanged: boolean; FontStylesChanged: TFontStyles);beginif BackgroundChanged or ForegroundChanged or (FontStylesChanged [])thenbeginif fsStrikeout in fLastStyle thenAddData('');if fsUnderline in fLastStyle thenAddData('');if fsItalic in fLastStyle thenAddData('');if fsBold in fLastStyle thenAddData('');end;if (BackgroundChanged or ForegroundChanged) and (fLastFG fFont.Color)then //mh 2000-10-10AddData('');if BackgroundChanged thenAddData('');end;procedure TSynExporterHTML.FormatAttributeInit(BackgroundChanged,ForegroundChanged: boolean; FontStylesChanged: TFontStyles);beginif BackgroundChanged thenAddData('


AddData('');if BackgroundChanged or ForegroundChanged or (FontStylesChanged [])thenbeginif fsBold in fLastStyle thenAddData('');if fsItalic in fLastStyle thenAddData('');if fsUnderline in fLastStyle thenAddData('');if fsStrikeout in fLastStyle thenAddData('');end;end;{begin}//mh 2000-10-10procedureTSynExporterHTML.FormatBeforeFirstAttribute(BackgroundChanged,ForegroundChanged: boolean; FontStylesChanged: TFontStyles);beginif BackgroundChanged thenAddData('


AddData('');if fsStrikeout in fLastStyle thenAddData('');end;end;{end}//mh 2000-10-10procedure TSynExporterHTML.FormatNewLine;beginAddNewLine;end;function TSynExporterHTML.GetFooter: string;beginResult := '';if fExportAsText thenResult := ''#13#10''#13#10;if not fCreateHTMLFragment thenResult := Result + ''#13#10'';end;function TSynExporterHTML.GetFormatName: string;beginResult := SYNS_ExporterFormatHTML;end;function TSynExporterHTML.GetHeader: string;constDescriptionSize = 105;HeaderSize = 47;FooterSize1 = 58;FooterSize2 = 24;NativeHeader = 'Version:0.9'#13#10 +


'StartHTML:%.10d'#13#10 +'EndHTML:%.10d'#13#10 +'StartFragment:%.10d'#13#10 +'EndFragment:%.10d'#13#10;HTMLAsTextHeader = ''#13#10 +''#13#10 +'%s'#13#10 +//+by sxg 2012-9-6 Chinese coding''#13#10+''#13#10 +''#13#10 +''#13#10;varsFontSize: string;//eb 2000-10-12beginResult := '';if fExportAsText then beginif not fCreateHTMLFragment thenResult := Format(HTMLAsTextHeader, [Title, ColorToHtml(fFont.Color),ColorToHTML(fBackgroundColor)]);{begin}//eb 2000-10-12if fFontSize fsDefault thensFontSize := Format(' size=%d', [1 + Ord(fFontSize)])elsesFontSize := '';Result := Result + Format(''#13#10'',[sFontSize, fFont.Name]);


{end}//eb 2000-10-12end else begin// Described inhttp://msdn.microsoft.com/library/sdkdoc/htmlclip/htmlclipboard.htmResult := Format(NativeHeader, [DescriptionSize,DescriptionSize + HeaderSize + GetBufferSize + FooterSize1,DescriptionSize + HeaderSize,DescriptionSize + HeaderSize + GetBufferSize + FooterSize2]);if not fCreateHTMLFragment thenResult := Result + ''#13#10''#13#10'';Result := Result + '';AddData('');end;end;end.这 样 就 可 以 正 确 编 译 了 。


第 三 十 九 章 <strong>Lazarus</strong> 的 第 三 方 组 件 调 试当 第 三 方 组 件 有 BUG 或 不 是 我 们 要 的 效 果 , 我 们 难 免 需 要 调 试 控 件 代 码 ,怎 么 做 呢 ?设 置 工 程 属 性 :Project->Project Option ->Compiler Option ->Other Source , 单 击 下 面 的 按 钮 ,然 后 在 出 现 的 窗 口 添 加 组 件 的 路 径 , 就 可 以 了 。


第 四 十 章试 窗 口<strong>Lazarus</strong> GUI 程 序 的 控 制 台 调首 先 打 开 你 的 工 程 , 然 后 看 工 程 源 码 project->view project source , 然 后 输 入{$apptype console }到 你 的 工 程 program 行 下 一 行 ;DebugLnEnter(DebugLnExit([DebugLn('几 个 函 数 是 <strong>Lazarus</strong> 的 LCL 统 一 的 调 试 窗 口 输 出 函 数 。如 图我 们 可 以 看 到 笔 者 正 在 调 试 字 符 宽 度 的 小 BUG, 已 经 成 功 , 可 以 参 见第 四 十 六 章 节 。


第 四 十 一 章 <strong>Lazarus</strong> 的 乱 码 问 题 2由 于 其 核 心 是 基 于 UTF8, 可 能 你 许 多 地 方 要 进 行 转 换 编 码 , 比 如1. 在 编 辑 器 输 入 的 字 符 , 存 入 非 UTF8 数 据 库 ,UTF8toAnsi2. 文 件 名 访 问 , If fileExistsUTF8(fileName) thenIF filExists(CP936ToUTF8(fileName)) Then3. 测 试 字 符 串 长 度 length(Utf8ToAnsi(' 你 好 '));4. 对 于 synEdit 的 lines.text 转 换 编 码 之 后 , 还 要 去 掉 BOM3 个 字 节S := utf8toansi(synedit1.lines.text);S := rightstr(s,length(s)-3);5. 使 用 API 的 地 方Messagebox(0,Utf8ToAnsi(" 提 示 信 息 "),UTF8ToAnsi(" 标 题 "),0);当 然 你 可 以 直 接 用 Application.ShowMessage(" 信 息 ");对 于 大 多 数 函 数 , 都 有 一 个 Utf8 前 缀 的 版 本 。 也 有 的 是 后 缀 版 。编 码 方 面 一 般 涉 及 最 多 的 就 是 , 命 令 行 参 数 , 文 件 读 , 文 件 写 , 目 录 操 作 ,文 件 查 找 , 编 辑 器 内 码 , 界 面 控 件 , 数 据 集 , 字 符 串 转 换 , 查 找 , 截 取 , 等 地 方 。主 要 在 lazutils\lazutf8classes.pas ,iconvencoding,lazutf8,filetuils ,XML ,JSON等 单 元其 中 LazUTF8 在 components\lazutils 目 录 , 还 有 一 个 lazutf8sysutilslazutf8classes.pas, 甚 至 还 包 括 一 个 lazutf16.pas 版 本 。我 们 看 看 有 哪 些 函 数 ?AnsiToUTF8 和 UTF8 ToAnsi 需 要 在 Linux,BSD , MacOSX 下 面 的 一 位widestring 管 理 器 , 但 是 通 常 这 些 操 作 系 统 使 用 的 UTF-8 当 做 系 统 编 码 , 所 以widestring 管 理 器 是 不 需 要 。function NeedRTLAnsi: boolean;// true 如 果 系 统 编 码 不 是 UTF-8procedure SetNeedRTLAnsi(NewValue: boolean);function UTF8ToSys(const s: string): string;// 像 UTF8ToAnsi 但 依 赖 widestring


管 理 器Function SysToUTF8(const s: string): string;// 像 AnsiToUTF8 但 依 赖WideString 管 理 器function UTF8CharacterLength(p: PChar): integer; // 测 试 UTF8 字 符 长 度function UTF8Length(const s: string): PtrInt;//UTF8 字 符 串 长 度function UTF8Length(p: PChar; ByteCount: PtrInt): PtrInt;function UTF8CharacterToUnicode(p: PChar; out CharLen: integer): Cardinal;//转 换 到 Unicodefunction UnicodeToUTF8(CodePoint: cardinal): string;//unicode 到 utf8function UnicodeToUTF8(CodePoint: cardinal; Buf: PChar): integer;//unicode 到utf8function UnicodeToUTF8SkipErrors(CodePoint: cardinal; Buf: PChar): integer;//忽 略 错 误 的 版 本function UnicodeToUTF8Inline(CodePoint: cardinal; Buf: PChar): integer; inline;function UTF8ToDoubleByteString(const s: string): string;//utf8 转 到 双 字 节 字符 串function UTF8ToDoubleByte(UTF8Str: PChar; Len: PtrInt; DBStr: PByte):PtrInt;function UTF8FindNearestCharStart(UTF8Str: PChar; Len: integer;BytePos: integer): integer;// 查 找 最 进 的 字 符 起 始 位function UTF8CharStart(UTF8Str: PChar; Len, CharIndex: PtrInt): PChar;// 某 字符 的 开 始 位 置 字 节 指 针function UTF8CharToByteIndex(UTF8Str: PChar; Len, CharIndex: PtrInt):PtrInt;// 类 似 上 个 , 返 回 字 节 位 置procedure UTF8FixBroken(P: PChar); overload;// 修 复 坏 掉 的 UTF8 串procedure UTF8FixBroken(var S: string); overload;// 重 载 的 字 符 串 参 数 版 本function UTF8CharacterStrictLength(P: PChar): integer;// 严 格 的 长 度function UTF8CStringToUTF8String(SourceStart: PChar; SourceLen: PtrInt) :string;//C 语 言 转 义 串 转 换 为 UTF8 原 始 串function UTF8Pos(const SearchForText, SearchInText: string; StartPos: SizeInt =


1): PtrInt;//POS 的 UTF8 版function UTF8PosP(SearchForText: PChar; SearchForTextLen: SizeInt;SearchInText: PChar; SearchInTextLen: SizeInt): PChar;function UTF8Copy(const s: string; StartCharIndex, CharCount: PtrInt): string;//复 制procedure UTF8Delete(var s: String; StartCharIndex, CharCount: PtrInt);// 删 除其 中 N 个 字 符procedure UTF8Insert(const source: String; var s: string; StartCharIndex:PtrInt);// 插 入 字 符 到 串function UTF8LowerCase(const AInStr: string; ALanguage: string=''): string;// 小写function UTF8UpperCase(const AInStr: string; ALanguage: string=''): string;// 大写function FindInvalidUTF8Character(p: PChar; Count: PtrInt;StopOnNonASCII: Boolean = false): PtrInt;// 扫 描 错 误function ValidUTF8String(const s: String): String;// 得 到 合 法 的 UTF8 串 , 有 非法 的 会 修 复typeTUTF8TrimFlag = (u8tKeepStart,u8tKeepEnd,u8tKeepTabs,u8tKeepLineBreaks,u8tKeepNoBreakSpaces,u8tKeepControlCodes // excluding tabs and line breaks);TUTF8TrimFlags = set of TUTF8TrimFlag;function UTF8Trim(const s: string; Flags: TUTF8TrimFlags = []): string;// 删 除字 符 串 的 前 后 空 格 和 回 车 等 字 符 , 具 体 见 前 面 定 义


procedure AssignUTF8ListToAnsi(UTF8List, AnsiList: TStrings);//UTF8 字 符 串复 制// 比 较 函 数function UTF8CompareStr(const S1, S2: string): Integer; inline;function UTF8CompareText(const S1, S2: string): Integer;function CompareStrListUTF8LowerCase(List: TStringList; Index1, Index2:Integer): Integer;function ConvertUTF8ToUTF16(Dest: PWideChar; DestWideCharCount:SizeUInt;Src: PChar; SrcCharCount: SizeUInt; Options: TConvertOptions;out ActualWideCharCount: SizeUInt): TConvertResult;function ConvertUTF16ToUTF8(Dest: PChar; DestCharCount: SizeUInt;Src: PWideChar; SrcWideCharCount: SizeUInt; Options: TConvertOptions;out ActualCharCount: SizeUInt): TConvertResult;function UTF8ToUTF16(const S: AnsiString): UnicodeString;function UTF16ToUTF8(const S: UnicodeString): AnsiString;// 本 地 化 相 关procedure LazGetLanguageIDs(var Lang, FallbackLang: String);procedure LazGetShortLanguageID(var Lang: String);同 样 , 这 些 函 数 在 FileUtils 里 面 也 有 , 关 于 UTF8 的 APi, 我 们 可 以 阅 读 IDE,或 者 其 他 很 多 组 件 的 源 码 , 都 在 用 。而 文 件 相 关 的 UTF8 函 数 如 下function FileExistsUTF8(const Filename: string): boolean;function FileAgeUTF8(const FileName: string): Longint;function DirectoryExistsUTF8(const Directory: string): Boolean;function ExpandFileNameUTF8(const FileName: string): string;function ExpandUNCFileNameUTF8(const FileName: string): string;function ExtractShortPathNameUTF8(Const FileName : String) : String;function FindFirstUTF8(const Path: string; Attr: Longint; out Rslt: TSearchRec):Longint;


function FindNextUTF8(var Rslt: TSearchRec): Longint;procedure FindCloseUTF8(var F: TSearchrec);function FileSetDateUTF8(const FileName: String; Age: Longint): Longint;function FileGetAttrUTF8(const FileName: String): Longint;function FileSetAttrUTF8(const Filename: String; Attr: longint): Longint;function DeleteFileUTF8(const FileName: String): Boolean;function RenameFileUTF8(const OldName, NewName: String): Boolean;function FileSearchUTF8(const Name, DirList : String; ImplicitCurrentDir :Boolean = True): String;function FileIsReadOnlyUTF8(const FileName: String): Boolean;function GetCurrentDirUTF8: String;function SetCurrentDirUTF8(const NewDir: String): Boolean;function CreateDirUTF8(const NewDir: String): Boolean;function RemoveDirUTF8(const Dir: String): Boolean;function ForceDirectoriesUTF8(const Dir: string): Boolean;function FileOpenUTF8(Const FileName : string; Mode : Integer) : THandle;function FileCreateUTF8(Const FileName : string) : THandle; overload;function FileCreateUTF8(Const FileName : string; Rights: Cardinal) : THandle;overload;// environmentfunction ParamStrUTF8(Param: Integer): string;function GetEnvironmentStringUTF8(Index: Integer): string;function GetEnvironmentVariableUTF8(const EnvVar: string): String;function GetAppConfigDirUTF8(Global: Boolean): string;function GetAppConfigFileUTF8(Global: Boolean; SubDir: boolean = false):string;// otherfunction SysErrorMessageUTF8(ErrorCode: Integer): String;那 么 <strong>Lazarus</strong> 不 支 持 Unicode 吗 ?


<strong>Lazarus</strong> 也 支 持 Unicode 类 型 , 就 是 WideString 类 型 , 只 是 在 编 辑 器 输 入 的是 UTF8, 所 以 要 转 换 , 然 后 将 Unicode 显 示 , 又 要 转 换 成 UTF8 的 模 式 , 除 非你 自 己 写 Unicode 的 界 面 控 件 , 比 如 :VarWs:WideString;BeginW:=UTF8ToUTF16(' 汉 字 ');Button1.Caption:=UTF16ToUTF8(w);String 类 型 本 身 没 有 区 分 ANSI 或 者 UTF8 编 码 , 又 或 者 你 的 本 地 编 码(Windows 的 代 码 页 ), 比 如 :VarS1:string;S2:string;S3:string;BeignS1 := " 汉 字 "; // 在 编 辑 器 直 接 输 入 , 是 UTF8S2 := UTF8ToAnSI(" 汉 字 ");// 根 据 当 前 代 码 页S3 := UTF8ToCP936(" 汉 字 ");// 无 论 当 前 代 码 页 是 什 么 , 转 换 成 GB2312 , 或Gb18030<strong>Lazarus</strong> 对 所 有 代 码 页 , 实 现 了 集 中 的 转 换 , 可 以 参 考 asiancodepages.inc,asiancodepagefunctions.inc,lconvencoding.pas 等 几 个 单 元 , 对 于 linux 系 , 可 以直 接 呼 叫 操 作 系 统 的 iconvert 例 程 , 否 则 可 以 直 接 使 用 lazarus 自 己 的 实 现 方 式 。伟 大 的 工 作 , 比 如Asiancodepagefunctions.inc 定 义 了function UTF8ToCP936(const s: string): string;beginResult := UTF8ToDBCS(s, @UnicodeToCP936);end;而 UTF8ToDBCS 又 定 义function UTF8ToDBCS(const s: string;


const UTF8CharConvFunc: TUnicodeToCharID): string;varlen:Src:integer;PChar;Dest: PChar;c: char;Unicode: longword;CharLen: integer;i: integer;beginif s = '' thenbeginResult := '';exit;end;len := length(s);SetLength(Result, len); // DBCS needs at most space as UTF-8Src:= PChar(s);Dest := PChar(Result);repeatc := Src^;if c < #128 thenbeginif (c=#0) and (Src-PChar(s)>=len) then break;Dest^ := c;Inc(Dest);Inc(Src);endelsebegin


Unicode := UTF8CharacterToUnicode(Src, CharLen);Inc(Src, CharLen);i := UTF8CharConvFunc(Unicode);//writeln(Format('%X', [i]));if i >= 0 thenbeginif i > $ff thenbeginDest^ := chr(i shr 8);Inc(Dest);Dest^ := chr(i);endelseDest^ := chr(i);Inc(Dest);end;end;until false;//SetLength(Result, Dest - PChar(Result));SetLength(Result, {%H-}PtrUInt(Dest) - PtrUInt(Result));end;呼 叫 一 个 过 程 ;function UnicodeToCP936(Unicode: cardinal): integer;begincase Unicode of0..127: Result := Unicode;elseResult := CP936CU[SearchTable(Uni936U, Unicode)];end;end;


这 个 过 程 主 要 就 调 用 了 SearchTable 这 个 函 数 ,function SearchTable(CodePageArr: array of word; id: cardinal): word;varidMid: integer;idLow, idHigh: integer;beginidLow := 0;idHigh := High(CodePageArr);while (idLow id thenidHigh := idMid - 1;


if CodePageArr[idMid] < id thenidLow := idMid + 1;end;Result := 0;end;先 在 Uni936U 查 到 信 息 , 再 作 为 CP936CU 这 个 数 组 下 标 , 查 到 数 据 。 所 以实 际 上 GB18030 也 是 部 分 支 持 的 。比 如 上 面 字 符 就 是 一 个 GB18030 字 符 ,unicode 编 码 3403 , 当 我 们 安 装 了Windows XP 的GB18030 支 持 包 , 并 且 新 建 一 个 工 程 , 将 其 输 入 到 我 们 的 控 件 上 , 可 以 看 到效 果 。可 见 <strong>Lazarus</strong> 的 代 码 编 辑 器 , 属 性 编 辑 器 是 支 持 此 编 码 的 。小 小 的 遗 憾 是 , 窗 体 标 题 没 有 支 持 。


第 四 十 二 章 GB18030,UNICODE,UTF-8Firebrid 从 2.5 版 开 始 支 持 GB18030 字 符 集 。这 是 国 家 标 准 , 将 来 必 定 需 要 支 持 。不 过 现 在 大 多 数 支 持 这 一 标 准 的 方 法 都 是 间 接 的 , 比 如 升 级 操 作 系 统 , 进 行编 码 转 换 。 这 一 字 符 集 是 Unicode 的 映 射 , 可 以 通 过 转 换 到 Unicode 进 行 支 持 。中 文 字 符 编 码 涉 及 到GB/T2311-2000GB 2312-1980GB/T11383-1989GB 12345-1990GB 13000.1-1993GB 18030-2000 强 制 性 标 准GB 18030-2005<strong>Lazarus</strong> 编 码 支 持 情 况 ,<strong>Lazarus</strong> 1.0 支 持 CP936 代 码 页 直 接 转 换 到 unicode。也 就 是 Windows 支 持 的 GBK, 中 国 国 家 标 准 GBK1.0, 对 于 GB18030-2000,Windows2000/XP 有 支 持 包 。<strong>Lazarus</strong> 能 部 分 支 持 。我 们 再 来 看 <strong>Lazarus</strong> 对 UTF8 的 支 持 情 况 , 主 要 在 这 个 函 数 :function UnicodeToUTF8Inline(CodePoint: cardinal; Buf: PChar): integer;begincase CodePoint of0..$7f:beginResult:=1;Buf[0]:=char(byte(CodePoint));end;$80..$7ff:begin


Result:=2;Buf[0]:=char(byte($c0 or (CodePoint shr 6)));Buf[1]:=char(byte($80 or (CodePoint and $3f)));end;$800..$ffff:beginResult:=3;Buf[0]:=char(byte($e0 or (CodePoint shr 12)));Buf[1]:=char(byte((CodePoint shr 6) and $3f) or $80);Buf[2]:=char(byte(CodePoint and $3f) or $80);end;$10000..$10ffff:beginResult:=4;Buf[0]:=char(byte($f0 or (CodePoint shr 18)));Buf[1]:=char(byte((CodePoint shr 12) and $3f) or $80);Buf[2]:=char(byte((CodePoint shr 6) and $3f) or $80);Buf[3]:=char(byte(CodePoint and $3f) or $80);end;elseResult:=0;end;end;我 们 可 以 看 到 其 对 unicode 最 大 支 持 $10ffff , 也 就 是 二 进 制100001111111111111111, 大 约 21 位 ,111 万 4111 个 码 位 。而 GB18030 定 义 的 是 161 万 1668 个 码 位 , 当 前 映 射 到 unicode 最 大 2FFFF,可 见 在 内 码 上 是 支 持 的 , 但 要 IDE 支 持 还 比 较 麻 烦 , 首 先 synedit 没 有 支 持GB18030 的 Windows 新 扩 展 函 数 , 并 且 lazarus 底 层 没 有 直 接 提 供 新 的 代 码 页(CP54936) 的 转 换 。


但 是 对 于 GBK 的 支 持 已 经 基 本 到 位 。 一 些 小 BUG 可 以 参 考 本 书 其 他 章 节 。


第 四 十 三 章 RichMemo 编 辑 器RTF 格 式 处 理 是 常 见 功 能 , 使 用 其 RichMemo1.LoadRichText(fs); 不 能 使 用RichMemo1.Lines.LoadFromFile('test2.rtf');也 不 能 使 用RichMemo1.Lines.SaveToFile('test2.rtf');这 样 保 存 出 来 的 是 去 掉 RTF 格 式 信 息 的 纯 文 本 格 式 , 格 式 是 UTF-8 的 。这 个 版 本 包 含 了 最 新 4.1 版 本 的 Windows RTF 控 件 。另 外 有 一 个 RichText 是 用 的 类 似 HTML 的 格 式 进 行 处 理 , 不 过 他 是 基 于FPGUI 的 另 外 一 种 模 式 , 是 采 用 代 码 生 成 界 面 , 非 可 视 化 设 计 , 类 似 C 的 开 发方 法 , 但 程 序 比 较 小 , 库 还 不 太 成 熟 , 是 个 第 三 方 开 发 库 。


第 四 十 四 章MySQL为 什 么 是 Firebird, 不 是MySQL 数 据 库 用 户 很 多 , 据 一 些 用 户 反 应 , 长 期 使 用 mySQL 总 是 发 现 出现 一 些 垃 圾 数 据 。 那 么 我 们 来 看 看 FireBird 和 MySql 的 对 比 。1. 安 装Mysql 5.1 安 装 >=56MBFirebird2.1 安 装


Firebird 有 数 据 库 热 备 份 , 增 量 备 份 , 影 子 数 据 库 (Shadow File, 一 个 一 模 一 样的 库 );假 如 有 A 数 据 库 , 有 影 子 数 据 库 B, 如 果 A 数 据 库 损 坏 , 执 行 激 活 指 令 ,B自 动 替 代 A 工 作 ,B 作 为 主 数 据 库 , 并 且 自 动 生 成 影 子 数 据 库 C;7. 数 据 复 制 方 面MySQL 支 持 单 向 数 据 库 复 制 ;FireBird 支 持 双 向 同 步 复 制 + 双 向 非 同 步 复 制 ;软 件 有 IBReplicator, 是 官 方 最 好 ,FBReplicator 开 源 版 ,FiBRE 开 源 , 跨 平台 ,ReplicadorBR 等 。8.SQL 标 准 支 持Mysql 许 多 支 持 不 是 任 何 一 个 标 准 ;FireBird 支 持 大 部 分 Sql92, 部 分 sql99;9. 最 先 开 发 目 的mysql 个 人 发 起 的 项 目 , 为 了 存 储 简 单 网 络 后 台 数 据 ;FireBird, DEC 公 司 关 系 数 据 库 项 目 , 提 供 高 可 靠 的 商 业 数 据 库 引 擎 ;10. 字 符 集Mysql 库 , 表 , 字 段 , 连 接 , 多 个 地 方 都 需 要 设 定 字 符 集 , 容 易 乱 码 ;Firebird 选 择 默 认 字 符 集 , 然 后 其 他 地 方 继 承 ;当 然 ,Mysql 的 存 在 也 是 有 一 些 道 理 的 , 作 为 一 个 开 源 数 据 库 , 离 不 开 开 发 者 的 支 持 。正 如 Linux 的 发 行 版 , 可 以 满 足 各 种 类 型 的 灵 活 需 求 ;


第 四 十 五 章 国 际 化 --I18N 与 <strong>Lazarus</strong>什 么 是 I18N 和 L10N ?I18N 是 internationalization 的 缩 写 形 式 , 意 即 在 i 和 n 之 间 有 18 个 字母 , 本 意 是 指 软 件 的 “ 国 际 化 ”; 与 之 类 似 ,L10N 是 localization 的 缩 写 形 式 ,意 即 在 l 和 n 之 间 有 10 个 字 母 , 本 意 是 指 软 件 的 “ 本 地 化 ”。自 己 编 写 一 个 可 以 更 换 语 言 的 程 序 步 骤 如 下 :1. 新 建 工 程 ;2. 设 置 工 程 的 i18n 属 性 为 允 许 ;3.Lfm 文 件 的 字 符 串 资 源 会 自 动 生 成 PO 文 件 ;4. 对 于 代 码 里 面 , 我 们 需 要 用 一 个 类 似 函 数 的 东 东 _( ) 将 我 们 需 要 国 际 化 的信息 括 起 来 。5. 单 元 里 面 引 用 defaultTranslator6. 保 存 工 程 , 会 自 动 生 成 PO 文 件7. 用 poEdit, 编 辑 这 个 文 件 , 保 存 为 aaa.xxx.po 的 名 字 ,xxx 是 语 言 代 码 ;<strong>Lazarus</strong> IDE 就 是 用 了 这 种 技 术 ; 他 会 自 动 翻 译 lcl 的 标 准 控 件 的 字 符 串 ;


第 四 十 六 章 synEdit 字 符 渲 染 宽 度最 终 调 用 在 synEditTextDoubleWidthChars.pasTSynEditStrings.DoGetPhysicalCharWidths当 前 版 本 对 中 文 输 入 法 的 软 键 盘 数 字 序 号 或 其 他 一 些 字 符 支 持 有 问 题 。 我 们只 需 要 在 这 个 函 数 添 加 支 持 。 当 前 主 要 支 持 GBK 字 符 集 以 及 其 他 东 方 双 宽 度 字符 集 。对 于 GB18030-2000 ,GB18030-2005 没 有 支 持 。 如 果 查 出 其 utf-8 字 符 , 其 实也 是 可 以 / 部 分 可 以 支 持 的 。 本 书 的 demo 源 码 支 持 了 这 个 版 本 的 补 丁 。但 是 synedit 自 己 智 能 化 的 将 俄 语 占 用 宽 度 成 了 单 宽 度 , 小 写 字 符 还 行 , 大写 字 符 似 乎 不 够 , 该 补 丁 支 持 这 些 字 符 :αβγδεζηθικλμνξοπρστυφχψωΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩабвгдеёжзийклмнопрстуфхцчшщъыьэюяㄅㄉˇˋㄓˊ˙ㄚㄞㄢㄦㄆㄊㄍㄐㄔㄗㄧㄛㄟㄣㄇㄋㄎㄑㄕㄘㄨㄜㄠㄤㄈㄌㄏㄒㄖㄙㄩㄝㄡㄥāáǎàōóòêēéěèīíǐìūúǔùǖǘǚǜüぁぃぅぇぉかきくけこんさしすせそたちつってとゐなにぬねのはひふへほゑまみむめもゃゅょゎをあいうえおがぎぐげござじずぜぞだぢづでどぱぴぷぺぽばびぶべぼらりるれろやゆよわァィゥヴェォカヵキクケヶコサシスセソタチツッテトヰンナニヌネノハヒフヘホヱマミムメモャュョヮヲアイウエオガギグゲゴザジズゼゾダヂヅデドパピプペポバビブベボラリルレロヤユヨワ 。,、;: ? ! …—·ˉˇ¨‘’“”々~‖∶" ' ` | 〃〔 〕〈 〉《 》「 」『 』.〖 〗【 】( )[ ]{ } ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫ⒈⒉⒊⒋⒌⒍⒎⒏⒐⒑㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛12345678910⑾⑿⒀⒁⒂⒃⒄⒅⒆⒇≈≡≠=≤≥≮≯∷±+-×÷/∫∮∝∞∧∨∑∏∪∩∈∵∴⊥∥∠⌒⊙≌∽√°′″$£¥‰%℃¤¢ 〇 一 二 三 四 五 六 七 八 九 十 百 千 万 亿 兆 吉 太 拍艾 分 厘 毫 微 ┌┍┎┏┐┑┒┓─┄┈├┝┞┟┠┡┢┣│┆┊┬┭┮┯┰┱┲┳┼┽┾┿╀╁╂╃└┕┖┗┘┙┚┛━┅┉┤┥┦┧┨┩┪┫┃┇┋┴


┵┶┷┸┹┺┻╄╅╆╇╈╉╊╋§№☆★○●◎◇◆□■△▲※→←↑↓〓#&@\^_ ̄―♂♀实 际 上 汉 语 拼 音 的 带 音 调 字 符 āáǎàōóòêēéěèīíǐìūúǔùǖǘǚ 应 该 占 单 宽 度 。实 际 上 , 这 个 代 码 实 现 的 是 utf8 版 本 的 unicode 字 符 宽 度 , 相 当 于 b 树 的 条件 判 断 , 从 而 避 免 了 用 一 个 数 组 来 记 录 字 符 宽 度 对 照 表 。 相 当 于 一 个 优 化 了 的 对照 表 。 其 实 也 可 以 采 用 转 换 到 unicode, 移 植 c 语 言 的 通 用 判 断 unicode 字 符 集 宽度 的 算 法 , 更 加 简 洁 ( 注 : 由 于 unicode 字 符 集 不 断 变 化 新 的 版 本 , 要 做 到 完 全 正确 , 只 能 不 断 适 应 新 的 版 本 变 化 ) , 笔 者 已 经 实 现 移 植 , 可 以 在 fpccn.com 下 载 。


第 四 十 七 章 Pascal 与 C 语 言为 什 么 学 习 Pascal 语 言 ?C 语 言 是 非 常 好 的 语 言 , 很 灵 活 , 很 接 近 汇 编 语 言 ; 但 以 前 的 数 据 结 构 方 面的 数 据 , 算 法 书 籍 都 采 用 Pascal/ 类 pascal 语 言 , 为 什 么 呢 ? Pascal 是 第 一 个 完整 实 现 结 构 化 编 程 的 语 言 , 现 在 任 何 语 言 的 核 心 任 然 是 他 ,Pascal 更 接 近 自 然 语言 英 语 , 用 其 描 述 算 法 , 非 常 容 易 阅 读 。 注 释 大 约 少 写 50%。 而 C 语 言 符 号 较短 , 并 且 大 多 采 用 缩 写 方 式 , 是 因 为 当 时 计 算 机 内 存 、 外 存 很 小 , 导 致 遗 留 问 题 。C 发 展 时 间 最 长 , 所 以 积 累 了 大 量 可 用 库 , 并 且 大 多 数 系 统 都 支 持 。 这 是 有 历 史原 因 的 , 导 致 C 很 长 时 间 是 用 得 最 广 泛 的 语 言 。Pascal 语 言 主 要 是 有 C 的 灵 活 性 , 而 又 有 C 的 简 洁 性 , 缩 写 函 数 库 比 较 少 ,语 法 更 加 容 易 阅 读 ;比 如FOR I:= 1 to 10 doBEGINA := B+ C;END;即 使 没 有 学 过 编 程 序 的 人 也 大 致 知 道 意 思 ;而 C 的For(int i=1;i


6..9: Caption := 'High';0, 10..99: Caption := 'Out of range';elseCaption := '';end;C 语 法Switch(I){Case 1:Case 2:Case 3Case 4:Case5: Caption := 'Low';break;Case 6:Case 7:Case 8:Case9: Caption := 'High';break;Case 0:Case 10:..... // 这 里 省 略 X 行Case99: Caption := 'Out of range'defaultCaption := '';end;当 然 你 可 以 用 IF 语 句 , 下 面 就 说 :同 样 比 较 IF 语 句PascalIF ( a in [0..99,109,202] thenBeginA := b;


End;用 C 语 言If ( (a > 0 && a < 99) || a == 109 || a == 202 ){A = b;}本 来 是 同 级 , 结 果 看 起 来 是 组 合 。还 有 函 数 比 较C 语 言A := atoi(b);Pascal 语 言a := StrToInt(b);而 且 C 语 言 没 有 支 持 String 类 型 , 就 算 用 C++ 的 CString 也 是 非 常 老 火 。他 是 一 个 对 象 , 要 去 NEW, 不 是 由 编 译 器 透 明 支 持 的 。比 如String *p1 = new string();特 别 是 指 针 类 型 太 多 , 导 致 了 代 码 阅 读 性 很 低 ;比 如String & operator=(const char*);或 者 c 的Char ***p;而 另 外 一 个 语 言 走 另 外 一 个 极 端 , 完 全 没 有 指 针 , 连 Basic 语 言 都 有 的 数 据类 型 , 他 却 没 有 , 也 没 有 struct / record 类 型 。 一 个 简 单 的 数 据 类 型 都 要 用 。String s = Integer(1).toString();看 起 来 语 法 是 漂 亮 , 但 是 也 太 啰 嗦 了 。同 样 一 个 最 简 单 的 struct/RECORD 类 型 , 他 要 用Class VOmyvalue{Private String myname;Private integer myage;Public void setName(WhoName:string){


Myname = WhoName;}Public String getName();{Return (myname);}Public void setAge(age:integer){Myage = age;}Public integer getAge(){Return myage;}}果 然 够 装 的 :-(我 们 再 看 一 个 c 的 例 子if(foo(547,6,1)>=0.4){switch(dd) {case 0:switch(cc) {case0:a=1;break;case 1:a=1;break; }case 1:switch(cc) {case 0:a=1;break;}}}


else{a=2;}可 读 性 很 差 的 。尽 管 是 这 样 ,C 的 地 位 , 许 多 语 言 还 是 难 以 动 摇 的 。我 们 再 来 看 一 个 vc6 的 程 序 , 可 以 编 译 通 过 , 但 是 运 行 会 报 错 , 我 们 只 看 其语 法// Test.h: interface for the CTest class.////////////////////////////////////////////////////////////////////////#if!defined(AFX_TEST_H__1664630B_3FB1_43FA_8ADD_1ED368269052__INCLUDED_)#defineAFX_TEST_H__1664630B_3FB1_43FA_8ADD_1ED368269052__INCLUDED_#if _MSC_VER > 1000#pragma once#endif // _MSC_VER > 1000//#include "stdafx.h"#include "afx.h"class CTest{private:CString name;int m_age;int m_weight;public:int getWeight();


CTest();virtual ~CTest();int getAge();};#endif //!defined(AFX_TEST_H__1664630B_3FB1_43FA_8ADD_1ED368269052__INCLUDED_)// 上 面 是 头 文 件 , 相 当 于 lazarus 的 实 现 节 前 面 的// 下 面 是 实 现 , 相 当 于 lazarus 的 实 现 节// Test.cpp: implementation of the CTest class.////////////////////////////////////////////////////////////////////////#include "Test.h"//////////////////////////////////////////////////////////////////////// Construction/Destruction//////////////////////////////////////////////////////////////////////CTest::CTest() // 构 造 函 数 , 不 知 道 规 则 , 就 看 不 懂 , 而 lazarus 很 明 白 ,create +constructor 描 述{}CTest::~CTest() // 这 个 用 destructor 描 述 更 加 好{}CTest::getAge() // 两 个 :, 后 面 版 本 的 语 言 还 有 ::: 够 繁 琐 了 吧{returnm_age;}int CTest::getWeight(){


for(int i=1;i


第 四 十 八 章 <strong>Lazarus</strong> 的 多 层 应 用 开 发Delphi 有 Datasnap 实 现 多 层 应 用 , 尽 管 许 多 人 诟 病 其 效 率 和 不 安 全 性 , 毕 竟 有 解 决 方案 。 许 多 人 会 问 那 么 lazarus 可 以 如 何 实 现 多 层 应 用 呢 ?我 们 来 看 一 个 多 层 控 件 RealThinClient3.32FS 最 后 免 费 版 本 。 当 然 你 也 可 以 购 买 最 新 跨iOS 的 新 版 本 。首 先 我 们 将 其 安 装 , 其 代 码 对 于 本 版 本 lazarus 有 些 BUG, 我 们 将 其 找 出 并 修 复 。安 装 完 毕 , 可 以 运 行 其 <strong>Lazarus</strong>_AppServer<strong>Lazarus</strong>_AppClient两 个 demo 实 现 远 程 RPC。将 其 服 务 端 结 合 ZeosDBO, 写 出 数 据 库 连 接 池 , 就 可 以 实 现 自 己 手 工 打 造 的 多 层 应 用 ,不 需 要 indy, 也 不 需 要 ado, 不 需 要 midas 的 任 何 东 西 。 甚 至 他 还 自 带 了 script 引 擎 。有 图 为 证 。


在 此 测 试 程 序 中 , 采 用 了 大 量 远 程 调 用 , 传 递 大 量 信 息 , 其 内 存 占 用 计 算 有


点 问 题 , 实 际 占 用


第 四 十 九 章 Firebird 语 法 概 要Firebird2.5 版 本 规 定Update table1 set a=1,b=a where a=2这 样 的 语 句 , 以 前 默 认 b 是 不 受 到 A 变 化 影 响 的 , 而 新 版 本 根 据 国 际 标 准是 要 影 响 的 。 如 果 不 需 要 这 个 特 性 , 可 以 在 配 置 文 件 关 闭 , 或 者 改 变 语 句 赋 值 顺序 。Select 语 句 支 持 子 语 句 ( 衍 生 表 ) 作 为 别 名 表 比 如Select * from (select * from table1) as b这 样 的 语 法老 版 本 不 支 持 。Select 的 left join,right join ,inner join 都 支 持 。注 意 空 值 扩 散 问 题 。CREATE TABLE test(a numeric(18,5) ,b float);insert into test(a) values(10);insert into test(a) values(null);select sum(a+b) from test;如 果 a 字 段 有 1 个 记 录 的 值 是 null, 那 么 返 回 合 计 是 null, 所 以 要 用Case 进 行 转 换Select sum(case a when null then 0 else a end + case b when null then 0 else b end)from testFirebird 数 据 类 型INTEGER: 长 整 型 , 取 值 范 围 :-2147483648 至 2147483647


FLOAT: 单 精 度 浮 点 型 , 取 值 范 围 :1.175*10- 38 至 3.402*10 38DOUBLE PRECISION: 双 精 度 浮 点 型 , 取 值 范 围 :2.225*10 -308 至 1.797*10 308DECIMAL: 小 数 型 , 可 指 定 有 效 位 数 最 大 为 18 位 或 小 数 点 后 18 位 。 比 如DECIMAL(5,2), 就 是 指 有 5 位 数 字 , 不 含 小 数 点 , 形 如 123.45NUMERIC: 小 数 型 , 与 DECIMAL 类 似 , 稍 后 讲 它 们 的 区 别 。注 意 , 当 数 据 含 小 数 部 分 时 , 请 尽 量 用 DECIMAL, 因 为 浮 点 型 有 精 度 问 题 , 除非 数 值 特 别 大 , 才 用 浮 点 型 !DECIMAL 与 NUMERIC 的 区 别 :比 如 ,DECIMAL(5,2) 与 NUMERIC(5,2) 所 分 别 定 义 的 字 段 ,DECIMAL(5,2) 指 的是 至 少 有 5 位 数 字 , 还 可 以 更 多 ! 而 NUMERIC(5,2) 指 的 是 , 就 是 5 位 , 不 多 也不 少 。SMALLINT: 短 整 型 , 取 值 范 围 :-32768 至 32767, 数 值 确 定 比 较 小 时 , 可 以 使用 , 可 以 节 省 磁 盘 空 间 与 提 升 效 率 , 相 当 于 Pascal 的 smallint;CHAR: 字 符 型 , 最 多 32767 个 字 符 , 注 意 , 使 用 CHAR 类 型 , 即 使 字 符 数 没 有达 到 指 定 字 段 的 宽 度 , 也 会 用 空 字 符 补 满 ! 取 值 时 , 请 注 意 用 TRIM() 等 函 数 去掉 多 余 空 字 符 。 除 非 确 定 每 条 记 录 的 字 符 数 不 变 , 否 则 请 用 VARCHAR 类 型 。VARCHAR: 可 变 长 度 字 符 型 , 最 多 32767 个 字 符 , 存 储 时 , 会 根 据 内 容 长 度 自动 改 变 存 储 位 数 , 不 会 产 生 多 余 空 字 符 。 当 字 符 数 超 过 32767 时 , 请 用 BLOB型 。


TIME: 时 间 型 , 取 值 范 围 :00:00 至 23:59.9999TIMESTAMP: 日 期 时 间 型 , 取 值 范 围 : 公 元 100 年 1 月 1 日 至 公 元 32768 年 2 月29 日 , 同 时 包 含 日 期 与 时 间 信 息 。 相 当 于 SqlServer 的 DateTime 和 <strong>Lazarus</strong> 的DateTimeDATE: 日 期 型 , 取 值 范 围 : 公 元 100 年 1 月 1 日 至 公 元 32768 年 2 月 29 日 。,注 意 , 建 库 时 需 选 择 DIALECT 3 级 别 才 支 持 DATE 型 , 否 则 就 是 TIMESTAMP型 。BLOB: 大 二 进 制 型 , 可 支 持 Text( 文 本 )、Binary Data( 二 进 制 型 , 比 如 图 片 , 声音 等 ) 等 子 类 型 。 取 值 范 围 :64KB 以 内 。 相 当 于 SqlServer 的 Image 类 型 。BOOLEAN: 逻 辑 型 ,Firebird 2.0 引 入 的 新 类 型 。 取 值 范 围 :TRUE( 值 ) 或FALSE( 假 )。 使 用 BOOLEAN 而 不 用 SMALLINT 的 理 由 是 可 以 用 更 少 的 位 数 来存 储 , 而 且 与 SQL 标 准 兼 容 , 但 是 , 数 据 将 与 1.5 版 本 不 兼 容 。


第 五 十 章 ZeosDBO 精 要创 建 数 据 库 , 其 属 性TZconnection 负 责 连 接 到 何 种 数 据 库 , 本 身 通 过 一 些 特 定 的 方 法 可 以TransactionIsolationLevel 是 指 事 务 级别 , 一 般 我 们 选 择 tiReadCommitted 就 可 以 了 , 是 指 的 读 提 交 过 的 , 其 他 用 户 未提 交 的 事 务 相 关 数 据 不 读 。 而 tiReadUncommitted 允 许 脏 读 ,tiRepeatableRead相 当 于 Firebird 的 snapshot 就 是 " 快 照 " 只 读 出 某 个 事 务 ID 的 值 , 之 后 影 响 的 不 管 ,得 益 于 Firebird 历 来 的 多 代 体 系 。在 这 个 事 务 级 别 , 其 他 用 户 无 论 做 任 何 操 作 , 都 不 会 被 这 个 用 户 影 响 , 在 一个 软 件 系 统 中 , 我 们 甚 至 可 以 在 决 策 支 持 模 块 ( 读 大 量 数 据 ), 单 独 用 一 个connection 做 这 个 级 别 的 读 , 达 到 领 导 看 到 某 时 间 点 的 数 据 的 快 照 , 是 准 确 的 。而 其 他 用 户 还 是 用 默 认 的 隔 离 级 别 继 续 自 己 的 任 务 。 不 受 任 何 影 响 。 笔 者 自 己 做了 一 个 模 拟 , 让 A 用 户 执 行 快 照 级 别 读 操 作 , 并 且 在 事 务 中 间 挂 起 。 另 外 一 个用 户 执 行 各 种 操 作 , 不 会 像 很 多 数 据 库 哪 像 被 锁 住 。TZQuery, 查 询 控 件 , 相 当 于 其 他 数 据 集 的 query,table,dataset, 主 要 的 控件 。 支 持 使 用 cachedupdate 模 式 , 结 合 自 己 的 TZUpdateSQl 实 现 , 自 动 将 变 化 数据 生 成 CRUD 指 令 , 执 行 自 动 更 新 。Tzreadonlyquery, 上 面 控 件 的 只 读 版 本 , 对 许 多 数 据 库 进 行 了 优 化 处理 , 只 读 就 意 味 着 会 采 用 尽 量 少 的 锁 定 。 不 能 执 行 post,delete,update 等 操 作 , 不支 持 cachedupdate, 不 支 持 TZupdatesql;


TZTable 和 其 他 数 据 集 差 不 多 。 不 过 他 也 支 持 TZUpdatesQLTZStoredproce 存 储 过 程 调 用 的 控 件 。TZSQLProcessor 执 行 多 个 SQL 语 句 , 中 间 用 ; 分 割 , 也 可 以 自 己 定 义分 割 符 ;TZSQLMonitor 监 视 程 序 发 出 的 指 令 。 可 以 写 入 文 件 。7.0 版 本 特 别 提 供 了 PostgreSQL 的 事 件 通 知 控 件 , 还 有 Firebird 的 事 件 通 知控 件 。我 们 知 道 ADO 的 控 件 很 繁 琐 , 特 别 是 参 数 输 入 。Adoquery.parameters.parambyname('tt').value := a;很 长 , 而 且 很 多 控 件 的 表 达 方 法 都 不 同 。那 么 使 用 ZEOS 呢 ?Zquery1.parambyname('tt').value := a;很 方 便 。这 也 就 让 我 们 编 写 程 序 的 风 格 得 到 统 一 , 也 就 是 说 相 当 于 某 些 语 言 的 DAO对 象 层 。平 滑 了 数 据 库 访 问 层 的 风 格 。而 TZupdateSQL 还 有 自 动 生 成 CRUD 语 句 的 可 视 化 编 辑 器 , 首 先 我 们 放 一个 TZupdatesql 到 form, 设 置 一 个 query 的 updatesql 属 性


其 中 的 wheremode 为wmWhereAll 表 示 按 用 户 设 置 的 update 条 件 进 行 更 新 。wmWhereKeyOnly 将 自 动 读 出 数 据 库 的 主 关 键 字 , 作 为 条 件 进 行update/delete 操 作 。在 其 上 面 鼠 标 右 键 弹 出 快 捷 菜 单 , 选 择 update sql editor这 里 会 自 动 分 析 我 们 的 复 杂 sql 语 句 , 找 出 可 以 更 新 的 表 , 然 后 我 们 选 择 key


fields 作 为 更 新 的 依 据 ,update fields 选 择 我 们 需 要 更 新 的 字 段 , 点 击 GenerateSQL 就 自 动 生 成 三 个 语 句 。这 个 语 句 告 诉 TZquery1, 更 新 table1, 包 括 table1 的 id,cname 字 段 , 条 件 是 库中 记 录 id 自 段 为 最 近 读 取 得 到 的 老 的 ID 值 , 这 和 Borland 的 BDE 的 updatesql是 一 样 的 , 用 OLD_ 表 示 老 的 数 据 。 其 他 带 冒 号 (:) 的 是 新 数 据 。 其 他 语 句 是 类 似的 。当 然 Insert 是 没 有 条 件 的 , 只 要 在 数 据 集 里 面 新 建 了 的 行 , 都 会 自 动 insert.可 是 我 们 有 时 候 自 己 对 keyfield 进 行 了 编 辑 , 可 能 导 致 更 新 错 误 , 怎 么 办 呢 ?这 个 时 候 我 们 就 需 要 用 TZupdatesql 的 updatemode 为 umUpdaeAll 模 式 了 。


第 五 十 一 章 <strong>Lazarus</strong> 语 法 精 要第 1 节 Pascal 的 来 历我 们 知 道 <strong>Lazarus</strong> 的 核 心 编 译 器 是 GNU FreePascal, 经 过 多 年 的 发 展 , 此 编译 器 已 经 十 分 成 熟 。 那 么 要 编 写 基 于 <strong>Lazarus</strong> 的 应 用 程 序 , 最 核 心 的 还 是 要 学 习Pascal 语 法 。 否 则 你 只 能 布 置 一 下 界 面 。 学 习 软 件 开 发 , 需 要 掌 握 语 言 ,IDE,语 言 的 函 数 库 , 操 作 系 统 的 函 数 库 , 算 法 , 数 据 结 构 , 实 际 应 用 的 行 业 知 识 等 。<strong>Lazarus</strong> 只 是 IDE 的 部 分 。Pascal - 发 音 帕 斯 卡Pascal 是 一 种 计 算 机 通 用 的 高 级 程 序 设 计 语 言 。 它 由 瑞 士 Niklaus Wirth 教 授( 生 于 :1934 年 2 月 15 日 ) 于 1968-1969 年 设 计 , 于 1970 年 发 布 。Pascal 也 可 以 是指 人 名 , 它 的 取 名 原 本 就 是 为 了 纪 念 十 七 世 纪 法 国 著 名 哲 学 家 和 数 学 家 BlaisePascal。 主 要 特 点 有 : 严 格 的 结 构 化 形 式 ; 丰 富 完 备 的 数 据 类 型 ; 运 行 效 率 高 ;查 错 能 力 强 。 Pascal 语 言 还 是 一 种 自 编 译 语 言 , 这 就 使 它 的 可 靠 性 大 大 提 高 了 。Pascal 具 有 简 洁 的 语 法 , 结 构 化 的 程 序 结 构 。 它 是 结 构 化 编 程 语 言 , 在 许 多 学 校计 算 机 语 言 课 上 都 是 Pascal 语 言 。 并 且 是 国 际 信 息 学 奥 林 匹 克 竞 赛 项 目 。Pascal 是 最 早 出 现 的 结 构 化 编 程 语 言 , 具 有 丰 富 的 数 据 类 型 和 简 洁 灵 活 的 操作 语 句 , 适 于 描 述 数 值 和 非 数 值 的 问 题 。正 因 为 上 述 特 点 ,Pascal 语 言 可 以 被 方 便 地 用 于 描 述 各 种 算 法 与 数 据 结 构 。尤 其 是 对 于 程 序 设 计 的 初 学 者 ,Pascal 语 言 有 益 于 培 养 良 好 的 程 序 设 计 风 格 和 习惯 。IOI( 国 际 奥 林 匹 克 信 息 学 竞 赛 ) 把 Pascal 语 言 作 为 三 种 程 序 设 计 语 言 之 一 ,NOI( 全 国 奥 林 匹 克 信 息 学 竞 赛 ) 把 Pascal 语 言 定 为 唯 一 提 倡 的 程 序 设 计 语 言 , 在大 学 中 Pascal 语 言 也 常 常 被 用 作 学 习 数 据 结 构 与 算 法 的 教 学 语 言 。在 Pascal 问 世 以 来 的 三 十 余 年 间 , 先 后 产 生 了 适 合 于 不 同 机 型 的 各 种 各 样 版本 。 其 中 影 响 最 大 的 莫 过 于 Turbo Pascal 系 列 软 件 。 它 是 由 美 国 Borland 公 司 设计 、 研 制 的 一 种 适 用 于 微 机 的 Pascal 编 译 系 统 。 该 编 译 系 统 由 1983 年 推 出 1.0版 本 发 展 到 1992 年 推 出 的 7.0 版 本 , 其 版 本 不 断 更 新 , 而 功 能 更 趋 完 善 。


Turbo Pascal 语 言 是 编 译 型 程 序 语 言 , 它 提 供 了 一 个 集 成 环 境 的 工 作 系 统 ,集 编 辑 、 编 译 、 运 行 、 调 试 等 多 功 能 于 一 体 。 并 且 是 首 个 支 持 在 内 存 中 编 译 程 序的 编 译 器 , 这 在 当 时 简 直 就 是 不 可 能 完 成 的 任 务 , 并 且 附 带 了 字 符 编 码 表 查 找 工具 软 件 , 在 <strong>Lazarus</strong> 里 面 不 但 带 了 此 软 件 , 增 强 为 查 unicode16,utf8 的 版 本 , 当然 中 文 也 可 以 查 找 。Pascal 有 6 个 主 要 的 版 本 , 分 别 是 Unextended Pascal、Extended Pascal、Object-Oriented Extensions to Pascal、Borland Pascal、Delphi Object Pascal 和 最 新 的 GnuFreePascal 跨 平 台 版 本 。FreePascal 的 兼 容 模 式 分 为 普 通 Pascal , 面 向 对 象 Pascal 和 Delphi 兼 容 模式 。第 2 节 第 一 个 Pascal 程 序下 面 我 们 就 以 一 个 实 例 来 看 一 看 Pascal 程 序 的 结 构 , 感 性 认 识 Pascal 语 言 程序 的 编 写 方 式 。例 1: 输 入 一 个 圆 的 半 径 , 求 出 其 圆 周 长 。设 圆 的 半 径 为 R, 周 长 为 L, 我 们 知 道 公 式 如 下 :L=2πR它 的 Pascal 程 序 如 下 :program zhouchang( input, output) ; { 程 序 首 部 }const { 常 量 说 明 }pi=3.14159var { 变 量 说 明 }l,r:real;begin { 程 序 开 始 }readln(r); { 输 入 半 径 }l:=2*pi*r; { 计 圆 周 长 }writeln('l=',l); { 输 出 圆 周 长 }end. { 结 束 程 序 }从 以 上 简 单 的 例 子 可 以 看 出 ,Pascal 程 序 是 由 程 序 首 部 、 程 序 说 明 部 分 和 程序 执 行 部 分 组 成 。 具 体 如 下 所 示 :


program 程 序 名 ; { 程 序 首 部 }说 明 部 分 { 说 明 部 分 }begin { 程 序 开 始 }语 句 1; { 执 行 语 句 }语 句 2; { 执 行 语 句 }…… { 执 行 语 句 }end. { 结 束 程 序 }上 面 程 序 由 如 下 两 部 分 组 成 :1、 程 序 首 部程 序 首 部 是 程 序 的 开 头 部 分 , 由 保 留 字 program 后 , 接 程 序 名 及 程 序 参 数 表组 成 , 结 束 时 一 定 要 有 分 号 。 程 序 名 zhouchang 是 用 户 自 己 定 义 的 标 识 符 , 参 数表 一 般 是 文 件 变 量 名 , 用 于 该 程 序 与 外 界 的 数 据 交 流 。 最 常 用 的 参 数 为 input 和output。Pascal 程 序 首 部 中 参 数 表 可 以 省 略 。2、 程 序 说 明 部 分Pascal 语 言 要 求 用 户 将 在 程 序 中 所 使 用 的 标 号 、 常 量 、 类 型 、 变 量 、 记 录 、文 件 、 以 及 过 程 和 函 数 除 了 Pascal 自 己 预 先 定 义 的 标 准 量 之 外 , 都 必 须 在 说 明 部分 说 明 后 才 能 在 程 序 执 行 部 分 使 用 。 但 各 个 内 容 部 分 是 可 选 的 , 只 有 执 行 程 序 部分 需 要 的 时 候 才 进 行 说 明 。3、 程 序 执 行 部 分紧 接 着 说 明 部 分 的 begin 和 end 之 间 的 部 分 为 程 序 的 执 行 部 分 。 它 由 一 系 列语 句 组 成 , 一 条 语 句 执 行 一 定 的 功 能 , 所 有 语 句 完 成 程 序 设 计 的 任 务 。 语 句 之 间用 “;” 隔 开 , 允 许 一 行 写 多 个 语 句 , 也 允 许 一 个 语 句 写 多 行 。 最 后 一 行 的 end后 加 “.” 号 表 示 结 束 。 所 跟 其 后 的 语 句 将 无 任 何 作 用 。Begin 与 end 应 配 对 出 现 ,这 是 每 一 个 Pascal 程 序 都 必 须 的 。注 意 : 后 面 将 学 习 到 的 语 句 中 , 也 需 要 引 用 begin 和 end 作 为 程 序 段 的 分 隔标 记 , 但 其 必 须 遵 守 语 句 规 则 。第 3 节数 据 类 型 、 常 量 的 变 量一 、 数 据 类 型 的 概 念计 算 机 处 理 数 据 对 象 是 一 个 广 义 的 概 念 。 例 如 ,125、12.76 是 数 据 ,’ 汉 字 ’


这 一 串 字 符 也 是 数 据 。 前 者 是 数 值 数 据 , 后 者 是 字 符 串 数 据 , 是 非 数 值 数 据 。 显然 , 为 了 表 示 这 些 数 据 , 它 们 在 内 存 中 必 须 以 不 同 方 式 存 放 。 为 处 理 这 些 数 据 ,计 算 机 对 它 们 施 加 的 运 算 也 不 同 。 为 此 ,Pascal 语 言 建 立 了 数 据 类 型 的 概 念 , 对描 述 的 数 据 进 行 分 类 。 每 一 种 数 据 类 型 定 义 了 一 个 具 有 相 同 性 质 的 数 据 集 合 。 各种 数 据 类 型 的 数 据 具 有 不 同 的 性 质 。 程 序 中 所 用 到 的 每 一 个 数 据 , 包 括 常 量 和 变量 都 有 一 个 和 它 相 联 系 的 类 型 。 由 此 决 定 了 数 据 所 具 有 的 值 , 也 决 定 了 对 该 数 据所 能 进 行 的 操 作 。Pascal 语 言 中 数 据 具 有 丰 富 的 类 型 , 按 它 们 的 特 点 可 以 分 为 简 单 类 型 、 构 造类 型 、 指 针 类 型 和 过 程 类 型 四 大 类 , 如 图 下 所 示 。其 中 , 标 准 类 型 用 语 言 系 统 预 先 定 义 的 标 准 标 识 符 表 示 , 整 型 用 integer 表示 , 实 型 用 real 表 示 , 布 尔 型 用 boolean 表 示 , 字 符 型 用 char 表 示 。二 、 常 量常 量 是 指 在 程 序 中 使 用 的 一 些 具 体 的 整 型 数 、 实 型 数 和 字 符 串 。(1) 整 型 数 : 如 9、3、-5、0 等 。(2) 实 型 数 : 如 3·1、-6.1E+20 等 。(3) 字 符 串 : 是 用 单 引 号 括 起 来 的 一 串 字 符 , 如 ,’book’、’96·5’、’ABC’等 。以 上 列 举 的 都 可 以 作 为 常 量 在 程 序 中 使 用 。 为 了 提 高 程 序 的 可 读 性 并 使 程 序便 于 修 改 , 在 程 序 中 往 往 用 一 些 标 识 符 来 代 表 具 体 的 常 量 。在 Pascal 语 言 中 , 可 以 给 一 些 常 量 取 个 名 字 用 一 个 标 识 符 代 表 它 , 这 就 是 常量 定 义 。 例 如 ,Cost=60;Blank=’ ’。经 常 量 定 义 的 标 识 符 又 称 为 常 量 标 识 符 。在 Pascal 语 言 中 , 常 量 定 义 要 写 在 常 量 定 义 部 分 中 。常 量 定 义 部 分 的 一 般 形 式 :Const( 常 量 标 识 符 1)= ( 常 量 1);( 常 量 标 识 符 2)=( 常 量 2);( 常 量 标 识 符 n)=( 常 量 n);Const 是 保 留 宇 , 表 示 开 始 一 个 常 量 定 义 部 分 , 其 后 可 以 有 若 干 个 常 量 定 义 ,


这 些常 量 定 义 之 间 要 用 “;” 号 分 隔 。 例 如 :ConstCost=60;A=Cost+30;Pi =3.14159;Pascal 语 言 对 常 量 定 义 有 如 下 要 求 :(1) 常 量 定 义 要 放 在 程 序 的 常 量 定 义 部 分 , 即 程 序 首 部 之 后 , 执 行 部 分 之 前 。(2) 必 须 遵 循 先 定 义 后 使 用 的 原 则 , 即 只 有 已 经 定 义 的 常 量 标 识 符 , 才 能 在程 序 中使 用 。三 、 变 量在 程 序 执 行 过 程 中 其 值 可 以 改 变 的 数 据 , 称 为 变 量 。 每 个 变 量 都 要 有 一 个 名称 , 这 就 是 变 量 名 。 变 量 名 由 用 户 自 己 定 义 , 但 必 须 符 合 标 识 符 的 规 定 。在 一 个 程 序 中 , 一 个 变 量 只 能 属 于 一 种 确 定 的 数 据 类 型 。 因 此 , 程 序 中 出 现的 每 个 变 量 都 必 须 说 明 其 数 据 类 型 , 这 样 就 规 定 了 该 变 量 的 取 值 范 围 , 也 决 定 了对 该 变 量 所 能 执 行 的 运 算 操 作 。变 量 的 类 型 , 可 以 是 标 准 数 据 类 型 integer、real、boolean 和 char, 也 可 以 是用 户 自 定 义 的 各 种 类 型 。变 量 说 明 形 式 是 : 一 个 变 量 标 识 符 或 由 逗 号 隔 开 的 多 个 变 量 标 识 符 在 它 的 冒号 ":" 后 面 说 明 其 数 据 类 型 。在 Pascal 程 序 中 , 变 量 说 明 要 写 在 变 量 说 明 部 分 中 。变 量 说 明 部 分 的 一 般 形 式 :var( 变 量 说 明 1);( 变 量 说 明 2);……( 变 量 说 明 n);其 中 var 是 保 留 字 , 表 示 一 个 变 量 说 明 部 分 开 始 。 一 个 var 可 以 含 有 多 个 不同 的 变 量 说 明 , 每 个 变 量 说 明 之 间 用 分 号 隔 开 , 有 时 称 被 分 号 隔 开 的 变 量 说 明 为


变 量 说 明 项 。 例 如 :varx,y:real;chl:char;t,f:boolean;注 意 : 不 同 类 型 的 变 量 一 般 不 能 互 相 串 用 。这 里 还 应 指 出 , 变 量 一 经 说 明 系 统 就 在 计 算 机 内 存 中 为 其 分 配 一 个 存 贮 空间 。 在 程 序 中 使 用 到 变 量 时 , 就 在 相 应 的 内 存 中 存 入 数 据 或 取 出 数 据 , 这 种 操 作称 为 变 量 的 访 问 。标 准 数 据 类 型Pascal 向 程 序 设 计 者 提 供 了 丰 富 的 数 据 类 型 , 它 们 用 于 专 门 的 目 的 , 但 却 都是 由 简 单 的 、 非 构 造 型 的 数 据 类 型 所 构 成 的 。 本 节 介 绍 Pascal 中 最 为 基 本 的 几 种数 据 类 型 : 整 型 、 实 型 、 布 尔 型 和 字 符 型 。 它 们 都 是 系 统 定 义 的 简 单 数 据 类 型 ,称 为 标 准 数 据 类 型 , 其 对 应 的 名 字 称 为 标 准 标 识 符 。1、 整 型一 个 整 型 数 据 用 来 存 放 整 数 , 整 型 数 据 可 以 是 正 整 数 、 负 整 数 和 整 数 零 。Pascal 中 的 整 型 常 数 必 须 按 规 定 严 格 书 写 。Pascal 支 持 6 种 预 定 义 整 型 , 它 们 是 短 整 型 (Shortint)、 整 型 (Integer)、 长 整型 (Longint)、 字 节 型 (Byte) 和 字 类 型 (Word) 和 双 字 类 型 (longword), 每 一 种 类 型规 定 了 相 应 的 整 数 取 值 范 围 以 及 所 占 内 存 字 节 数 ( 一 个 字 节 为 8 个 二 进 制 位 )。 因此 , 用 户 在 具 体 编 程 定 义 变 量 类 型 时 , 要 根 据 它 们 的 特 点 选 用 适 当 的 类 型 , 以 达到 理 想 的 效 果 。 当 两 个 不 同 范 围 类 型 的 操 作 数 进 行 运 算 时 , 得 到 的 结 果 属 于 较 大范 围 的 类 型 。Pascal 语 言 规 定 可 以 对 整 型 数 据 进 行 算 术 运 算 符 +、 一 、*、Div、Mod。它 们 分 别 表 示 加 、 减 、 乘 、 整 除 和 取 余 。 这 五 种 运 算 , 要 求 参 加 运 算 的 两 个数 都 是 整 型 数 , 运 算 结 果 也 是 整 型 数 。 前 三 种 运 算 与 一 般 的 算 术 运 算 加 、 减 、 乘相 同 。Div 整 除 运 算 , 是 两 个 整 型 数 相 除 取 整 数 部 分 ( 商 的 整 数 部 分 ), 得 到 整 型结 果 。Mod 取 余 运 算 , 是 两 个 整 型 数 相 除 取 余 数 , 余 数 的 符 号 与 被 除 数 符 号 相同 。 例 如 :3 Div 2 = 1 5 Div 7 = 0


6 Div (-4) = - 1 (-12) Div (-5) = 27 Mod 4 = 3 (14) Mod (-4) = 2(-18) Mod (-6) = 0 6 Mod l7 = 6由 此 可 见 ,a Mod b, 所 得 结 果 的 符 号 与 a 相 同 , 其 值 ( 绝 对 值 ) 在 0~∣b∣-1之 间 。 运 算 符 Mod 与 Div 之 间 有 如 下 关 系 :a Mod b = a – (a Div b) * b (b0)其 中 Mod 运 算 的 结 果 的 符 号 与 a 的 符 号 相 同 。利 用 以 上 两 种 运 算 可 以 对 正 整 数 进 行 分 离 。 例 如 :n 为 四 位 数 8531, 可 用 下 法 分 离 出 它 的 个 、 十 、 百 、 千 位 。8531 Mod l0 = 1 ( 个 位 数 )(8531 Mod l00) Div l0 = 3 ( 十 位 数 )(8531 Mod l000) Div l00 = 5 ( 百 位 数 )8531 Mod l000 = 8 ( 千 位 数 )利 用 a Mod b 可 以 判 断 a 能 否 被 b 整 除 。 当 a Mod b = 0 时 ,a 能 被 b 整 除 。2、 实 型一 个 实 型 数 据 用 来 存 放 实 数 。 实 型 数 据 可 以 是 正 实 数 、 负 实 数 和 实 数 零 。 实型 数 据 一 般 用 小 数 或 指 数 形 式 ( 亦 称 科 学 表 示 法 ) 表 示 。 例 如 :+1993,33,3.5E+8(=3.5×105), -0.5E-3(=-0.5×10-3,),-20.0,, 0.0 等 都是 合 法 实 型 数 。Pascal 支 持 一 种 预 定 义 实 型 , 它 们 是 基 本 实 型 (Real)、 单 精 度 实 型 (Single)、双 精 度 实 型 (Double)、 扩 展 实 型 (Extended) 和 装 配 实 型 (Comp)。 每 一 种 类 型 规 定了 相 应 的 实 数 取 值 范 围 和 所 占 内 存 字 节 数 , 以 及 它 们 所 能 达 到 的 精 度 , 即 有 效 数字 位 数 。 因 此 , 用 户 在 具 体 编 程 时 应 根 据 以 上 的 参 数 适 当 选 用 , 以 达 到 最 佳 效 果 。如 下 表 所 示 。对 于 此 类 实 型 数 据 , 若 其 绝 对 值 大 于 上 界 , 则 产 生 上 溢 ; 绝 对 值 小 于 下 界 ,则 产 生 下 溢 , 下 溢 导 致 结 果 为 0。Comp 类 型 的 取 值 范 围 是 -263+1~238-1 之 间 的整 数 , 相 当 于 十 进 制 的 -9.218~9.218。 由 于 Comp 类 型 的 数 据 表 示 成 二 进 制 形 式的 数 , 这 种 类 型 的 变 量 有 时 处 理 起 来 比 较 方 便 , 特 别 对 于 数 值 很 大 的 整 数 间 的 计算 , 这 种 数 据 类 型 很 有 用 。


Pascal 语 言 允 许 实 型 数 使 用 下 列 运 算 符 进 行 运 算 。运 算 符 :+、-、*、/分 别 表 示 加 、 减 、 乘 和 除 。 其 中 "/" 叫 实 数 除 , 即 使 两 个 整 型 数 相 除 , 其 结 果也 总 是 实 型 , 如 : 7/2=3.5 6/3=2.03、 字 符 型用 标 准 标 识 符 Char 标 明 字 符 型 。 字 符 型 数 据 可 以 是 字 母 、 符 号 、 数 字 (0-9)等 ASCII 码 的 所 有 字 符 。Pascal 支 持 扩 展 ASCII 码 , 共 包 括 256 个 字 符 。 但 非 印刷 字 符 是 不 能 在 标 准 显 示 上 显 示 或 打 印 输 出 。 在 计 算 机 内 部 , 字 符 集 的 元 素 是 以该 元 素 在 字 符 集 内 的 顺 序 位 置 来 标 记 的 , 位 置 取 值 范 围 为 0~255, 我 们 称 这 些 整数 为 字 符 在 字 符 集 内 的 序 数 值 或 序 号 。 每 个 字 符 型 数 据 在 内 存 中 占 一 个 字 节 。 将字 符 用 单 引 号 括 起 来 , 即 成 字 符 常 数 , 如 ,’X’,’7’,’?’。 字 符 常 数 可 按 字 符的 序 数 值 确 定 大 小 关 系 , 也 就 是 说 它 们 的 大 小 由 它 们 所 对 应 的 ASCII 码 值 决 定 ,如 :’Y’,’Z’,’A’


longin–2147483648..2147483647 4 带 符 号 32t位longw0..4294967295 4 无 符 号 32 位ordcardinlongword的 别 名aldwordInt64 -8 带 符 号 64 位9223372036854775808..9223372036854775807qword 0..18446744073709551615 8 无 符 号 64 位4、 布 尔 型一 个 布 尔 型 数 据 用 来 存 放 逻 辑 值 , 或 称 布 尔 值 。Pascal 支 持 预 定 义 布 尔 型 ,以 标 准 标 识 符 Boolean 表 示 。Boolean 一 词 , 系 根 据 19 世 纪 英 国 数 学 家 Georgeboole (1815-1864) 的 名 字 而 得 ,George boole 为 现 代 布 尔 代 数 之 父 。 布 尔 型 数 据 的值 只 有 两 个 :True( 逻 辑 真 ) 和 False( 逻 辑 假 )。 布 尔 型 是 顺 序 类 型 , 规 定False


复 杂 数 据 类 型严 格 来 说 类 也 是 一 种 数 据 类 型 。Pascal 的 复 合 数 据 类 型 由 基 本 类 型 组 成 。Pchar 是 类 型 , 也 可 以 看 作 一 个 转 换 函 数Pchar 可 以 将 字 符 串 类 型 转 换 成 尾 巴 是 字 符 编 码 0 的 指 针 。 而 相 反 的 运 算 是Strpas那 么 unicode 的 转 换 是 punicodechar, 是 两 个 0 结 束 。Var p:pchar;S:string;BeginP := pchar(s);或 者 这 样 。Program three;Var S : String[30];P : PChar;beginS := ’This is a null-terminated string.’#0;P := @S[1];WriteLn (P);end.Pointer 本 身 类 型 ,, 也 可 以 看 作 一 个 强 制 转 换 函 数 。相 当 于 c 语 言 的 void 指 针 。 也 可 以 自 己 定 义 指 针 。Var s:ansistring;P:pointerBeginP:=pointer(s);Ansistring 才 能 这 样 转 换 。ArrayPascal 支 持 动 态 数 组 。 数 组 支 持 子 界 类 型 定 义 下 标 , 可 以 不 从 0 开 始 , 如 :Var a:array[1..2] of byte;


Set集 合 类 型 , 支 持 散 的 有 序 列 数 , 或 子 界 定 义 , 同 时 可 以 用 in 进 行 测 试 。If a in [#$20,#2,0..3] thenRecord记 录 类 型 , 就 是 c 下 面 的 struct, 不 过 有 变 化 , 可 以 支 持 变 体 的 记 录 , 用 来 做底 层 数 据 结 构 , 或 者 做 自 定 义 数 据 库 , 很 方 便 。 如 ;Type body=recodeAge :shortint;Name:string[50]End;File文 件 类 型 , 很 老 的 兼 容 类 型 , 现 在 一 般 都 用Tfilestream,TStringlist代 替 其 二 进 制 , 文 本 类 型 的 File.Variant变 体 类 型 , 主 要 是 由 编 译 器 实 现 的 根 据 具 体 类 型 进 行 管 理 的 特 别 类 型 , 用 来实 现 OLE/COM 程 序 , 特 别 是 数 据 库 基 本 必 须 使 用 的 , 使 得 程 序 编 写 更 加 方 便 。Procedure过 程 是 没 有 返 回 值 的 函 数 , 可 以 带 括 号 调 用 , 也 可 以 直 接 像 变 量 使 用 , 取 决于 你 高 兴 。类类 是 一 种 特 殊 的 复 杂 数 据 类 型 , 包 含 了 类 的 名 字 , 私 有 的 数 据 和 接 口 。 维 持了 继 承 等 的 VMT 虚 拟 方 法 表 等 数 据 。变 量 的 作 用 域变 量 的 作 用 域 分 全 局 , 局 部 和 线 程 。定 义 如Var a:string;在 implementation 前 面 的 变 量 , 我 们 称 之 为 全 局 变 量 。之 后 的 和 函 数 begin 前 面 的 变 量 , 为 局 部 变 量 。


全 局 变 量 在 引 用 他 的 单 元 可 以 访 问 , 而 局 部 变 量 只 在 本 单 元 或 函 数 体 内 有用 。类 的 成 员 变 量 部 分 我 们 可 以 通 过 实 例 对 象 直 接 操 作 , 有 的 需 要 通 过 属 性 或 者方 法 才 能 访 问 。Pascal 的 变 量 不 能 在 规 定 的 三 个 地 方 之 外 的 地 方 定 义 ( 而 object pascal 的 成员 变 量 也 可 以 算 作 这 一 类 ), 这 点 比 C 严 格 , 同 时 可 以 让 程 序 员 养 成 良 好 风 格 。分 类 树简 单类 型序 数整 数字 符布 尔Integer取 值 范 围-2147483648 ..2147483647Cardinal 0 .. 4294967295 4字节4说 明有 符 号 32位无 符 号 32位Shortint -128 .. 127 1 有 符 号 8 位Smallint -32768 .. 32767 2Longint-2147483648 ..2147483647Int64 -2 63 .. 2 63 84有 符 号 16位有 符 号 32位有 符 号 64位Byte 0 .. 255 1 无 符 号 8 位Word 0 .. 65535 2Longword 0 .. 4294967295 4AnsiChar(Char)ANSI 字 符 集无 符 号 16位无 符 号 32位8 位WideChar Unicode 字 符 集 16 位BooleanFalse < TrueOrd(False) = 0Ord(True) = 1Succ(False) = TruePred(True) = FalseByteBool False True 1WordBoolOrd(False) = 0Ord(True) 02LongBool Succ(False) = TruePred(False) = True41


字 符串结 构类 型实 数枚 举子 界Real 5.0×10 -324 .. 1.7×10 308 8Real48 2.9×10 -39 .. 1.7×10 38 6[ 精度 ]15..16[ 精度 ]11..12;向 后 兼 容Single 1.5×10 -45 .. 3.4×10 38 4 [ 精 度 ]7..8Double 5.0×10 -324 .. 1.7×10 308 8Extended[ 精度 ]15..163.6×10 -4951 ..1.1×10 4932 10 [ 精度 ]19..20Comp -2 63 + 1 .. 2 63 - 1 8CurrencyShortString 255 个 字 符StringAnsiStringunicodeStringWideString其 他-922337203685477.5808 ..922337203685477.5807大 约 2 31大 约 2 30个 字 符个 字 符StringString[0..255]PCharPAnsiStringPWideString集 合 Set 最 多 256 个 元 素 [0..255]数 组静 态82..256B4B..2GB4B..2GB[ 精度 ]19..20[ 精度 ]19..20向 后 兼 容8 位 (ANSI)字 符多 用 户 服 务和多 语 言 应 用程 序 ;和 com 定义 的 BSTR兼 容


数 组动 态数 组记 录Record文 件File类Class类 引 用Classreference接 口Interface无 类 型指 针Pointer指 针类 型有 类 型指 针预 定义 类型 指针PAnsiStringPStringPByteArrayPCurrencyPDoublePExtendedPSinglePIntegerPOleVariantPShortStringPTextBufPVarRecPVariantPWideStringPWordArray过 程类 型程 序 过程 类 型对 象 过程 类 型ProceduralProcedural变 体类 型VariantOleVariant


第 4 节函 数标 准 函 数 。Pascal 语 言 提 供 了 自 变 量 为 整 型 量 的 标 准 函 数 有 顺 序 函 数 算 术 函数 和 转 换 函 数 等 。标 准 函 数 是 Pascal 语 言 预 先 定 义 的 , 它 们 实 际 上 是 能 完 成 特 定 功 能 的 子 程 序的 程 序 段 。 每 个 标 准 函 数 都 用 一 个 标 识 符 来 标 识 , 每 个 标 准 函 数 都 能 完 成 一 个 特定 的 功 能 , 在 程 序 中 可 以 直 接 调 用 它 们 。Pascal 语 言 中 某 些 标 准 函 数 与 数 学 中 的函 数 有 相 似 之 处 。一 、 整 数 类 型 函 数整 型 是 顺 序 类 型 , 即 所 有 的 整 型 数 都 是 按 一 定 的 顺 序 排 列 的 。 如 3 的 后 序 数是 4,350 的 后 序 数 是 351。 以 后 介 绍 的 布 尔 型 、 字 符 型 、 枚 举 类 型 和 子 界 类 型等 都 是 顺 序 类 型 。 顺 序 函 数 可 以 对 顺 序 类 型 数 据 进 行 操 作 , 但 要 注 意 它 们 自 变 量的 取 值 范 围 。1 前 趋 函 数 :Pred(x) 函 数 值 为 x-l, 例 如 :Pred (6)=5 Pred (-21)=-222 后 继 函 数 :Succ (x) 函 数 值 为 x+l, 例 如 :Succ (l5)=16 Succ (-114)= -1133 绝 对 值 函 数 :Abs (x) 函 数 值 为 —X—, 例 如 :Abs (-119)=119 Abs (101)=1014 平 方 函 数 :Sqr (x) 函 数 值 为 X2, 例 如 :Sqr (-5)=,25 Sqr (l0)= 100以 上 四 个 函 数 的 结 果 仍 是 整 型 数 。5 奇 函 数 :Odd (x), 函 数 的 结 果 为 布 尔 型 。 当 X 为 奇 数 时 , 函 数 值 为 true;当 X 为 偶 数 时 , 函 数 值 为 false。 例 如 :Odd (13)= True Odd (16)= False6 字 符 函 数 :Chr (X), 函 数 值 是 序 号 的 ASCII 字 符 , 属 字 符 型 。 例 如 :Chr (65)=’A’ Chr (32)=’ ’二 、 实 数 类 型 函 数在 下 列 算 术 函 数 中 ,X 可 以 是 实 型 或 整 型 数 的 表 达 式 。 对 于 函 数 Abs 和 Sqr,


其 结 果 类 型 和 变 量 X 的 类 型 相 同 , 其 他 算 术 函 数 的 结 果 类 型 都 是 实 型 。绝 对 值 函 数 Abs(x): 函 数 值 为 x 的 绝 对 值平 方 函 数 Sqr (x): 函 数 值 为 x 的 平 方小 数 函 数 Frac (x): 函 数 值 为 x 的 小 数 部 分整 数 函 数 Int (x): 函 数 值 为 x 的 整 数 部 分正 弦 函 数 Sin (x): 函 数 值 为 x 的 正 弦 , 其 申 , 的 单 位 为 弧 度余 弦 函 数 Cos (x): 函 数 值 为 x 的 余 弦 , 其 中 , 的 单 位 为 弧 度指 数 函 数 Exp (x): 函 数 值 为 了 ex对 数 函 数 Ln (X): 函 数 值 为 x 的 自 然 对 数平 方 根 函 数 的 Sqrt (x): 函 数 值 为 x 的 平 方 根反 正 切 函 数 Arctan(x): 函 数 值 为 x 的 反 正 切 , 单 位 为 弧 度随 机 函 数 Random: 无 自 变 量 时 , 函 数 值 取 (0,1) 间 的 随 机 小 数 ; 有 自 变 量 且为 Word 类 型 时 , 函 数 值 取 (0, 自 变 量 ) 间 的 随 机 整 数 。三 、 字 符 类 型 函 数Pascal 语 言 提 供 如 下 自 变 量 为 字 符 型 的 标 准 函 数 , 其 中 Chr 为 字 符 型 。后 继 函 数 Succ (ch): 例 如 ,Succ ('8')='9' Succ ('E')='F'对 字 符 集 的 最 后 一 个 字 符 ,Succ 函 数 无 意 义 。前 趋 函 数 Pred (ch): 例 如 ,Pred ('7')='6' Pred ('B')=' A'序 数 函 数 Ord (ch):: 给 出 字 符 ch 在 ASCII 字 符 集 中 的 序 号 , 结 果 为 整 型 。注 意 :Ord ('7')7, 正 确 的 是 :Ord ('7')=Ord('0')+7=48+7=55若 ch 是 数 字 字 符 , 则 Ord (ch)-Ord ('0') 是 该 数 字 字 符 的 数 值 。 例 如 :Ord ('7')-Ord('0')=7前 面 介 绍 的 字 符 函 数 Chr (i) 是 Ord (ch) 的 逆 函 数 。 例 如 :Chr (55)= '7' Chr (Ord('A'))='A'三 、 布 尔 类 型 函 数Pascal 语 言 提 供 布 尔 型 函 数 主 要 是 几 个 字 符 型 函 数 。Ord (B) 例 如 :Ord (false)=0 Ord (true)=1第 5 节表 达 式运 算 是 对 数 据 进 行 加 工 处 理 的 过 程 , 得 到 运 算 结 果 的 数 学 公 式 或 其 它 式 子 统


称 为 表 达 式 。 表 达 式 可 以 是 常 量 也 可 以 是 变 量 或 算 式 , 在 表 达 式 中 又 可 分 为 : 算术 表 达 式 、 逻 辑 表 达 式 和 字 符 串 表 达 式 。1、 算 术 表 达 式 :算 术 表 达 式 是 最 常 用 的 表 达 式 , 又 称 为 数 值 表 达 式 。 它 是 通 过 算 术 运 算 符 来进 行 运 算 的 数 学 公 式 。 我 们 先 来 看 Visual Basic 中 的 算 术 运 算 符 :算 术 运 算 符运 算 符 表 达 式 说 明 举 例* X*Y 求 X 乘 Y 的 值 6*7=42/ X/Y 求 X 除 Y 的 值 ( 浮 点 数 运 算 ) 2.76/1.2=2.3div X div Y 求 X 除 Y 的 整 数 商 ( 对 整 型 数 计 算 ) 25=5Mod X mod Y 求 X 除 Y 的 余 数 ( 对 整 型 数 运 算 ) 25 mod 4=1+ X+Y 加 法 运 算 32+2=34- X-Y 减 法 运 算 48-21=27由 于 Visual Basic 只 能 识 别 按 其 格 式 书 写 的 数 学 表 达 式 , 所 以 必 须 将 我 们 常用 的 数 学 表 达 式 转 换 成 Visual Basic 表 达 式 。 例 如 :数 学 式 Visual Basic 表 达 式2、 逻 辑 运 算逻 辑 运 算 的 结 果 只 有 两 个 :True( 真 ) 和 False( 假 )。Visual Basic 提 供 了 六种 关 系 运 算 符 和 四 种 逻 辑 运 算 符 :=( 等 于 )、=( 大 于 等 于 )、( 不等 于 )NOT( 非 )、AND( 与 )、OR( 或 )、XOR( 异 或 )运 算 关 系p q NOT p p AND q p OR qTrue True False True TrueTrue False False False TrueFalse True True False TrueFalse false True False False总 结 取 反 都 真 才 真 有 1 真


就 真例 如 :5>3 结 果 为 True, “a”>”b” 结 果 为 False。3、 表 达 式 的 运 算 优 先 顺 序在 进 行 表 达 式 的 转 换 过 程 中 , 必 须 了 解 各 种 运 算 的 优 先 顺 序 , 使 转 换 后 的 表达 式 能 满 足 数 学 公 式 的 运 算 要 求 。 运 算 优 先 顺 序 为 :括 号 → 函 数 → 乘 方 → 乘 、 除 → 加 、 减 → 字 符 连 接 运 算 符 → 关 系 运 算 符 → 逻 辑运 算 符如 果 同 级 的 运 算 是 按 从 左 到 右 次 序 进 行 ; 多 层 括 号 由 里 向 外 。例 :(10+6)*3^2*COS(1)/2*8+71 4 3 5 2 6 7 8Sqrt(Abs(p/n-1))+14 3 1 2 5数 学 上 的 表 达 式 与 pascal 语 言 表 达 式 的 区 别数 学 表 达 式 PASCAL 表 达 式注 意2a 2*a * 号 不 能 省 略a÷b a/b 除 号 的 写 法a≠b ab 不 等 号 的 写 法a≤b a=b 大 于 等 于 号 的 写 法第 6 节 Pascal 字 符 与 符 号1. 标 识 符(1) 标 识 符 的 定 义 : 标 识 符 就 是 以 字 母 开 头 的 字 母 数 字 序 列 , 有 效 长 度 为 63个 字 符 , 并 且 大 小 写 等 效 。 可 以 用 来 标 示 常 量 、 变 量 、 程 序 、 函 数 等 。 例 如 例 1.1中 的 Area( 程 序 名 ),pi( 符 号 常 量 ),s、r( 变 量 名 ) 都 是 标 识 符 。(2) 标 识 符 的 分 类 :a. 保 留 字 ( 关 键 字 )所 谓 保 留 字 是 指 在 Pascal 语 言 中 具 有 特 定 的 含 义 , 你 必 须 了 解 它 的 含 义 , 以便 于 正 确 的 使 用 , 否 则 会 造 成 错 误 。 标 准 Pascal 语 言 中 的 保 留 字 一 共 有 35 个 ,


Pascal 语 言 一 共 有 51 个 。 下 面 是 Pascal 语 言 的 保 留 字 :AND,ARRAY,BEGIN,CASE,CONST,DIV,DO,DOWNTO,ELSE,END,FILE,FOR,FUNTION,GOTO,IF,IN,LABEL,MOD,NIL,NOT,OF,OR,PACKED,PROCEDURE,PROGRAM,RECORD,REPEAT,SET,THEN,TO,TYPE,UNTIL,VAR,WHILE,WITH 等b. 标 准 标 识 符 : 指 Pascal 语 言 预 先 定 义 的 标 识 符 , 具 有 特 殊 含 义 。以 下 列 举 了 Pascal 语 言 部 分 常 用 的 标 准 表 识 符 :标 准 常 量 False Maxint True标 准 类 型 Boolean Char Real Integer标 准 函 数 Abs Arctan Chr Cos Eof Eoln ExpLn Odd Ord Pred Round Sin SqrSqrt Succ Trunc标 准 过 程 Dispose Get New Pack Page Put ReadReadln Reset Rewrite Unpack Write Writeln标 准 文 件 Input Outputc. 用 户 自 定 义 标 识 符 : 由 你 自 己 根 据 需 要 来 定 义 。(1) 选 用 的 标 识 符 不 能 和 保 留 字 相 同 。(2) 语 法 上 允 许 预 定 义 的 标 准 标 识 符 作 为 你 自 己 定 义 的 标 识 符 使 用 , 但 最好 还 是 不 要 用 。以 下 列 举 了 你 自 己 在 定 义 标 识 符 时 可 以 用 的 字 符 :A..Z,a..z,0..9 和 _( 下 划 线 ), 其 中 首 位 必 须 是 字 母 , 字 母 不 区 分 大 小 写 。第 7 节单 元PASCAL 语 言 的 程 序 中 , 通 过 在 开 头 使 用 uses 命 令 , 说 明 使 用 的 单 元 , 语法 是 :Uses < 单 元 名 称 >标 准 库 单 元 :System、DOS、Printer (DOS 版 本 , 通 常 我 们 使 用 的 Windows版 本 和 Linux 版 本 等 库 有 所 不 同 ,delphi,lazarus 版 本 也 有 所 不 同 )对 于 FreePascal 由 于 我 们 常 用 的 编 写 Application 程 序 , 所 以 其 单 元 引 用 不 同 。单 元 的 结 构


单 元 的 程 序 类 似 于 一 般 的 源 程 序 , 结 构 一 般 如 下 :Unit < 单 元 名 称 >interfaceUses < 单 元 名 称 表 >;< 公 共 声 明 >implementationuses< 单 元 名 称 表 >;< 私 有 声 明 >< 过 程 和 函 数 程 序 段 >begin...< 初 始 化 >End.可 以 看 出 ,interface 一 节 接 就 相 当 于 C 中 函 数 之 外 的 部 分 ,uses 相 当 于include,implementation 相 当 于 各 个 函 数 部 分 。第 8 节 结 构 化 程 序 设 计程 序 由 数 据 结 构 和 算 法 组 成 , 而 算 法 由 过 程 , 函 数 , 语 句 组 成 , 语 句 有 顺序 执 行 语 句 , 条 件 选 择 语 句 , 循 环 语 句 。其 中 条 件 语 句 是IF < 条 件 语 句 >THEN < 执 行 块 1> ELSE < 执 行 块 2>CASE 语 句 < 表 达 式 > of < 值 表 > 语 句 end;Var i : integer;...Case i of3 : DoSomething;1..5 : DoSomethingElse;end;循 环 语 句 有While < 布 尔 表 达 式 > do < 循 环 体 语 句 >;循 环 语 句 执 行 流 程 。


布 尔 表 达 式FalseTrue循 环 体而 另 外 一 个 循 环 语 句Repeat 语 句 的 语 法 格 式 为 :repeat循 环 体 语 句until 布 尔 表 达 式 ;Repeat 循 环 语 句 的 执 行 流 程 如 图 1-2-1 所 示 。循 环 体False布 尔 表 达 式True不 同 之 处 在 先 执 行 , 至 少 一 此 循 环 再 判 断 条 件 是 否 成 立 。For 循 环 , 支 持 数 字 计 数 控 制 步 长 , 进 行 循 环 。For Day := Monday to Friday do Work;For I := 100 downto 1 doWriteLn (’Countingdown : ’,i);For I := 1 to 7*dwarfs do KissDwarf(i);For 语 句 里 面 不 能 对 计 数 器 赋 值 。循 环 都 可 以 用 break 跳 出 ;用 continue 执 行 下 此 循 环 。第 9 节面 向 对 象 的 程 序 设 计面 向 对 象 的 程 序 设 计 就 是 利 用 pascal 的 单 元 进 行 设 计 。pascal 有 object 关 键 字 , 就 是 用 于 面 向 对 象 的 程 序 设 计 , 使 用 起 来 , 程 序 的结 构 更 加 清 晰 。语 法 :


unit < 单 元 名 >;{$mode objfpc}{$H+} // 高 速 编 译 器 此 单 元 是 Object pascalinterfaceusesClasses, SysUtils; // 使 用 了 哪 些 标 准 单 元type{ 注 释 }TForm1 = class(TForm) //TForm1 类 继 承 于 TFormbtnNew: TButton;// 这 节 的 变 量 相 当 于 public 或 者 published 但 是 由 IDE 维护 , 对 应 到 Form 资 源procedure btnNewClick(Sender: TObject);// 按 钮 的 处 理 试 件 , 也 是 IDE 维 护private{ private declarations } // 私 有 变 量 , 只 能 本 类 访 问Protected// 本 类 和 继 承 于 本 类 的 子 类 可 以 访 问public{ public declarations }// 公 共 接 口Published// 非 继 承 于 Tform 的 类 可 以 发 布 成 控 件 , 在 IDE 的 控 件 属 性 窗 口 可 见end;varForm1: TForm1; // 全 局 变 量 , 但 不 建 议 这 样 用 , 而 是 声 明 到 调 用 方implementation{$R *.lfm} // 宏 , 告 诉 编 译 器 加 载 和 本 单 元 一 样 的 名 称 的 表 单 资 源 文 件procedure TForm1.btnNewClick(Sender: TObject); // 类 方 法 的 具 体 实 现var fs:tstringlist; // 方 法 的 局 部 变 量beginApplication.messagebox('hello,world'); //application 是 标 准 单 元 form.pas 里 面的 全 局 变 量end;


End. // 本 单 元 结 束如 果 我 们 要 声 明 一 个 不 基 于 任 何 其 他 基 类 的 新 类 , 怎 么 办 ?Typemyclass= Class;没 错 , 就 是 class 关 键 字 。但 是 我 们 一 般 都 基 于 TObject 继 承 。 是 因 为 TObject 有 默 认 的 构 造 函 数 等 。那 么 我 们 知 道 , 在 c 语 言 里 面 , 一 个 这 样 的 访 问 :Something.somebody := 1;意 味 着 是 直 接 访 问 一 个 struct 的 一 个 属 性 。 那 么 在 lazarus 的 GUI 程 序 里 面 ,我 们 用Form1.caption := 'Hello';又 是 怎 么 立 即 就 看 到 Hello 字 符 显 示 到 窗 口 的 标 题 栏 了 呢 ?这 就 要 归 功 于 编 译 器 的 魔 法 , 上 面 的 语 句 被 编 译 器 翻 译 成 了 如 下 类 似 C 语言 的 语 句 。SetCaption (Form1.Caption , 'Hello');实 际 上 就 是 调 用 了 一 个 过 程 , 过 程 里 面 再 调 用 了 显 示 绘 图 函 数 , 所 以 才 可 以看 到 只 是 赋 值 就 实 现 了 画 出 文 字 的 现 象 。Freepascal 还 支 持 Object 类 型 , 而 LCL 库 还 定 义 了 TObject 类 型 ,TObject 继 承 于 Class.那 么 Object 和 Class 区 别 是 什 么 呢 ?Object 相 当 于 一 个 record, 当 其 被 声 明 , 就 会 分 配 内 存 在 Stack, 而 Class 必 须调 用 constructor 来 初 始 化 , 并 且 分 配 内 存 到 heap. 相 当 于 object 的 指 针 。第 9 节 Helper类 和 Record 支 持 helper 功 能 , 相 当 于 给 类 添 加 一 个 方 法 , 而 不 用 重 新 修 改这 个 类 的 任 何 代 码 。 比 如TObjectHelper = class helper for TObjectfunction AsString(const aFormat: String): String;end;function TObjectHelper.AsString(const aFormat: String): String;


eginResult := Format(aFormat, [ToString]);end;varo: TObject;beginWriteln(o.AsString(’Theobject’’ s name is %s’));end.第 10 节 主 程 序对 于 <strong>Lazarus</strong> 的 Application 程 序 来 说 , 一 个 项 目 就 有 一 个 lpr 文 件 , 意 思 是<strong>Lazarus</strong> PRograme 。 这 个 文 件 相 当 于 c 语 言 的 包 含 main 函 数 的 哪 个 .c 文 件 。或 者 Java 的 包 含 main 函 数 的 主 程 序 , 或 者 html 的 index.html。 我 们 来 看 调 用上 面 单 元 的 程 序 ;program ScriptAssistant; // 主 程 序 说 明{$mode objfpc}{$H+}Uses // 使 用 了 哪 些 单 元{$IFDEF UNIX}{$IFDEF UseCThreads} //unix 类 操 作 系 统 , 使 用 的 线 程cthreads,{$ENDIF}{$ENDIF}Interfaces, // this includes the LCL widgetset //LCL<strong>Lazarus</strong> 的 控 件Forms, uMain; // 将 调 用 上 面 uMain 单 元 里 面 的 类{$R *.res} // 主 程 序 图 标 等 资 源beginRequireDerivedFormResource := True;Application.Initialize; // 上 面 forms 里 面 的 application 全 局 对 象 初 始 化Application.CreateForm(TForm1, Form1); // 创 建 一 个 Tform1 类 的 实 例 , 对 象名 form1Application.Run; // 开 始 运 行 这 个 主 程 序 , 由 于 此 程 序 只 有 一 个 form, 所 以 会


默 认 为 主 窗 口 ,application 对 象 会 管 理 各 个 窗 口 , 将 windows 消 息 发 送 给 主 窗 口 或其 里 面 的 控 件 , 从 而 实 现 包 装 所 有 windows API, 实 现 一 个 GUI 程 序 。end.


第 五 十 二 章 <strong>Lazarus</strong> 的 代 码 打 印经 常 看 网 上 同 学 说 怎 么 打 印 代 码 ?直 接 file->print打 印 语 法 高 亮 的 代 码 , 不 是 问 题 。我 们 可 以 看 到 lazarus 对 菜 单 的 划 分 十 分 合 理 。File 菜 单 全 是 file 操 作 。三 级 菜 单 很 少 。


第 五 十 三 章 <strong>Lazarus</strong> 的 源 码 导 出 功 能在 project->publish project和 清 理 目 录 相 似 , 不 过 , 之 后 你 可 以 执 行 命 令 , 比 如 7zip 压 缩 。


第 五 十 四 章<strong>Lazarus</strong> 的 注 释 编 写其 支 持 插 入 CVS 标 签插 入 日 期 标 签插 入 文 件 名将 当 前 选 择 的 作 为 注 释 或 反 注 释


第 五 十 五 章Lazaurs 转 换 C 语 言 头 文 件如 果 你 有 开 发 c 的 库 , 可 又 要 用 lazarus 调 用 , 怎 么 办 ?h2pas 来 帮 忙 , 安 装这 个 组 件 。然 后 在 tools->h2pas 里 面 打 开 , 这 个 东 东 会 自 动 将 c 语 法 转 到 pas对 使 用 动 态 连 接 库 很 有 用 。


第 五 十 六 章 <strong>Lazarus</strong> 的 代 码 重 构代 码 重 构 , 许 多 现 代 IDE 都 支 持 ,<strong>Lazarus</strong> 提 供 了 7 个 菜 单 来 支 持 。选 项 Source ->Refactoring->特 别 是 unused Units , 很 有 用 哦 。不 过 要 小 心 使 用 ;


第 五 十 七 章<strong>Lazarus</strong> 的Unicode,UTF8,Ascii 字 符 速 查这 个 功 能 在 edit -> insert from character map, 当 然 , 这 个 功 能 可 以 插 入 所 以 支持 的 ascii,unicode 字 符 , 也 可 以 只 是 查 看 , 汉 字 也 支 持 。强 大 。记 不 住 ascii 码 ? 这 里 都 有 了 。这 可 是 borland 以 前 最 牛 的 一 个 工 具 软 件 , 卖 到 了 百 万 份 拷 贝 。 现 在 也 免 费 , 功 能 十 分


第 五 十 八 章 <strong>Lazarus</strong> 各 控 件 兼 容 性 速 查我 们 知 道 lazarus 是 跨 平 台 的 , 那 么 我 们 怎 么 知 道 某 个 控 件 的 某 些 属 性 可 以在 哪 个 平 台 使 用 呢 ?我 们 可 以 使 用 菜 单 View ->Restriction browser 其 中 控 件 类 . 属 性 前 面 的 图 标指 出 某 个 属 性 在 该 平 台 不 可 用 。 右 边 显 示 了 不 可 用 的 英 文 描 述 。 上 面 显 示 了 图 标和 平 台 的 对 应 关 系 。


第 五 十 九 章 <strong>Lazarus</strong> 各 控 件 的 存 在 性菜 单 view ->ide internals -> package links , 你 可 以 看 到这 样 我 们 就 可 以 根 据 此 表 信 息 找 到 我 们 安 装 的 控 件 是 否 正 确 。


第 六 十 章查 看 IDE 的 快 速 工 具 栏IDE 的 快 捷 工 具 栏 , 打 开 菜 单 View ->IDE Speed buttons, 有 这 些第 一 行 有新 单 元新 窗 体 类打 开保 存全 部 保 存切 换 窗 体 / 代 码 窗 口第 二 行 有查 看 单 元 列 表查 看 窗 口 列 表运 行暂 停终 止跟 踪 进 入跟 踪执 行 到 函 数 返 回


第 六 十 一 章 查 看 IDE 的 控 件 面 板控 件 的 查 看 方 式 有 多 种 , 其 中 面 板 是 一 种 。然 后 在 面 板 上 我 们 用 鼠 标 右 键 。 选 择 view all, 可 以 看 到 一 个 可 以 按 名 称 过滤 的 选 择 器 , 这 是 Delphi 专 家 工 具 才 能 达 到 的 功 能 。 同 时 支 持 按 面 板 和 继 承 树选 择 。


第 六 十 二 章 需 要 编 译 的 单 元我 们 安 装 了 控 件 , 途 中 可 能 需 要 查 看 当 前 编 译 器 哪 些 单 元 需 要 编 译 。可 以 选 择 菜 单view ->ide internals -> what needs building的 窗 口 , 他 会 自 动 分 析 哪 些 需 要 重 新 编 译 连 接 到 lazarus.exe也 可 以 。当 然 你 也 可 以 选 择 其 他 包 进 行 分 析 , 比 如 自 己 开 发 的 控 件 , 还 有 自 己 的 项 目只 要 选 择 Project 就 可 以 了 。


第 六 十 三 章 代 码 美 化菜 单 source->JEDI code format -> 根 据 需 要 选 择 子 菜 单 。当 前 版 本 会 将 中 文 进 行 编 码 到 widestring, 会 乱 码 , 所 以 我 们 需 要 修 改 JCF2这 个 component 并 且 重 新 编 译 lazarus.exe只 需 要 修 改 fsInputCode, fsOutputCode: WideString; 两 个 的 类 型 为 ansistring在 Converter.pas 单 元 。


第 六 十 四 章 代 码 内 容 查 找比 如 我 们 在 编 写 一 个 大 型 系 统 的 时 候 , 可 能 某 个 信 息 需 要 查 找 , 怎 么 办 呢 ?我 们 可 以 使 用 search -> Find in file...在 新 的 对 话 框 text to find 后 面 编 辑 框 输 入 " 我 要 查 的 内 容 "然 后 回 车 , 找 到 的 内 容 会 在


出 来 , 你 看 , 其 还 有 输 出 代 码 的 结 构如 果 此 对 话 框 没 有 出 来 。 我 们 使 用 菜 单View -> search results就 可 以 显 示 出 来 了 。


第 六 十 五 章 调 试 窗 口这 里 说 的 调 试 窗 口 是 指 的 ,View->Debug Windows, 下 面 选 择Watchs 跟 踪 的 变 量Break points 断 点Local variables 局 部 变 量Register 寄 存 器Call stack 调 用 栈Thread 线 程...下 面 还 有 几 个 。我 们 可 以 看 到 其 信 息 很 丰 富 。


第 六 十 六 章 查 看 代 码 树 型 结 构这 是 当 前 单 元 的 引 用 , 很 直 观 吧 ?同 时 他 还 显 示


这 是 单 元 宏 的 结 构 , 对 与 写 控 件 , 太 方 便 了 。


第 六 十 七 章find xxx我 安 装 不 上 控 件 提 示 can not提 示 这 个 信 息 , 一 般 并 不 是 路 径 问 题 , 而 是 某 些 单 元 编 译 失 败 , 需 要 根 据 提示 修 改 , 如 果 此 提 示 单 元 信 息 消 失 , 需 要 清 除 已 编 译 的 单 元 , 完 全 重 新 编 译 这 个控 件 , 然 后 根 据 提 示 修 改 。清 除 已 经 编 译 的 单 元 在 File ->clear directoryKeep files matching filter 表 示 保 留 的 文 件 扩 展 名Remove files matching filter 表 示 要 清 理 的 文 件 扩 展 名 。这 个 功 能 和 项 目 备 份 的 功 能 极 为 相 似 。只 是 一 个 提 取 出 需 要 的 , 一 个 清 理 了 不 需 要 的 ;


第 六 十 八 章 WinMain 在 哪 里学 习 过 Windows SDK 编 程 的 C/C++ 程 序 员 都 知 道 ,Windows 程 序 必 然 有 一 个 死 循 环 的WinMain 程 序 , 可 以 在 <strong>Lazarus</strong> 里 面 并 没 有 , 那 么 他 在 哪 里 呢 ?我 们 可 以 在 Lcl\Forms.pas里 面 找 到 这 样 的 变 量 声 明varApplication: TApplication = nil;Screen: TScreen = nil;ExceptionObject: TExceptObject;HintWindowClass: THintWindowClass = THintWindow;RequireDerivedFormResource: Boolean = False;我 们 根 据 此 线 索 可 以 找 Tapplication 找 application.inc 文 件 , 里 面 有 这 样 的 代 码{------------------------------------------------------------------------------TApplication RunMainForm is loaded and control is passed to event processor.------------------------------------------------------------------------------}procedure TApplication.Run; // 这 个 就 是 我 们 在 lazarus 主 程 序 里 面 看 到 的 执 行 的 成 员 函 数beginif (FMainForm nil) and FShowMainForm then FMainForm.Show;WidgetSet.AppRun(@RunLoop); // 这 里 就 呼 叫 了 一 个 死 循 环end;{------------------------------------------------------------------------------TApplication RunLoopcontrol is passed to event processor.------------------------------------------------------------------------------}procedure TApplication.RunLoop;// 这 就 是 visual c ++ 的 那 个 大 循 环beginrepeatif CaptureExceptions then // 设 置 了 要 捕 获 错 误try // run with try..exceptHandleMessage; // 接 管 所 有 消 息exceptHandleException(Self);endelse


end;HandleMessage; // run without try..exceptuntil Terminated;// 不 捕 获 错 误 , 直 接 处 理 消 息我 们 再 来 看 handleMessage 怎 么 做 的{------------------------------------------------------------------------------Method: TApplication.HandleMessageParams: NoneReturns: NothingHandles all messages first then the Idle------------------------------------------------------------------------------}procedure TApplication.HandleMessage;beginWidgetSet.AppProcessMessages; // process all events // 处 理 消 息if not Terminated then Idle(true); // 如 果 没 有 消 息 , 就 使 用 发 呆 神 功end;我 们 再 来 看 createform 方 法{------------------------------------------------------------------------------TApplication CreateFormNote: The name is confusing and only kept for Delphi compatibility. It cancreate any kind of components.Create a Component instance and sets the pointer to the component variableand loads the component. If it is a form it will be added to the applicationsforms list------------------------------------------------------------------------------}procedure TApplication.CreateForm(InstanceClass: TComponentClass;out Reference);varInstance: TComponent;ok: boolean;AForm: TForm;begin// Allocate the instance, without calling the constructorInstance := TComponent(InstanceClass.NewInstance);// set the Reference before the constructor is called, so that// events and constructors can refer to itTComponent(Reference) := Instance;ok:=false;try


if (FCreatingForm=nil) and (Instance is TForm) thenFCreatingForm:=TForm(Instance);Instance.Create(Self);ok:=true;finallyif not ok then beginTComponent(Reference) := nil;if FCreatingForm=Instance thenFCreatingForm:=nil;end;end;if (Instance is TForm) thenbeginAForm := TForm(Instance);UpdateMainForm(AForm);if FMainForm = AForm thenAForm.HandleNeeded;if AForm.FormStyle = fsSplash thenbegin// show the splash form and handle the paint messageAForm.Show;AForm.Invalidate;ProcessMessages; // 这 个 是 典 型 的 消 息 循 环end;end;{$IFDEF AfterConstructionDataModuleNotWorking}if (Instance is TDataModule) thenbeginTDataModule(instance).AfterConstruction;end;{$ENDIF}end;上 面 已 经 说 了 保 留 createform 只 是 为 了 和 delphi 兼 容 , 我 们 也 看 到 前 面 的 分 析 , 已 经 能 够 处理 消 息 , 也 就 是 说 不 使 用 这 个 createform 也 应 该 可 以 执 行 。我 们 再 来 看 看 ProcessMessagesprocedure TApplication.ProcessMessages;beginWidgetSet.AppProcessMessages;ProcessAsyncCallQueue;end;他 和 前 面 的 Tapplication.run 是 调 用 了 同 一 个 方 法 AppProcessMessages


那 么 也 就 是 说 一 个 应 用 没 有 建 立 某 个 窗 口 , 也 是 可 以 的 哦 ? 是 的 .我 们 可 以 看 到 application.createform 这 句 被 屏 蔽 掉 , 也 是 可 以 运 行 的 只 是 没 有 窗 口 。那 么 前 面 看 了 application.run 派 发 消 息 , 那 么 application.initialize 是 做 什 么 的 , 用 ctrl+click追 踪 代 码 :procedure TApplication.Initialize;varRes: TFPResourceHandle;begininherited Initialize;// interface object and screenif (WidgetSet=nil) or (WidgetSet.ClassType = TWidgetSet)then beginDebugLn('ERROR: ',rsNoWidgetSet);raise Exception.Create(rsNoWidgetSet);end;WidgetSet.AppInit(ScreenInfo); // 主 要 调 用ScreenInfo.Initialized := True;Screen.UpdateScreen;// set that we are initialized => all exceptions will be handled by our HandleExceptioninclude(FFlags, AppInitialized);// application iconif <strong>Lazarus</strong>Resources.Find('MAINICON') nil thenIcon.LoadFrom<strong>Lazarus</strong>Resource('MAINICON')elsebeginRes := FindResource(HInstance, PChar('MAINICON'), PChar(RT_GROUP_ICON));if Res 0 thenIcon.LoadFromResourceHandle(Hinstance, Res);end;end;而 AppInit 又 是 做 什 么 的 呢 :


TWidgetSet = class(TObject)protectedFThemeServices: TThemeServices;procedure PassCmdLineOptions; virtual;function CreateThemeServices: TThemeServices; virtual;function GetAppHandle: THandle; virtual;procedure SetAppHandle(const AValue: THandle); virtual;publicconstructor Create; virtual;procedure BeforeDestruction;override;procedure AppInit(var ScreenInfo: TScreenInfo); virtual; abstract;我 们 可 以 看 到 是 一 个 纯 虚 方 法 , 这 个 方 法 就 是 多 种 操 作 系 统 的 统 一 的 接 口 , 实 现 主 窗 口 的 创建 。 放 在 Interfacebase.pp 。我 们 可 以 看 到 < 安 装 目 录 >lcl\interfaces 这 个 文 件 夹 里 面 有 qt,win32,wince 等 文 件 夹 , 通 过 参数 设 置 , 就 可 以 实 现 不 同 操 作 系 统 的 GUI 界 面 , 从 而 实 现 上 面 提 到 的 纯 虚 方 法 , 实 现 了 跨 平台 。分 析 告 一 段 落 。


第 六 十 九 章 转 换 Delphi 的 代 码 到 <strong>Lazarus</strong>转 换 Delphi 的 普 通 应 用 和 控 件 是 比 较 容 易 的 , 大 约 10% 的 代 码 需 要 自 己 进行 处 理 :1. 转 换 时 选 择 Delphi 兼 容 模 式 ;2. 代 码 的 格 式 必 须 保 存 为 UTF8, 否 则 会 乱 码 ;3.Form 必 须 稍 微 修 改 一 下 , 再 保 存 , 将 会 自 动 将 字 符 转 换 到 UTF8 模 式 ; 否则 乱 码 ;4. 一 些 控 件 属 性 会 丢 失 ; 或 者 需 要 用 批 量 替 换 工 具 进 行 替 换 ;5.ClientDataset 用 MemTable 替 换 , 一 些 属 性 , 或 代 码 需 要 修 改 ;6.RichMemo 无 法 完 全 取 代 RichEdit; 目 前 没 有 很 好 的 办 法 , 只 能 自 己 扩 展 ;7.Tdatetimepicker 需 要 用 TdateEdit 替 换 , 需 要 手 工 处 理 , 单 元 是 editbtn;8.<strong>Lazarus</strong> 自 带 的 数 据 库 连 接 控 件 都 可 以 用 ZEOSDBO 代 替 ;9.ActiveX 的 控 件 需 要 FPC2.6.1, 目 前 1.1 正 在 研 究 加 入 这 个 功 能 ;10. 其 他 主 要 在 UTF8 的 处 理 方 面 ;11.DBGrid 可 以 代 替 大 多 数 其 他 第 三 方 Grid, 一 些 特 性 丢 失 , 比 如 常 用 的EhLib 的 Footer.


第 七 十 章能<strong>Lazarus</strong> 的 属 性 编 辑 器 收 藏 功当 我 们 编 写 一 个 Form 类 的 时 候 , 需 要 设 置 控 件 的 很 多 属 性 , 常 常 , 我 们 需要 设 置 某 类 控 件 的 几 个 属 性 , 可 是 我 们 每 次 都 需 要 从 属 性 编 辑 器 那 里 去 找 出 他们 , 非 常 浪 费 时 间 , 有 没 有 快 捷 的 方 式 呢 ?属 性 编 辑 器 收 藏 夹 功 能 就 是 解 决 这 个 问 题 的 良 方 。1. 首 先 我 们 需 要 选 中 我 们 要 操 作 的 控 件 ;2. 然 后 我 们 在 属 性 编 辑 器 里 面 收 藏 这 个 属 性 到 收 藏 夹 ;3. 后 面 其 他 控 件 我 们 就 在 收 藏 夹 里 面 修 改 就 可 以 了 ;


这 样 , 生 产 率 提 高 了 不 知 道 多 少 倍 ;


第 七 十 一 章 <strong>Lazarus</strong> 开 发 的 应 用 程 序 支 持文 件 拖 放以 前 我 们 要 开 发 这 个 功 能 , 需 要 自 己 写 代 码 , 现 在 只 用 这 样设 置 窗 口 的 allowDropFiles := True然 后 处 理 他 。


第 七 十 二 章 ActiveX概 述LazActiveX 软 件 包 包 含 TActiveXContainer 控 件 和 必 需 的 IDE 整 合 工 具产 生 来 自 一 个 TypeLibrary 的 ActiveX 控 件 或 直 接 地 从 对 象 (exe 或 动 态 链 接库 ).ActiveX 是 一 种 微 软 视 窗 技 术 而 且 只 能 在 那 一 个 平 台 上 使 用 。 在 Windows上 交 叉 的 编 辑 是 可 能 的 , 但 是 typelib 导 入 工 具 只 能 在 Windows 上 产 生 COM 绑 定 。(Wine 上 没 有 测 试 过 )LazActiveX 必 须 要 Fpc2.6.1 才 支 持 的 控 件 。 操 作 系 统 需 要 WindowXP 或 者 更新 的 。安 装 LazActiveX菜 单 Package ->Install /Unintall packages..., 选 择 LazActiveX 0.1, 安 装 并 且 Save and reBuild IDE.使 用 方 法有 3 种 不 同 方 法 , 使 用 ActiveX 控 件 。1. 拖 放 ,TActivexContainer 到 Form, 然 后 设 置 ActiveX ClassName 为OLEClassName 属 性 , 适 合 迟 绑 定 和 没 有 直 接 的 事 件 支 援 。2. 导 入 ActiveX Type Library , 拖 放 TActiveXContainer 到 Form 上 ,ActiveX 对 象 而 且 分 配 它 到 ComServer 特 性 。 适 当 的 为 早 绑 定 和 与 事 件 支 持 。3. 创 建 一 个 来 自 TypeLibrary 的 一 个 新 控 件 或 对 象 并 将 控 件 放 在 Form 上 。 这也 使 用 早 绑 定 而 且 有 完 整 的 事 件 支 持 。 事 件 句 柄 能 从 IDE 赋 值 。TActiveXContainer 延 迟 绑 定虽 然 理 论 相 当 复 杂 、 延 迟 绑 定 是 把 一 个 ActiveX 元 件 运 的 最 快 速 的 方 法 。例 子 :Form 上 放 一 个 嵌 入 VLC 播 放 器 。VLC 必 须 被 安 装 !!- 在 一 Form 上 放 TActiveXContainer 、 TButton 和 TFileNameEdit 。


- 调 整 TActiveXContainer 大 小 放 置 , 设 置OLEClassName 为 ’VideoLAN.VLCPlugin.2' , 设 定 Active:=True。 效 果 如 下 :创 建 按 钮 的 Onclick 事 件 , 输 入 代 码 :procedure TForm1.Button1Click(Sender: TObject);varActx:variant;beginActx:=ActiveXContainer1.ComServer;Actx.playlist.add(widestring(FileNameEdit1.FileName));Actx.playlist.play;end;运 行 这 个 程 序 并 且 点 击 按 钮 , 选 择 一 个 影 片 , 就 可 以 播 放 。另 外 一 种 方 式 是 Tools 工 具 菜 单 - 》 选 择 Import Type Library, 选 择axVLC.Dll, 然 后


axVLC_1_0_TLB 单 元 将 会 被 自 动 创 建 。个 单 元同 样 'C:\WINDOWS\system32\ieframe.dll' , 将 会 生 成 SHDocVw_1_1_TLB 这可 以 导 入 IE 浏 览 器 哦 。而 第 三 种 方 式 是 在 导 入 DLL 的 时 候 , 选 中 Create Package, 就 可 以 产 生 相 应的 ActiveX 组 件 , 比 如 IE 浏 览 器 控 件 。那 么 在 FPC2.6.1 之 外 的 版 本 是 否 可 以 支 持 ActiveX 呢 ?事 实 上 是 可 以 的 , 有 一 个 DemoAX 演 示 了 如 何 实 现 WEB 浏 览 器 的 嵌 入 。首 先 他 声 明 IUnknown 接 口typePIUnknown=^IUnknown;TAtlAxAttachControl = function(Control:IUnknown;hwind:hwnd;ppUnkContainer:PIUnknown): HRESULT; stdcall;IEventIntfEvents = dispinterface['{EAB22AC2-30C1-11CF-A7EB-0000C05BAE0B}']然 后 在 Form create 时 候 加 载 ActiveX 支 持 , 并 加 载 Iexplorerprocedure TForm1.FormCreate(Sender: TObject);varatl:hmodule;AtlAxAttachControl:TAtlAxAttachControl;beginatl:=LoadLibrary('atl.dll');AtlAxAttachControl:=TAtlAxAttachControl(GetProcAddress(atl,'AtlAxAttachControl'));EventSink1:= TEventSink.Create(Self);EventSink1.OnInvoke:=EventSink1Invoke;WebBrower:=CreateOleObject('Shell.Explorer');EventSink1.Connect(WebBrower, IEventIntfEvents);


AtlAxAttachControl(WebBrower,panel1.Handle,nil);WebBrower.GoHome;end;使 用WebBrower:=CreateOleObject('Shell.Explorer'); 这 句 创 建 一个 OLE 对 象 的 实 例 (WebBrower 是 一 个 variant 类 型 ) , 然 后 用EventSink1.Connect(WebBrower, IEventIntfEvents); 关 联 到 一 个 事 件处 理 程 序 ,AtlAxAttachControl(WebBrower,panel1.Handle,nil); 这 句 将 控 件 内 容显 示 到 Panel1 去WebBrower.GoHome; 这 句 执 行 OLE 对 象 的 方 法 。所 以 在 <strong>Lazarus</strong>1.0, 没 有 直 接 可 视 化 支 持 OLE 容 器 , 也 没 有 办 法 直 接 可 视 化编 辑 事 件 , 一 切 都 需 要 你 自 己 去 编 写 关 联 代 码 , 且 必 须 要 有 OLE 控 件 的 详 细 资 料 。只 是 没 有 自 动 化 支 持 , 而 是 要 手 写 代 码 而 已 。


第 七 十 三 章 ZEOSDBO 当 作 Memtable为 什 么 有 这 样 的 议 题 ?当 我 们 编 写 一 个 程 序 的 时 候 , 在 Delphi 里 面 我 们 常 常 需 要 将 数 据 库 数 据 提取 到 客 户 端 , 编 辑 后 再 批 量 保 存 , 有 时 候 我 们 想 将 数 据 库 断 开 , 然 后 批 量 保 存 ,或 者 三 层 方 式 。 可 是 存 在 几 个 问 题 :1. 用 Connection ,DataProvider ,ClientDataset, Datasource,DBGrid 这 样 需 要 很 多 控 件 ;2. 使 用 多 个 String 或 者 Recorde 加 Array 保 存 数 据 , 再 手 动 显 示 到StringGrid,Edit 里 面 , 可 是 代 码 量 比 较 大 ;3. 使 用 ZQuery 和 UpdateSQL 控 件 , 但 是 要 编 写 三 种 语 句 , 而 且 特 殊 的情 况 , 有 时 候 有 问 题 , 不 可 控 性 比 较 高 。4. 使 用 三 层 控 件 ;5. 使 用 ORM 工 具 、 组 件 ;现 在 提 出 一 种 新 的 解 决 方 式 :这 种 处 理 方 式 就 是 使 用 ZQuery 的 CachedUpdates=True, 读 数 据 ;插 入 , 更 新 的 时 候 , 自 己 手 工 写 代 码 , 不 使 用 UpdateSQL 控 件 , 这 样 既 保 留了 感 知 控 件 的 方 便 性 , 又 保 留 了 硬 编 码 的 可 控 性 ;


第 七 十 四 章BUG 修 复 ,lazarus 输 入 汉 字 ,输 入 1 个 出 两 个系 统 环 境 :ubuntu 8.04 LTSlazarus 1.1.0fcitx 输 入 法现 象 : 在 edit 组 件 里 面 , 输 入 汉 字 , 英 文 , 汉 字 不 显 示 , 英 文 输 入 1 个 字 母 ,出 现 2 个 字 母 , 显 示 双 汉 字官 方 解 决 方 法 : 无在 bugtracker 上 若 干 处 解 决 方 法 都 无 效私 有 解 决 方 法 :sudogedit/usr/share/lazarus/1.1.0/lcl/interfaces/gtk2/gtk2proc.inc在 这 个 图 形 化 编 辑 器 里 面 , 修 改 checkdeadkey 这 个 过 程 的 呼 叫 的 地 方 ,直 接 注 释 掉 这 个 过 程 的 调 用//checkDeadKey;保 存然 后 进 入 su 状 态cd /usr/share/lazarus/1.1.0make最 后 重 新 启 动 lazarus, 编 写 测 试 程 序 ,ok效 果 : 输 入 汉 字 , 字 符 , 都 ok 了推 导 :1.0.2 等 其 他 版 本 同 理是 否 导 致 新 的 bug: 未 知经 查 , 这 个 东 东 是 处 理 死 键 问 题 的 , 如 果 没 有 这 个 需 求 , 可 以 屏 蔽 死 键在 某 些 非 U.S. 英 语 键 盘 上 , 有 些 键 用 於 给 字 母 加 上 音 调 。 因 为 它 们 本 身 不产 生 字 元 , 所 以 称 之 为 「 死 键 」。 例 如 , 使 用 德 语 键 盘 时 , 对 於 U.S. 键 盘 上 的 +/=


键 , 德 语 键 盘 的 对 应 位 置 就 是 一 个 死 键 , 未 按 下 Shift 键 时 它 用 於 标 识 锐 音 , 按下 Shift 键 时 则 用 於 标 识 抑 音 。据 悉 , 如 果 在 管 理 员 权 限 使 用 lazarus 无 此 问 题 。


第 七 十 五 章 循 环 内 SQL什 么 是 循 环 内 SQL?我 们 来 看 一 个 算 法 。Query1.close;Query1.sql.text := 'select * from users';Query1.open;While not query1.eof doBeginQuery2.close;Query2.sql.text := 'select * from userlimit where userid=' + s;Query2.open;While not query2.eof doBeginIf query2.fieldbyname('module1enabled').asbool thenBeginbtnModule1.enabled := true;End;Query2.next;End;Query1.next;End;我 们 可 以 看 到 循 环 内 有 一 个 发 出 sql 语 句 的 地 方 , 整 个 算 法 浪 费 了 大 量 的 时间 在 服 务 器 通 信 上 , 慢 了 数 十 倍 。 整 个 算 法 是 说 , 某 个 用 户 具 有 某 个 权 限 , 就enabled 某 个 控 制 ( 这 是 打 比 方 ), 不 是 实 际 应 用 。 那 么 , 循 环 内 将 可 能 发 出 无 数 个查 询 , 两 个 数 据 集 的 数 据 规 模 不 大 的 情 况 下 , 实 际 上 我 们 可 以 将 循 环 内 的 代 码 ,放 在 循 环 外 , 并 且 , 我 们 在 循 环 内 , 用 locate, 或 者 用 memdataset 保 存 数 据 , 自己 进 行 比 对 , 速 度 将 快 很 多 。


第 七 十 六 章 TForm 是 类某 些 语 言 说 , 我 的 数 据 类 型 , 全 部 都 是 “ 类 ”, 我 说 全 部 都 是 “ 累 ”, 在 实 际使 用 的 时 候 , 一 个 简 单 类 型 Integer , 搞 成 一 个 “ 类 ”, 比 较 的 时 候 还 要 解 包 , 为了 “ 类 ” 而 “ 累 ”。<strong>Lazarus</strong> 和 Delphi 一 样 , 我 们 每 天 的 开 发 都 是 基 于 类 , 而 且 大 部 分 都 是 类 ,最 多 的 就 是 TForm 的 子 类 , 每 天 我 们 在 设 计 可 视 化 的 窗 体 的 时 候 , 就 是 在 编 写一 个 类 。 这 是 其 他 语 言 不 可 以 想 象 的 , 虽 然 其 他 语 言 也 有 的 有 此 功 能 , 但 都 没 有这 么 优 雅 , 要 么 引 入 的 名 字 太 长 , 要 么 可 视 化 不 全 面 。 要 么 用 xml 保 存 类 属 性 ,要 么 用 代 码 解 析 , 不 允 许 你 修 改 界 面 定 义 代 码 。 具 体 是 什 么 IDE, 就 不 说 了 。那 么 是 否 什 么 地 方 都 应 该 只 用 类 呢 ? 当 然 是 否 定 的 , 杀 鸡 应 该 用 鸡 刀 , 杀 牛就 用 牛 刀 , 大 师 门 总 是 将 复 杂 问 题 简 单 化 。 而 有 的 “ 大 师 ” 总 是 将 简 单 的 问 题 复杂 化 , 复 杂 问 题 更 加 复 杂 化 , 好 像 程 序 里 面 不 搞 上 几 个 引 擎 , 不 搞 上 多 少 接 口 ,不 搞 上 指 针 、 链 表 , 不 搞 上 XML, 不 起 个 框 架 、 平 台 的 名 字 , 就 对 不 起 爹 娘 , 对不 起 社 会 似 的 。<strong>Lazarus</strong> 的 实 现 运 用 了 各 种 技 巧 , 各 种 最 直 接 的 实 现 方 式 , 该 用 类 就 用 类 ,该 包 含 文 件 就 包 含 文 件 , 该 接 口 就 接 口 , 该 过 程 就 过 程 , 该 数 组 就 数 组 。 这 才 是软 件 开 发 的 真 谛 。那 么 既 然 Tform 就 是 类 , 就 应 该 可 以 再 被 继 承 , 拥 有 属 性 , 拥 有 构 造 重 载 ,析 构 重 载 的 能 力 咯 ?是 的 , 你 可 以 将 数 据 库 连 接 , 在 lpr 文 件 里 创 建 , 用 TForm 的 重 载 构 造 函 数create(ADatabaseConnection:TZConnection;AUserID:string;AOwner:TObject);这 样 的 形 式 , 将 数 据 库 连 接 传 递 给 TForm, 从 而 实 现 Tform 类 不 直 接 引 用Datamodale 的 最 大 解 耦 合 。当 然 你 也 可 以 在 Tform 类 实 例 化 后 , 使 用 form1.userid:=1; 这 样 的 属 性 设 置 方式 , 在 Form 之 间 传 递 信 息 , 返 回 值 也 可 以 。只 需 要 设 定 其 public 或 者 published 节 , 比 如 :Published


Property userid :integer read Fuserid write SetUserId;一 个 LFM 文 件 就 是 这 个 类 的 属 性 的 配 置 , 而 一 个 pp/ pas 文 件 就 是 这 个 类的 头 文 件 和 实 现 。对 比 其 他 语 言 来 说 :*.LFM 等 于 php 下 的 phplib 引 擎 的 模 版 文 件 tpl, 但 php 模 版 里 面 不能 关 联 事 件 。*.pp,pas 文 件 就 是 php 的 业 务 逻 辑 脚 本 。相 对 于 java 来 说 .*.lfm 相 当 于 properties 文 件 , 但 properties 文 件 也 不 能 挂 接 事 件 , 不是 可 视 化 开 发*.pas,*.pp 相 当 于 .java 文 件相 对 于 android 来 说 *.lfm 相 当 于 界 面 的 xml 文 件 , 而 *.pas 相 当 于java 文 件 , 但 是 android 界 面 存 取 是 用 id 号 去 find( 找 ) 控 件 , 而 lazarus 是 直 接名 字 存 取 , 而 且 丰 富 得 多 。


第 七 十 七 章 MVC我 们 是 需 要 MVC 还 是 不 需 要 MVC? 对 于 许 多 开 发 语 言 来 说 , 存 在 代 码 和界 面 混 合 的 开 发 方 式 , 这 就 是 第 一 代 GUI 开 发 方 式 , 我 们 发 现 后 期 维 护 相 当 困难 。 所 以 产 生 了 MVC 的 需 求 , 将 逻 辑 放 Modal , 显 示 放 View, 而 操 作 引 起 的 反映 放 Control 里 面 。 这 样 做 的 好 处 是 维 护 十 分 方 便 , 逻 辑 很 清 晰 , 缺 点 是 开 发 速度 比 较 慢 。 那 么 对 于 RAD 开 发 是 怎 么 处 理 的 呢 ?RAD 工 具 都 有 一 个 共 同 的 处 理方 法 , 将 界 面 配 置 放 在 一 个 文 本 文 件 , 将 control 和 modal,View 的 代 码 放 在 一 起 。这 样 就 达 到 了 界 面 可 视 化 设 计 , 不 影 响 代 码 的 效 果 。 是 介 于 第 一 代 开 发 方 式 和MVC 模 式 之 间 的 方 式 。打 个 比 方 , 如 果 你 熟 悉 PHP.用 lazarus 动 态 创 建 组 件 相 当 于 php 完 全 和 html 混 合 的 开 发 方 式 , 不 可 以可 视 化 设 计 ;用 lazarus 默 认 开 发 方 式相 当 于 php + phplib + html 模 版 的 方 式 ( 模 版 在lazarus 是 lfm 文 件 , *.pp, *.pas 就 是 php 文 件 )当 然 你 也 可 以 用 非 可 视 化 方 式 / 可 视 化 方 式 , 结 合 MVC 的 方 式 , 实 现 更 细 的划 分 。 基 于 快 速 开 发 , 就 不 用 这 种 方 式 。


第 七 十 八 章 B/S 还 是 C/S什 么 是 B/S, 什 么 是 C/S? 我 们 究 竟 应 该 基 于 那 种 模 式 进 行 软 件 开 发 ?B/S 就 是 代 表 浏 览 器 (Browser) 加 服 务 器 (Server) 的 软 件 运 行 模 式 , 而 C/S 代 表的 是 富 客 户 端 (Client) 加 服 务 器 (Server) 的 软 件 运 行 方 式 。B/S 代 表 是 的 Internet 发 展 的 兴 盛 , 代 表 的 是 互 联 网 运 动 的 产 物 , 基 于 其 模式 进 行 软 件 开 发 , 特 点 是 免 维 护 , 部 署 容 易 , 可 以 支 持 大 量 客 户 端 , 不 用 安 装 客户 端 ; 缺 点 是 客 户 端 功 能 太 弱 , 服 务 器 负 载 太 重 , 大 量 浪 费 客 户 端 资 源 , 用 在 html解 析 , 脚 本 语 言 低 效 率 执 行 , 文 本 类 型 的 数 据 解 析 上 了 , 服 务 器 性 能 要 求 高 , 动不 动 就 要 集 群 , 价 格 贵 , 标 准 互 相 兼 容 性 差 , 开 发 成 本 高 , 适 合 互 联 网 应 用 。C/S 代 表 的 是 大 量 原 来 的 原 生 程 序 的 编 写 , 丰 富 的 表 现 手 段 , 数 据 格 式 一 般都 基 于 二 进 制 压 缩 格 式 , 是 LAN( 内 网 ) 应 用 的 代 表 , 客 户 端 部 署 必 须 下 载 一 个 客户 端 , 并 且 进 行 自 动 更 新 。 功 能 强 大 , 基 本 上 什 么 功 能 都 可 以 实 现 。由 于 B/S 有 服 务 端 , 所 以 天 生 具 有 反 盗 版 的 特 性 , 而 C/S 模 式 软 件 具 有 速 度快 , 不 怕 读 大 量 数 据 , 对 于 决 策 支 持 系 统 , 海 量 数 据 分 析 , 海 量 数 据 读 取 ( 比 如VOD), 具 有 不 可 替 代 的 作 用 。这 两 种 方 式 都 有 其 优 点 和 缺 点 。 一 般 一 个 成 熟 的 软 件 项 目 应 该 结 合 二 者 的 优点 , 避 免 二 者 的 缺 点 来 实 现 一 个 混 合 架 构 。


第 七 十 九 章 Internet 宝 库Internet 的 兴 起 , 给 学 习 知 识 带 来 的 前 所 未 有 的 方 便 。 这 是 一 个 知 识 爆 炸 的时 代 , 同 时 也 是 一 个 充 满 垃 圾 信 息 的 时 代 。如 何 学 习 , 学 习 什 么 ? 决 定 我 们 成 就 的 大 小 。别 人 的 只 言 片 语 , 代 码 都 有 可 能 是 我 们 需 要 的 宝 贝 。 同 时 , 我 们 的 回 答 也 是别 人 的 参 考 , 当 你 学 习 到 前 人 的 知 识 的 时 候 , 不 要 忘 记 后 来 者 。对 于 软 件 开 发 ,googlecode ,sourceforge 是 不 可 或 缺 的 , 而 自 己 学 习 的 主 要论 坛 、 社 区 也 是 解 答 疑 惑 的 好 伙 伴 。


第 八 十 章什 么 时 候 用 分 号 什 么 时 候 省 略一 些 童 鞋 说 ,Pascal 最 麻 烦 的 是 不 知 道 什 么 时 候 用 分 号 , 不 知 道 什 么 时 候可 以 省 略 或 者 必 须 不 用 分 号 。总 结 如 下 :IF 语 句 的 Then 和 ELSE 之 间 如 果 没 有 使 用 BEGIN END 就 必 须 不 能 用 分号 , 比 如 :IF a > 1 then b := 2Else b := 3;另 外 如 果 是 一 个 复 合 语 句 或 者 函 数 体 的 最 后 一 句 可 以 不 用 分 号 , 加 上 也 没 有就 是 这 里错 误 , 比 如 :If a > 1 thenBeginC := 2;B := 3EndElseB := 4;这 里 都 可 以 省 略 , 因 为 不 影 响编 译 器 进 行 识 别 。 加 上 也 不 会错 误 。Function TForm1.calc(aAge:integer):integer;BeginResult := 123;Result := 2End;


第 八 十 一 章 ubuntu 安 装 lazarus当 然 你 得 先 安 装 ubuntu 桌 面 版 , 可 以 从 windows xp 下 安 装 , 比 如 安 装ubuntu 8.04LTS 版 本 。安 装 完 毕 后 , 需 要 手 工 apt-get 自 动 安 装 几 个 语 言 包 , 然 后 进 入 系 统 的 语 言设 置 里 面 , 启 用 中 文 , 会 自 动 提 示 有 包 没 有 安 装 , 按 提 示 安 装 上 后 , 整 个 系 统 就完 全 中 文 化 了 。然 后 根 据 需 要 安 装 scim 输 入 法 , 或 者 fcitx 输 入 法 , 并 且 可 以 根 据 本 书 其 他章 节 , 实 现 汉 字 输 入 BUG 的 解 决 。FreePasal 下 载 :http://www.freepascal.org/<strong>Lazarus</strong> 下 载 :http://sourceforge.net/projects/lazarus/files/首 先 , 分 别 下 载 FreePascal 和 <strong>Lazarus</strong> 的 deb 版 本 , 根 据 你 的 需 要 , 下 载 fpc-2.6.0-1.i386.deb.tar 和 lazarus-0.9.30.4.i386.deb.tar 或 最 新 版 本 。然 后 放 在 自 己 家 目 录 ~/进 入 家 目 录Cd ~/把 fpc-2.6.0-1.i386.deb.tar 解 压 到 目 录 ,ubuntu 命 令 :Tar -xvf fpc-2.6.0-1.i386.deb.tarTar -xvf lazarus-0.9.30.4.i386.deb.tar然 后 在 目 录 下 执 行 :sudo dpkg -i *.deb安 装 这 个 deb 包 安 装 到 系 统 , 通 知 系 统 可 以 通 过 apt-get 进 行 下 一 步 安 装 ;最 后 在 终 端 下 执 行 : sudo apt-get install -f这 个 指 令 的 意 思 是 强 制 安 装 刚 注 册 的 的 那 几 个 软 件 包 。 并 且 自 动 寻 找 依 赖 关系 。 所 以 你 的 电 脑 必 须 连 接 到 网 上 。安 装 完 毕 , 将 会 出 现 在 系 统 的 左 上 角 第 一 个 菜 单 里 面 的 编 程 里 面 的lazarus.OK, 然 后 我 们 参 照 第 一 章 , 做 Hello 吧 。


第 八 十 二 章 UI 设 计什 么 是 UI 设 计 ? 这 个 东 西 的 范 围 十 分 广 泛 。 大 致 上 , 和 人 交 互 的 东 西 都 可以 称 作 UI(User Interface)比 如 , 你 每 天 使 用 手 机 , 在 使 用 UI。 你 每 天 使 用 电 梯 , 在 使 用 UI。 你 孩 子每 天 使 用 玩 具 , 在 使 用 UI。 你 去 餐 厅 吃 饭 , 在 使 用 UI。 你 去 玩 一 个 游 戏 , 在 使用 UI。UI 就 是 人 和 其 他 物 体 进 行 交 互 的 方 式 。 他 包 括 操 作 方 法 , 界 面 赋 予 人 感官 体 验 。那 么 , 具 体 到 客 户 端 软 件 开 发 方 面 , 他 涉 及 到 界 面 布 局 是 否 合 理 , 是 否 采 用了 合 理 的 交 互 控 制 , 是 否 符 合 业 务 流 程 , 是 否 符 合 大 多 数 人 使 用 习 惯 , 学 习 时 间是 否 过 长 , 感 官 感 觉 是 否 舒 适 等 等 。当 开 始 一 个 项 目 的 时 候 , 我 们 需 要 首 先 分 析 整 个 系 统 给 谁 用 ? 用 户 水 平 怎 么样 ? 业 务 流 程 是 怎 样 的 ? 如 何 切 分 各 个 模 块 ? 各 个 模 块 之 间 如 何 切 换 ? 是 否 需要 各 个 模 块 进 行 对 比 ? 我 们 有 哪 些 软 硬 件 资 源 可 以 提 供 合 适 的 界 面 ? 比 如 , 键 盘为 主 , 触 摸 屏 为 主 , 还 是 鼠 标 为 主 , 还 是 使 用 操 纵 杆 , 或 者 其 他 外 部 设 备 。输 出 的 设 备 是 什 么 ? 打 印 机 , 大 屏 幕 , 电 子 屏 , 还 是 计 算 机 屏 幕 ?是 给 本 国 人 用 , 还 是 给 多 国 人 用 , 他 们 的 习 惯 是 什 么 ? 对 色 彩 , 形 状 有 什 么避 讳 ?具 体 到 PC 计 算 机 应 用 软 件 来 说 ,UI 经 历 了 如 下 几 个 阶 段 :1. 命 令 行 阶 段 , 这 个 阶 段 的 用 户 都 是 比 较 专 业 的 , 主 要 输 入 设 备 为 键 盘 , 输出 设 备 为 监 视 器 , 每 此 输 入 都 是 按 一 定 顺 序 的 , 显 示 字 符 方 式 的 菜 单 或 者 帮 助 提示 , 如 果 错 误 , 需 要 按 提 示 回 到 某 个 步 骤 ;2. 字 符 图 形 阶 段 , 这 个 阶 段 的 的 用 户 也 相 对 专 业 , 主 要 输 入 设 备 为 键 盘 , 输出 设 备 为 监 视 器 , 主 要 按 回 车 实 现 输 入 单 元 格 ,tab 键 可 以 跳 转 到 下 个 或 上 个 单元 格 ;3. 鼠 标 字 符 图 型 阶 段 , 这 个 阶 段 的 用 户 就 可 以 面 向 普 通 用 户 , 主 要 输 入 设 备为 键 盘 , 输 出 设 备 为 监 视 器 , 辅 助 输 入 设 备 为 鼠 标 , 打 印 机 等 。


4. 图 形 化 界 面 , 主 要 输 入 设 备 为 键 盘 , 鼠 标 , 输 出 设 备 为 监 视 器 , 打 印 机 等 ;5. 互 联 网 阶 段 , 主 要 输 入 设 备 为 鼠 标 , 键 盘 , 输 出 设 备 为 监 视 器 ;6. 触 摸 屏 和 其 他 方 式 混 合 阶 段 , 主 要 输 入 设 备 为 触 摸 屏 , 键 盘 , 鼠 标 , 输 出设 备 为 监 视 器 ;也 就 是 说 , 随 着 人 机 界 面 的 越 来 越 复 杂 化 , 给 我 们 软 件 开 发 提 出 越 来 越 多 的挑 战 , 如 何 设 计 优 秀 的 人 机 界 面 , 将 是 考 验 一 个 软 件 开 发 人 员 和 软 硬 件 企 业 的 一大 难 题 。具 体 到 一 个 客 户 端 应 用 软 件 来 说 , 我 们 可 能 需 要 结 合 网 页 , 触 摸 屏 等 多 种 界面 , 来 完 成 一 个 软 件 的 设 计 工 作 。首 先 我 们 避 开 复 杂 的 , 谈 谈 仅 仅 是 PC 客 户 端 软 件 的 设 计 。PC 客 户 端 软 件 , 目 前 的 交 互 模 式 有 如 下 一 些 类 型 :1. 闪 屏 窗 口 (splash);2. 登 录 窗 口 ;3. 主 窗 口 MDI 界 面 ;4. 主 窗 口 MPI 界 面 ;5. 主 窗 口 单 窗 口 界 面 ;6. 子 窗 口 MDI 界 面 ;7. 子 窗 口 MPI 界 面 ;8. 子 窗 口 模 态 界 面 ;9. 子 窗 口 非 模 态 界 面 ;10. 设 定 窗 口 , 左 分 类 , 右 内 容 界 面 ;11. 导 航 Notebook 界 面 ;12. 主 窗 口 左 边 导 航 横 向 tabpage, 右 边 内 容 界 面 ;13. 左 边 tree, 右 边 内 容 界 面 ;14.DOCK 界 面 ;15.Top+LEFT+Main 三 分 栏 界 面 ;16.9 宫 格 /N 宫 鸽 界 面 ;17. 左 边 手 风 琴 、 分 类 导 航 , 右 边 内 容 界 面 ;18. 四 周 工 具 栏 , 中 间 内 容 界 面 ;


上 面 还 只 是 从 大 的 界 面 布 局 划 分 , 下 面 是 根 据 业 务 类 型 来 设 计 。1. 非 数 据 库 处 理 类 , 比 如 图 片 , 视 频 , 文 字 处 理 , 工 具 软 件 等 , 这 些 不 保 存数 据 库 , 不 使 用 grid,dataset. 布 局 是 尽 可 能 将 主 要 元 素 占 据 最 大 的 位 置 , 其 他 位置 ( 主 要 是 四 周 ) 布 置 按 钮 。2. 数 据 库 , 字 段 比 较 少 的 列 表 信 息 。3. 数 据 库 , 字 段 比 较 少 的 编 辑 , 可 以 和 列 表 信 息 一 个 界 面 处 理 , 以 减 少 用 户切 换 界 面 次 数 。4. 数 据 库 , 字 段 比 较 多 的 编 辑 , 列 表 查 询 和 编 辑 界 面 分 开 , 以 让 用 户 编 辑 信息 的 界 面 更 加 大 , 如 果 超 过 一 屏 可 以 处 理 的 能 力 , 需 要 增 加 分 页 , 或 者 滚 动 条 ,从 而 减 少 切 换 。具 体 应 用 需 要 根 据 软 件 提 供 的 功 能 , 进 行 界 面 的 设 计 。具 体 到 界 面 元 素 , 有Label,Edit,Combobox,Listview,RichText,Memo,MainMenu,Pagecontrol, Image 等 。虽 然 有 许 多 复 杂 的 构 成 元 素 来 构 成 UI. 但 是 其 设 计 是 有 一 定 规 律 可 遵 循 的 。大 致 总 结 如 下 :1. 要 遵 循 整 齐 , 整 洁 的 规 则 ;2. 不 放 无 效 的 界 面 元 素 ;3. 遵 循 业 务 流 程 的 顺 序 ;4. 遵 循 人 脑 的 逻 辑 思 考 习 惯 ;5. 遵 循 清 晰 , 可 阅 读 的 规 则 ;6. 适 当 的 限 制 用 户 ;7. 合 理 的 提 示 , 帮 助 ;8. 清 晰 的 描 述 ;那 么 我 们 来 看 一 看 一 个 界 面 的 具 体 设 计 :示 例 对 话 框


我 们 来 分 析 一 下 这 个 例 子 :逻 辑 顺 序好 的 界 面 应 该 符 合 人 的 思 维 逻 辑 , 如 果 是 颠 倒 我 们 的 思 维 逻 辑 , 这 样 的 界 面很 糟 糕 。 比 如 :布 局 美 观如 图 式 的 布 局 就 很 合 理 , 如 果 我 们 变 一 下 , 看 看 后 面 的 布 局 。糟 糕 的 布 局


我 们 再 来 看 一 个 Form再 看 修 改 版 本还 不 太 好 , 再 修 改还 缺 点 什 么 ?


颜 色 似 乎 太 土 , 改 变这 个 对 话 似 乎 好 些 。通 过 这 个 例 子 , 我 们 大 致 上 可 以 学 习 到 UI 界 面 设 计 的 精 髓 , 其 他 界 面 设 计的 模 式 实 际 上 是 和 这 个 例 子 相 似 的 。对 于 世 界 上 大 多 数 人 来 说 , 有 一 个 从 上 到 下 从 左 到 右 的 习 惯 。有 前 面 介 绍 的 就 是 指 的 后 面 的 东 西 的 思 考 习 惯 。那 么 界 面 设 置 好 了 , 接 下 来 做 什 么 , 我 们 还 需 要 将 界 面 可 输 入 部 分 设 置 跳 转顺 序 。然 后 , 我 们 在 保 存 和 里 面 应 该 加 如 数 据 有 效 性 检 查 , 比 如 , 当 用 户 什 么 都 没有 输 入 的 时 候 , 给 于 提 示 , 如 下 代 码 :If edtUserName.text = '' thenBeginshowmessage(' 请 输 入 用 户 姓 名 !');Exit;End;如 果 我 们 用


showmessage(' 必 须 输 入 用 户 姓 名 '); 可 能 是 不 够 友 好 的 。。 最 后 才 实 现 真 实 的 提 交 , 然 后 捕 获 提 交 是 否 成 功 , 给 于 提 示 。拓 展 训 练 :1. 给 必 须 输 入 的 框 加 上 颜 色 , 或 者 星 号 提 示 ;2. 给 必 须 输 入 的 提 示 后 加 入 setfocus 代 码 ;3. 调 整 上 面 界 面 不 够 友 好 的 地 方 ;那 么 我 们 再 来 看 一 些 经 典 的 界 面 吧 , chrome 模 仿 :这 个 界 面 将 我 们 常 见 的 pagecontrol 进 行 了 美 化 , 采 用 了 gdi+ ,directdraw 加速 的 方 式 实 现 漂 亮 的 效 果 , 再 结 合 notebook 实 现 翻 页 。左 侧 导 航


这 个 左 侧 导 航 组 件 , 实 现 了 后 台 页 面 缓 冲 , 前 后 交 换 的 方 式 实 现 不 闪 烁 的 切换 页 面 , 并 且 让左 边 书 签 颜 色 和 右 边 内 容 融 合 。Splash这 个 界 面 采 用 了 作 图 软 件 进 行 了 左 边 , 和 上 边 的 高 光 效 果 的 处 理 , 而 对 右 边和 下 面 做 了 阴 影 的 处 理 , 文 字 也 做 了 同 样 的 处 理 , 显 得 很 有 立 体 感 。还 是 Tpicshow 的 复 合 界 面


这 个 界 面 组 合 了 Pagecontrol,picshow, 而 pagecontrol 里 面 使 用 了 radio group进 行 分 组 , 再 用 缩 进 对 齐 的 方 式 实 现 了 界 面 的 美 化 。 文 字 标 签 后 面 有 : 表 示 内 容在 后 面 , 而 check,radio 都 没 有 冒 号 。 下 面 再 用 状 态 栏 进 行 了 简 要 的 描 述 。


第 八 十 三 章 <strong>Lazarus</strong> 和 mongo Mud 游 戏如 果 您 是 曾 经 玩 过 Mud 游 戏 ( 一 种 文 字 游 戏 ) 的 玩 家 , 那 么 你 一 定 对 这 样 的 信息 有 兴 趣东 大 街>score姓 名 : 李 逍 遥 年 龄 :14 岁 饮 水 :■■■■■■■ 饥 饿 :■■■■■■■>skills基 本 拳 脚 23223/200 天 下 无 双 基 本 剑 法 19238/198 天 下 无 双九 阳 神 功 23232/192 天 下 无 双 太 极 剑 法 232/30 马 马 虎 虎那 么 , 也 就 是 说 上 面 的 数 据 , 我 们 用 常 规 的 SQL 数 据 库 , 要 分 成Score 表PlayerIDRoleNameAgeWatorFoodPlayersSkills 表PlayerIDSkillIDSkillLevelSkillExpSkills 表SkillIdSkillName再 用 条 件 , 主 键 等 对 多 个 表 查 询 , 才 可 以 获 取 到 全 部 信 息 , 比 较 麻 烦 吧 ?


而 这 个 游 戏 的 引 擎 , 就 是 Mudos, 是 怎 么 存 储 这 些 数 据 的 呢 ?Mixer 这 个 数 据 类 型 , 其 实 就 是 JSON 数 据 格 式 类 似 的 一 种 结 构 , 支 持 自 己嵌 套 , 这 种 数 据 结 构 就 是 存 储 这 类 数 据 非 常 好 的 数 据 结 构 。MongoDB 底 层 就 用 的 这 种 数 据 结 构 --BSON。上 面 的 结 构 , 重 新 构 造 一 下 :Palyers{PlayerID:102,RoleName: 李 逍 遥 ,Age:14,Wator:16,Food,16Skills[{SkillID:1, skillName:' 基 本 拳 脚 ',SkillName:SkillLevel:200,SkillExp:23223,LevelName:' 天 下 无 双 ' },{skillid:2,skillName:' 基 本 剑 法 ',skillLevel:198,SkillExp:19238,LevelName:' 天下 无 双 '},{SkillID,3,SkillName:' 九 阳 神 功 ',SkillLevel:192,SkillEp:23232:LevelName:' 天下 无 双 '},{SkillID:4,SkillName:' 太 极 剑 法 ',SkillLevel:30,SkillExp:232,LevelName:' 马 马虎 虎 '}]}我 们 可 以 看 到 , 这 个 数 据 结 构 , 是 自 包 含 的 , 减 少 了 关 系 数 据 库 的 键 , 但 是也 增 加 了 冗 余 的 Key 和 Value。此 数 据 结 构 可 以 表 达 许 多 数 据 结 构 。Mongo 是 当 前 最 热 门 的 NoSQL 方 案 , 那 么 lazarus 是 否 也 支 持 这 个 好 东 东呢 ?没 错 , 他 是 支 持 的 。关 于 他 的 支 持 方 案 有 几 种 :1. 官 方 支 持 : 官 方 只 给 出 了 一 个 0.71 版 本 的 c 库 , 要 自 己 编 译 , 然 后 用 delphi xe调 用 的 wrapper 也 有 了 , 我 们 可 以 在 他 的 基 础 上 创 建 lazarus 版 本 , 优 点 是 支 持 所


有 功 能 , 缺 点 也 很 明 显 , 需 要 2 个 dll 支 持 ;2. 第 三 方 库 , 优 点 是 没 有 dll 库 , 缺 点 是 没 有 完 全 实 现 ;3. 自 己 按 mongo 官 方 10gen 的 资 料 编 写 驱 动 ;笔 者 在 官 方 的 基 础 上 实 现 了 修 改 版 本 , 并 且 将 其 测 试 程 序 也 正 确 实 现 了 。我 们 可 以 看 到 lazarus 存 取 Mongodb 是 非 常 优 雅 的 , 直 接 上 图 :这 个 是 地 址 簿 的 演 示 程 序 。代 码 风 格 :对 象 映 射 ?Yes值 对 象 ? YES和 这 些 技 术 很 像 。注 : 此 程 序 的 完 整 代 码 , 在 本 书 附 源 码 里 有 。


第 八 十 四 章借 鉴 Rails 的 规 则Rails 是 习 惯 约 定 优 于 配 置 , 借 鉴 到 lazarus, 我 们 可 以 运 用 到 :1. 项 目 结 构Source 放 源 码Doc 放 文 档Help 放 帮 助Componets 放 组 件Test 放 测 试2. 对 象 命 名数 据 库 表 products那 么 其 基 本 浏 览 界 面 窗 体 tfrmProductsList新 增 加 界 面 TfrmProductNew修 改 界 面 TfrmProductEdit相 应 的 窗 体 单 元 名 uProductsList呼 叫 的 菜 单 项 ,mnuProductsList视 图 vProductsList 等 等也 就 是 说 , 整 个 开 发 中 的 所 有 资 源 , 都 用 前 缀 区 分 类 别 , 用 相 似 的 名 字 表 达同 类 的 元 素 。这 样 我 们 在 维 护 代 码 的 时 候 , 就 能 很 快 找 到 自 己 需 要 的 东 西 。


第 八 十 五 章借 鉴 SSH 的 action 模 式没 错 , 比 如 我 们 在 实 现 一 个 MDI 界 面 的 时 候 , 我 们 可 以 这 样 :菜 单 项 : mnuProductListmnuVendormnuSupplier然 后 他 们 的 处 理 事 件 都 是 一 个 相 同 的 事 件 挂 接mnuBaseInfoOnclick代 码 是Var sName:string;sName :=lowercase((sener as tmenuitem).name);If sName='mnuproductlist' thenBeginfrmProductList.show;End;If sName = 'mnuvendor' thenBeginfrmVendor.show;End;怎 么 样 ? 代 码 是 否 足 够 清 晰 ?


第 八 十 六 章 事 件 驱 动 还 是 非 事 件 驱 动事 件 驱 动 本 来 是 一 种 编 程 的 很 大 的 进 步 , 通 过 Form 设 计 器 , 我 们 可 以 快 速生 成 数 据 库 编 辑 界 面 。 但 是 , 为 什 么 完 全 基 于 事 件 的 程 序 员 被 许 多 人 看 不 上 ? 现在 有 的 人 认 为 玩 RAD 的 人 不 是 真 正 的 程 序 员 。那 么 如 何 让 别 人 改 变 这 种 印 象 呢 ?这 就 需 要 改 变 我 们 自 己 , 一 般 说 来 , 设 计 单 机 的 数 据 库 软 件 , 采 用 事 件 驱 动机 制 , 还 是 比 较 好 的 。 但 是 事 件 驱 动 带 来 的 麻 烦 是 , 我 们 必 须 了 解 事 件 发 生 的 时机 , 各 个 事 件 的 顺 序 。举 例 说 , 我 们 在 form 上 放 一 个 database, 一 个 dataset, 一 个 datasource, 一 个dbgrid 和 一 个 datanavigator 组 件 , 就 立 即 可 以 实 现 对 一 个 数 据 表 的 编 辑 功 能 。 这是 许 多 教 程 , 包 括 本 教 程 前 面 讲 到 的 。 这 就 是 只 会 拖 拉 几 个 控 件 就 能 编 程 的 程 序员 。那 么 这 么 做 有 什 么 坏 处 呢 ?首 先 , 这 个 程 序 不 是 多 用 户 的 , 对 单 用 户 是 没 有 问 题 的 。然 后 , 在 这 个 水 平 , 我 们 不 知 道 lcl 框 架 做 了 什 么 , 发 出 了 什 么 sql 指 令 ,这 对 于 我 们 的 进 步 是 非 常 不 利 的 。也 就 是 说 , 在 编 写 多 用 户 程 序 的 时 候 , 涉 及 到 两 个 问 题 :1. 多 用 户 并 发 ;2. 使 用 感 知 还 是 非 感 知 控 件 的 问 题 ;下 面 我 们 就 这 两 个 问 题 , 分 两 章 讲 解


第 八 十 七 章多 用 户 并 发那 么 什 么 是 多 用 户 并 发 ?我 们 知 道 , 数 据 库 对 多 用 户 并 发 , 是 进 行 了 处 理 的 , 为 什 么 还 要 提 出 这 样 的议 题 ?没 错 , 数 据 库 是 多 用 户 进 行 了 并 发 控 制 的 , 但 他 是 微 观 上 的 控 制 。 对 宏 观 的控 制 , 我 们 仍 然 要 在 代 码 实 现 。举 例 说 明 :用 户 A 读 到 产 品 信 息 , 价 格 是 10;用 户 B 读 到 产 品 信 息 , 价 格 也 是 10;用 户 A 此 时 修 改 产 品 价 格 为 20;用 户 B 也 修 改 产 品 价 格 为 30;这 个 时 候 用 感 知 控 件 的 问 题 就 出 来 了 , 究 竟 最 终 价 格 应 该 是 多 少 ?那 么 上 面 的 程 序 , 在 某 种 意 义 上 是 合 理 的 , 就 是 说 以 最 终 用 户 修 改 为 准 。但 是 在 某 些 领 域 , 比 如 银 行 , 这 样 的 修 改 是 不 合 理 的 , 这 种 现 象 称 之 为丢 失 更 新 (1);我 们 需 要 改 进 算 法 , 也 就 是 执 行Update products set price=30 where price=20 and product_id=1;这 样 的 语 句 去 确 认 , 自 己 的 修 改 是 基 于 老 的 版 本 的 ;另 外 的 策 略 是 , 在 表 products 建 立 一 个 版 本 机 制 (sqlserver 的 timestamp), 一个 字 段 记 录 本 行 的 版 本 rowVersion, 可 以 用 触 发 器 , 自 动 更 新 这 个 字 段 。一 旦 发 现 自 己 修 改 的 是 别 人 修 改 过 的 版 本 , 就 提 示 用 户 无 法 更 新 , 并 且 刷 新出 最 新 的 记 录 。那 么 这 就 涉 及 到 使 用 非 感 知 控 件 的 问 题 , 下 一 章 我 们 来 解 释 怎 么 做 。


第 八 十 八 章感 知 还 是 非 感 知对 于 上 一 章 讲 到 的 问 题 , 丢 失 更 新 , 我 们 可 以 使 用 TupdateSql 控 件 , 其 where语 句 里 面 要 判 断 老 的 版 本 , 如Update products where price=:price where price=:OLD_price andproduct_id=:OLD_product_id注 意 , 上 面 的 OLD_ 是 Tupdatesql 组 件 定 义 的 前 缀 , 也 就 是 说 他 会 将 老 的 值去 替 换 到 这 个 位 置 。Tupdatesql 还 有 一 个 作 用 是 , 查 询 关 联 表 , 更 新 其 中 一 个 表 .那 么 对 于 不 习 惯 使 用 Tupdatesql 的 童 鞋 , 我 们 可 以 使 用 非 感 知 控 件 进 行 编辑 , 用 SQL 指 令 的 形 式 , 对 操 作 进 行 并 发 控 制 。比 如 一 个 Edit1 隐 藏 ,text 是 product_id一 个 edit3 隐 藏 ,text 是 老 的 价 格一 个 edit2 显 示 价 格 , 供 编 辑更 新 的 指 令 是 .Query1.close;Query1.sql.text := 'update products set price =' + edit2.text + ' where price='+edit3.text + ' and product_id=' + edit1.text;Query1.execsql;备 注 : 上 面 对 象 名 字 , 应 该 取 得 更 加 有 意 义 , 此 处 只 是 为 了 演 示 方 便 。那 么 现 在 又 带 出 另 外 一 个 问 题 , 如 果 用 户 在 edit2.text 里 输 入 了 特 殊 字 符 ,非 数 字 , 将 会 导 致 sql 语 句 错 误 , 怎 么 办 ?3 种 解 决 方 案 :1.edit2 使 用 tnumericedit2. 对 edit2.text 进 行 过 滤3. 用 参 数 化 查 询 方 式 ;


第 八 十 九 章 OLEVariant 和 Int64 转 换我 们 来 写 一 个 测 试 程 序 如 下unit Unit1;{$mode objfpc}{$H+}interfaceusesClasses, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,uInt64OleVariant;type{ TForm1 }TForm1 = class(TForm)Button1: TButton;Button2: TButton;procedure Button1Click(Sender: TObject);procedure Button2Click(Sender: TObject);private{ private declarations }public{ public declarations }end;varForm1: TForm1;implementation{$R *.lfm}{ TForm1 }procedure TForm1.Button1Click(Sender: TObject);var olev:olevariant;


int6:int64;beginint6 := 2323432232323;showmessage(inttostr(int6));olev :=int6;showmessage(inttostr(olev)); //-145074813end;procedure TForm1.Button2Click(Sender: TObject);var olev:olevariant;int6:int64;beginint6 := 2323432232323;showmessage(inttostr(int6));olev := Int64ToOleVar( int6);showmessage(inttostr(OleVarToInt64(olev))); // 正 确end;procedure TForm1.Button3Click(Sender: TObject);var olev:olevariant;int6:int64;beginint6 := 2323432232323;showmessage(inttostr(int6));olev := int64( int6);showmessage(inttostr(int64(olev))); //-145074813end;end.我 们 可 以 看 到 , 红 色 部 分 , 前 面 button1 click 的 时 候 显 示 的 int64 数 据 是 错误 的 。而 , 即 使 强 制 指 定 类 型 , 仍 然 不 行 , 见 Button3Click


所 以 我 们 可 以 编 写 代 码 支 持 相 互 转 换 ,Button2Click 的 就 是 正 确 的 了 , 这 个 错误 在 delphi 7 一 样 存 在 。同 样 , 由 于 mongodb 驱 动 的 BSON 类 函 数 , 也 使 用 了 int64, 所 以 在 程 序 编码 的 时 候 , 我 们 也 要 使 用 Int64ToOleVar(1234567890123), 强 制 转 换 类 型 。 用int64() 转 换 无 效 。此 代 码 见 本 书 附 源 码 。


第 九 十 章数 据 库 组 件 的 选 择对 于 C 语 言 来 说 , 写 一 个 Grid 组 件 , 需 要 数 千 行 的 代 码 , 同 样 对 于 <strong>Lazarus</strong>也 是 , 而 C 无 法 实 现 所 见 所 得 的 表 单 设 计 (Form Designer), 而 <strong>Lazarus</strong> 有 许 多 现 成的 控 件 。 除 了 本 书 介 绍 的 ZeosDBO 这 个 大 小 通 吃 的 组 件 之 外 , 还 有 系 统 自 带 的连 接 组 件 , 还 有 FIBPlus,IBObjects,UIB 等 等 其 他 第 三 方 组 件 都 支 持 <strong>Lazarus</strong>。 除了 这 些 连 接 组 件 外 , 数 据 库 组 件 还 有 感 知 的 可 视 化 组 件 , 比 如 本 书 介 绍 的 :1. 系 统 自 带 DBGrid, DBEdit...;2. 第 三 方 组 件 KGrid, 这 个 组 件 最 大 的 特 点 就 是 可 以 插 入 任 意 组 件 到 Grid 里面 , 实 现 融 合 式 Grid;3. 第 三 方 组 件 RxNew 则 是 另 外 一 个 风 格 , 可 以 快 速 实 现 多 表 头 , 表 格 结 尾实 现 合 计 ,KeyValue 自 动 对 应 等 等 。一 般 说 来 我 们 选 择 组 件 要 基 于 这 样 几 个 原 则 :1. 资 料 丰 富 ;2. 成 熟 稳 重 ;3. 轻 量 级 , 容 易 和 其 他 组 件 共 存 , 不 干 扰 其 他 组 件 ;4.BUG 少 , 有 源 码 , 这 样 我 们 就 可 以 在 发 现 BUG 的 第 一 时 间 , 将 BUG 扼杀 在 摇 篮 里 。一 般 来 说 , 专 门 针 对 某 类 数 据 库 的 组 件 , 能 够 提 供 更 加 细 致 的 控 制 , 而 通 用组 件 更 加 适 合 数 据 库 类 型 有 可 能 需 要 更 改 的 场 合 。


第 九 十 一 章 数 据 类 型 之 间 转 换DateTimeToFileDate 函 数 将 TDatetime 的 日 期 格 式 转 换 为 DOS 的 日 期 格 式DateTimeToStr 函 数 将 日 期 时 间 格 式 转 换 为 字 符 串DateTimeToString 函 数 将 日 期 时 间 格 式 转 换 为 字 符 串DateToStr函 数 将 日 期 格 式 转 换 为 字 符 串FileDateToDateTime 函 数 将 DOS 的 日 期 格 式 转 换 为 Tdatetime 的 日 期 格 式FloatToDecimal 函 数 将 浮 点 数 转 换 为 十 进 制 数FloatToStrF 函 数 将 浮 点 数 转 换 为 字 符 串FloatToStr函 数 将 浮 点 数 转 换 为 字 符 串FloatToText 函 数 将 给 定 的 浮 点 数 转 换 为 十 进 制 数FloatToTextFmt 函 数 将 给 定 的 浮 点 数 转 换 为 十 进 制 数IntToHexIntToStr将 整 型 数 转 换 为 十 六 进 制 数将 整 型 数 转 换 为 字 符 串StringToWideChar 函 数 将 ANSI 字 符 串 转 换 为 UNICODE 字 符 串StrToDate函 数 将 字 符 串 转 换 为 日 期 格 式StrToDateTime函 数 将 字 符 串 转 换 为 日 期 / 时 间 格 式StrToFloatStrToInt函 数 将 给 定 的 字 符 串 转 换 为 浮 点 数函 数 将 字 符 串 转 换 为 整 型StrToInt64StrToIntDefStrToTime函 数 将 字 符 串 转 换 为 整 型 或 默 认 值函 数 将 字 符 串 转 换 为 时 间 格 式TextToFloat 函 数 将 字 符 串 ( 以 NULL 结 束 的 格 式 ) 转 换 为 浮 点 数TimeToStr函 数 将 时 间 格 式 转 换 为 字 符 串VarToDateTime函 数 将 给 定 的 变 体 转 换 为 日 期 时 间WideCharLenToString 函 数 将 ANSI 字 符 串 转 换 为 UNICODE 字 符 串WideCharToString 函 数 将 UNICODE 字 符 串 转 换 为 ANSI 字 符 串WideCharToStrVar 函 数 将 UNICODE 字 符 串 转 换 为 ANSI 字 符 串 变 量


lazarus byte 数 组 怎 么 转 换 成 Stringconsta: array[0..5] of Byte = (4,5,1,8,0,7);vari: Integer;str: String;beginstr:= '';for i:= 0 to High(a) dostr:= str + IntToStr(a[i]);ShowMessage(str);end;lazarus 中 String,PChar,PByte,Array of Char,Array of Byte 转 换 :var s:string;pc:pchar;pb:pbyte;ac:array[1..100] of char;ab:array[1..100] of byte;i:integer;begin s:='this is a test';pc:=pchar(s); //string->pcharpb:=pbyte(pc); //pchar->pbytefor i:=1 to length(s) dobeginac[i]:=s[i]; //string->arrary of charab[i]:=byte(s[i]); //string->arrary of byteend;s:=pc; //pchar->strings:=string(pb); //pbyte->strings:=c; //arrary of char->string;


end;一 般 来 说 各 种 数 据 类 型 和 字 符 串 类 型 之 间 比 较 容 易 转 换 , 而 变 体 类 型 可 以存 放 任 何 类 型 的 变 量 。 我 们 常 用 的 主 要 是 字 符 串 和 其 他 类 型 的 转 换 , 使 用 转 换 函数 进 行 。 而 兼 容 类 型 的 变 量 是 可 以 直 接 赋 值 的 比 如 :Var a:integer;B :word;BeginB := a;A := b;哪 些 是 兼 容 的 呢 ?Integer ,short,word,dword,longword 等 序 数 类 型 是 相 互 兼 容 的 , 只 要 取 值 范 围没 有 超 出 , 其 他 类 型 和 他 赋 值 要 转 换 , 比 如 string 转 换 到 整 数 需 要 strtoint, 反 向需 要 inttostr。小 数 类 型 是 兼 容 整 数 类 型 的 , 但 反 过 来 就 需 要 用 trunc,floor,round 等 函 数 丢弃 小 数 部 分 。var a:integer;b :word;c : real;begina := 1;b := a;a := b;c := a;a := round(c);// 这 里 决 定 怎 么 处 理 小 数 点 以 后 的 值同 样 , 枚 举 类 型 和 整 形 也 要 进 行 转 换 , 布 尔 型 , 字 符 型 和 整 形 之 间 都 要 用 ord函 数 进 行 转 换 , 而 反 向 转 换 就 比 较 麻 烦 。有 的 类 型 到 其 他 类 型 的 转 换 需 要 经 过 多 次 转 换 , 比 如 字 符 串 数 组 里 面 保 存 了一 个 数 字 123.4 , 分 别 用 了 5 个 字 符 数 存 储 组 单 元 , 要 转 换 到 小 数 , 就 需 要 先 转 换到 字 符 串 , 然 后 用 strtofloat 来 进 行 转 换 。


取 值 范 围 比 较 小 的 变 量 保 存 类 型 和 他 相 似 但 是 取 值 范 围 比 他 大 的 类 型 , 就 可能 发 生 数 据 类 型 丢 失 的 现 象 。祖 先 类 型 的 类 变 量 , 可 以 保 存 子 类 的 变 量 , 使 用 的 时 候 进 行 强 制 转 换 , 比 如变 量Var o:TObject;就 可 以 保 存 任 何 集 成 于 TObject 的 类 变 量 ( 就 是 对 象 啦 )。比 如O := Button1;(O as TButton).caption := ' 对 象 类 型 转 换 ';


第 九 十 二 章 数 据 库 开 发 要 点对 于 数 据 库 开 发 来 说 , 最 重 要 的 是 什 么 ? 这 是 许 多 教 程 缺 失 的 部 分 。 我 们 下面 来 探 讨 一 下 。第 一 节 掌 握 SQL 命 令 , 基 本 数 据 类 型 , 和 别 的 数 据 库 系 统 的 不 一 样 的 地方比 如 firebird 支 持 date,time 类 型 , 其 他 数 据 库 多 数 不 支 持 ;ms sqlserver 支 持 timestamp ,firebird 也 有 , 但 是 mssql 的 是 一 个 行 版 本 号 ,相 当 于 lazarus 的 int64, 而 firebird 的 timestamp 相 当 于 lazarus 的 datetime;要 了 解 你 的 开 发 工 具 和 数 据 库 引 擎 的 配 合 情 况 , 有 没 有 bug, 如 何 避 免 。


第 二 节 游 标游 标 的 使 用 比 较 方 便 , 相 当 于 lazarus 的While not query1.eof doBegin// 处 理 逻 辑Query1.next;End;并 且 游 标 是 每 读 一 行 , 发 出 一 次 查 询 , 比 上 面 逻 辑 还 慢 , 相 当 于 循 环 中 发 出 sql指 令 。尽 量 不 用 游 标 , 但 是 要 做 到 这 点 , 需 要 对 sql 指 令 十 分 熟 悉 。


第 三 节 . 准 从 范 式也 许 你 有 这 样 的 设 计Products(product_id,product_name,price)Purchase_detail(product_id,product_name,real_price,qty)我 们 可 以 看 到 上 面 的 product_name 是 冗 余 的 , 在 某 种 情 况 下 , 这 样 设 计 可能 是 必 须 的 , 但 大 多 数 情 况 下 , 可 能 是 错 误 的 , 非 常 容 易 导 致 数 据 的 不 一 致 性 ;


第 四 节 用 批 量 查 询 代 替 多 次 查 询 ;比 如 你 有 若 干 配 置 , 在 一 个 表 里 面 叫 做 settings(setting_id ,setting_name)你 打 算 这 样 取Function getSetting(Asetting_id:string):string;// 返 回 设 置 字 符 串BeginDm.query1.close;Dm.query1.sql.text := 'select settings_name from settings where setting_id=' +quotedstr(setting_id);Dm.query1.open;Result := dm.query1.fields[0].asstring;End;没 错 , 这 段 代 码 怎 么 看 都 没 有 问 题 。 问 题 在 哪 里 ?问 题 出 在 如 果 配 置 有 100 条 , 将 发 出 100 次 查 询 。我 们 是 可 以 改 进 的 , 比 如 :Type Tsettings = class;PrivateFconnection :Tzconnection;Fquery:tzquery;FKey:Tstringlist;FValues:Tstringlist;PublicFunction LoadSettings():boolean;Function GetSettings(asetting_id:string):string;End;// 省 略 ....主 要 在 加 载 这 一 一 次 加 载 .Function TSettings.loadSettings():boolean;BeginFquery.close;Fquery.sql.text :='select * from settings';


Fquery.open;While not fquery.eof doBeginFkey.add(fquery.fieldbyname('setting_id').asstring;Fvalue.add(fquery.fieldbyname('setting_name').asstring;fQuery.next;End;End;上 面 之 是 一 个 算 法 描 述 , 当 然 我 们 可 以 考 虑 加 上 前 面 只 加 载 一 行 的 情 况 , 进行 刷 新 , 就 解 决 了 配 置 及 时 获 取 单 个 的 问 题 。上 面 我 们 也 用 到 了 内 存 数 据 保 存 查 询 结 果 , 从 而 能 够 大 大 加 快 我 们 程 序 的 速度 。


第 五 节 索 引 问 题一 般 来 说 , 数 据 库 的 索 引 要 根 据 业 务 语 句 来 进 行 建 立 , 比 如 有 语 句 ,Select f1,f2 from table1 where f3 like 'abc%' and f4='2012-3-3';这 样 的 语 句 , 就 要 在 f3,f4 字 段 上 建 立 索 引 , 主 键 上 自 动 会 创 建 索 引 。 所 谓索 引 就 是 一 个 更 小 的 表 , 由 系 统 维 护 , 并 且 一 般 都 是 使 用 B 树 , 或 者 hash 模 式进 行 查 找 的 , 通 过 建 立 多 个 这 样 的 目 录 表 , 方 面 我 们 查 询 语 句 快 速 查 到 我 们 需 要的 信 息 。 典 型 的 以 空 间 换 时 间 的 方 法 。


第 六 节 使 用 事 务对 于 事 务 要 求 高 的 数 据 库 应 用 来 说 , 事 务 控 制 非 常 重 要 , 使 用 事 务 要 遵 循 几个 原 则 :1) 事 务 里 面 只 包 含 必 须 的 操 作 , 也 是 防 止 死 锁 和 提 高 服 务 器 性 能 ;2) 事 务 里 面 不 要 包 含 用 户 界 面 交 互 的 代 码 , 防 止 死 锁 ;3) 事 务 最 好 在 服 务 器 端 进 行 , 可 以 放 在 程 序 里 面 , 也 可 以 放 在 存 储 过 程 里 面 。这 样 可 以 减 少 因 为 通 信 延 迟 导 致 的 服 务 器 并 发 性 能 降 低 , 这 也 是 3 层 数 据 库 开 发的 好 处 之 一 。


第 七 节 清 楚 的 知 道 业 务 代 码 所 有 查 询 语 句这 是 因 为 索 引 , 优 化 都 需 要 知 道 业 务 代 码 所 有 的 查 询 语 句 , 比 如 下 面 的 语 句就 要 进 行 优 化 :Select * from table1 where cast(date1 as date) = '2012-2-3';因 为 等 号 左 边 的 字 段 每 行 都 要 进 行 转 换 再 进 行 比 较 , 会 导 致 表 扫 描 。 速 度 很慢 。 这 就 需 要 在 数 据 库 设 计 期 , 考 虑 后 期 查 询 方 便 。


第 八 节 不 要 在 事 务 中 挂 起事 务 中 挂 起 , 将 会 导 致 表 被 锁 死 , 其 他 人 无 法 操 作 , 特 别 是 zeosdbo 组 件 里面 , 象 这 样 。Zconnection1.begintransaction;Showmessage(' 保 存 成 功 !');Zconnection.commit;应 该 将 提 示 信 息 , 放 到 事 务 操 作 外 面 。


第 九 节 不 要 打 开 很 大 的 数 据 集数 据 集 每 次 打 开 , 都 会 消 耗 服 务 器 内 存 ,Cpu 资 源 , 所 以 我 们 一 般 需 要 限 定客 户 打 开 的 信 息 量 的 多 少 . 一 般 我 们 都 要 设 置 日 期 条 件 , 其 他 条 件 等 进 行 数 据 的查 询 , 减 少 回 读 的 数 据 量 。这 需 要 根 据 业 务 量 , 和 业 务 类 型 进 行 设 定 , 比 如 , 我 们 的 一 种 单 据 , 有 草 稿和 正 式 两 种 状 态 , 一 般 我 们 需 要 关 心 的 是 当 前 这 一 个 月 的 单 据 。我 们 就 默 认 打 开 当 前 这 个 月 的 单 据 索 引 ( 表 头 ), 这 样 的 数 据 量 就 比 较 可 以 接受 , 进 一 步 , 我 们 可 以 默 认 打 开 草 稿 状 态 的 部 分 。


第 十 节 使 用 参 数 化 查 询 语 句查 询 的 时 候 , 我 们 喜 欢 自 己 组 装 字 符 串 , 但 是 如 果 用 户 输 入 单 引 号 , 就 可 能打 断 我 们 的 sql 语 句 , 从 而 导 致 报 错 误 , 我 们 尽 量 采 用 参 数 语 句 , 对 于 zeosdbo组 件 来 说 , 参 数 就 是 用 冒 号 : 开 始 的 。 然 后 用Zquery1.parambyname('datap').asstring := 'adads';这 样 的 形 式 。实 际 上 对 于 数 据 库 系 统 来 说 , 参 数 化 查 询 相 当 于 一 个 临 时 的 存 储 过 程 , 动 态参 数 就 是 存 储 过 程 的 参 数 。


第 十 一 节 大 数 据 测 试估 算 数 据 规 模 , 做 模 拟 数 据 生 成 , 然 后 测 试 程 序 反 应 , 主 要 针 对 数 据 库 操 作需 要 优 化 的 地 方 进 行 查 询 优 化 , 创 建 索 引 等 。 可 以 自 己 写 特 定 的 数 据 产 生 器 。


第 十 二 节如 何 设 计 主 键主 键 设 计 不 外 乎 这 几 种 模 式 :1. 设 计 成 用 户 可 编 辑 的 整 数 或 英 文 , 中 文 ;2. 设 计 成 自 增 长 类 型 整 数 ;3. 设 计 成 整 数 , 用 select max(myid) 获 取 , 并 加 1;4. 设 计 成 字 符 串 类 型 , 用 select max(myid) , 并 加 1;5. 设 计 成 字 符 串 类 型 , 用 自 定 义 函 数 生 成 随 机 id;6. 设 计 成 字 符 串 类 型 ,CLSID;7. 设 计 成 字 符 串 , 部 分 自 动 增 长 模 式8. 设 计 成 硬 件 相 关 , 加 随 机 数 字下 面 我 们 就Select MAX(ID) 这 是 一 个 普 遍 的 错 误 , 当 两 个 用 户 在 同 一 时 间 插 入 数 据 时 ,这 会 导 致 错 误 。 你 可 以 使 用 SCOPE_IDENTITY,IDENT_CURRENT 和 IDENTITY


第 十 三 节避 免 null 字 段数 字 字 段 可 以 默 认 为 0日 期 字 段 可 以 默 认 为 now文 本 字 段 可 以 默 认 为 '' 注 意 '' 和 null 是 两 个 概 念 , 尽 管 我 们 在 代 码 里 用asstring 会 将 null 自 动 转 换 成 '', 但 是 还 是 可 以 考 虑 设 置 一 个 默 认 值 。


第 十 四 节尽 量 不 用 text 类 型Text 类 型 字 段 比 较 影 响 数 据 库 存 取 , 因 为 数 据 库 存 储 这 类 字 段 的 时 候 , 是 根据 页 的 大 小 设 置 此 字 段 按 一 定 大 小 , 分 成 多 个 小 块 存 储 的 。 一 般 来 说 此 类 数 据 不太 重 要 , 我 们 可 以 将 其 用 文 件 保 存 到 磁 盘 上 , 但 是 存 取 可 能 需 要 一 个 通 道 , 比 如服 务 端 写 一 个 tcp 的 服 务 程 序 , 或 者 用 http,ftp 上 传 , 下 载 , 用 MongoDB 来 辅 助存 储 这 类 数 据 , 也 是 不 错 的 。


第 十 五 节适 当 使 用 触 发 器一 般 来 说 , 触 发 器 要 尽 量 少 用 , 不 适 当 的 使 用 触 发 器 , 可 能 导 致 触 发 器 的 循环 触 发 , 导 致 数 据 库 死 掉 。


第 十 六 节适 当 使 用 存 储 过 程存 储 过 程 的 过 多 使 用 , 可 能 导 致 代 码 可 读 性 比 较 低 , 可 能 导 致 代 码 扩 展 比 较困 难 , 因 为 存 储 过 程 基 本 上 是 全 局 的 , 比 如 多 人 合 作 的 时 候 , 如 果 存 储 过 程 一 旦确 定 使 用 , 并 且 发 布 给 客 户 了 , 后 期 最 好 不 要 改 动 , 特 别 是 接 口 方 面 , 这 就 相 当于 其 他 语 言 的 接 口 , 一 旦 接 口 有 变 动 , 就 必 须 发 布 新 的 版 本 , 保 留 旧 的 版 本 。


第 九 十 三 章 冒 泡 排 序 算 法 等1. 冒 泡 排 序 算 法 是 算 法 中 的 算 法 , 是 最 基 础 的 , 我 们 就 来 讨 论 一 下 。题 目 :有 如 下 10 个 数 字 , 请 将 他 按 大 到 小 输 出 :12,33,92,22,44,464,-32,323,22,878排 序 前排 序 后冒 泡 排 序 算 法 是 排 序 的 最 简 单 实 现 , 如 图 上 所 示 , 冒 泡 的 原 理 来 自 鱼 儿 吐 泡 ,最 大 的 泡 会 排 在 最 上 面 。 我 们 来 看 算 法 的 图 示 。头 个 数 字后 面 数 字比 较 第 一 个 数 字 和 后 面 的数 字 , 如 果 后 面 任 何 一 个 比第 一 个 大 , 就 和 第 一 个 交换 , 那 么 就 是 说 , 最 大 的 这个 泡 泡 , 浮 到 最 上 面 了 。然 后 我 们 取 出 第 2 个 数字 , 也 只 和 后 面 的 比 较 。直 到 头 个 数 字 为 倒 数 第 2个 , 后 面 数 字 为 最 后 一 个 。一 步


算 法 代 码 如 下 :program sort;// 程 序 名 称 声 明{$mode objfpc}{$H+}// 定 义 object fpc 模 式uses{$IFDEF UNIX}{$IFDEF UseCThreads} //unix 系 统 线 程 模 式 单 元 引 用cthreads,{$ENDIF}{$ENDIF}Classes{ you can add units after this };var a:array [0..9] of integer;// 定 义 一 个 数 组 , 每 个 元 素 是 integer 类 型i,j:integer;t:integer;// 定 义 两 个 下 标 ( 或 者 叫 做 数 字 型 的 指 针 ) 指 向 头 个 数 , 和 后 面 数// 用 来 保 存 临 时 数 据 , 以 实 现 交 换Begin// 下 面 给 数 组 初 始 值 , 没 有 排 序a[0] := 12;a[1] := 33;a[2] := 92;a[3] := 22;a[4] := 44;a[5] := 464;a[6] := -32;a[7] := 323;a[8] := 22;a[9] := 878;for i:=0 to 8 do // 指 向 第 1-9 个 数for j:= I+1 to 9 do // 指 向 第 头 个 数 后 面 的 和 后 面 的beginif a[i] < a[j] then // 找 出 大 泡 泡begin


t := a[i]; //3 句 实 现 交 互a[i] := a[j];a[j] := t;end;end;for I:=0 to 9 do // 输 出 排 序 后 数 据writeln(a[i]);readln;end.


第 九 十 四 章 MongoDB, 再 遇 MongoNOSQL, 是 Not Only SQL, 随 着 互 联 网 应 用 的 大 量 涌 现 , 传 统 基 于 关 系 数 据库 的 软 件 编 程 , 已 经 越 来 越 不 能 承 载 此 类 应 用 的 需 求 。 虽 然 可 以 通 过 memorycached , 读 写 分 离 , 分 布 式 负 载 均 衡 等 多 种 技 术 实 现 , 但 是 都 各 家 有 各 家 的 优 缺点 。 有 没 有 一 种 编 程 简 单 , 部 署 简 单 , 而 又 能 够 承 载 此 类 需 求 的 数 据 存 储 解 决 方案 呢 ?有 , 就 是 NOSQL 运 动 。MongoDb 作 为 此 项 运 动 的 代 表 , 正 受 到 越 来 越 多的 关 注 , 下 面 我 们 就 其 在 lazarus 的 使 用 , 做 一 个 简 单 的 讲 解 :1. 安 装 mongodb2. 编 译 mongodb 的 c 语 言 驱 动3. 使 用 lazarus 编 译 测 试 demo4. 测 试 demo 的 详 细 讲 解5. 第 二 个 测 试 demo 的 注 意 事 项1. 安 装 mongodb首 先 我 们 从 网 络 上 下 载mongodb-win32-i386-2.0.6.zip( 这 个 版 本 是 支 持windowsxp 32 位 最 后 一 个 版 本 , 用 来 学 习 够 了 ) , 然 后 , 我 们 将 其 解 压 缩 到D:\mongodb , 然 后 我 们 进 入 cmd , 执 行Cd d:\mongodb\binD:Mkdir dataMkdir logsmongod --dbpath=D:\mongodb\data -logpath=D:\mongodb\logs\mongodb.log将 指 定 数 据 库 存 放 在 安 装 目 录 的 data 下 , 日 志 在 logs然 后 我 们 进 入 浏 览 器 , 浏 览 http://localhost:27017, 会 显 示 一 行 信 息 , 那 么 就对 了 。 成 功 开 启 了 mongodb 服 务 的 单 机 模 式 。2. 编 译 mongodb 的 c 语 言 驱 动


当 然 我 们 首 先 要 有 mongo-c-driver ,mongo-delphi-driver 两 个 从 git 可 以 获 取 。使 用 lazarus 连 接 mongodb 需 要 驱 动 程 序 , 有 3 个 :A. 官 方 驱 动 c 语 言 版 本 , 编 程 成 dll, 将 delphi 包 装 版 本 修 改 为 lazarus 版 本 ;B. 第 3 方 驱 动 , 无 dll, 但 功 能 相 对 不 完 整 ;C. 其 他 驱 动 ;C 语 言 驱 动 的 编 译 比 较 麻 烦 , 需 要 python 等 环 境 , 要 点 是 环 境 变 量 不 能 有中 文 , 否 则 scons 这 个 脚 本 不 能 解 码 。笔 者 在 vs2008,python,scons 这 样 的 环 境 进 行 了 正 确 的 编 译 。


3. 使 用 lazarus 编 译 测 试 demo使 用 lazarus 打 开 官 方 驱 动 附 带 的 测 试 程 序 , 由 于 官 方 驱 动 基 于 0.7 版 本 , 而我 们 的 驱 动 基 于 0.71, 并 且 官 方 是 基 于 delphi 新 版 本 , 所 以 代 码 我 们 必 须 修 改 一下 , 主 要 有 几 个 方 面 :A. 测 试 样 例 里 面 有 gfs.storeFile('..\..\mongo.pas','mongo.pas'); 实 际 上 这 个 文 件找 不 到 , 会 报 告 错 误 ,B. 我 们 的 驱 动 是 新 的 版 本 , 执 行 到mongo.indexCreate(ns, 'name', indexDropDups)会 在 控 制 台 输 出 No Connection, Err = 2 , 那 么 说 明 后 端 数 据 库 没 有 正 确 启动 .C. 在 原 始 代 码 里 面 有b2 := BSON(['test', 'testing', 'age', 32,'subobj', '{','single', sing,'}','int64', Int64(1234567890123),'double', 98.7, 'null', Null, 'logical', False, 'now', now ]);b2.display();输 出 为 ---------------------test (2) : testingage (16) : 32subobj (3) :single (1) : 3.1415901184082int64 (16) : 1912276171double (1) : 98.7null (10) : NULLlogical (8) : Falsenow (2) : 2013-02-28---------------------------


注 意 红 色 部 分 ,int64 丢 失 了 数 据 , 需 要 修 改 为 我 们 自 己 的 补 丁 。代 码 修 改 为 :b2 := BSON(['test', 'testing', 'age', 32,'subobj', '{','single', sing,'}','int64', Int64ToOleVar(1234567890123),'double', 98.7, 'null', Null, 'logical', False, 'now', now ]);b2.display();-------- 新 的 输 出 为test (2) : testingage (16) : 32subobj (3) :single (1) : 3.1415901184082int64 (18) : 1234567890123double (1) : 98.7null (10) : NULLlogical (8) : Falsenow (2) : 2013-02-28


4. 测 试 demo 的 详 细 讲 解{Copyright 2009-2011 10gen Inc.Licensed under the Apache License, Version 2.0 (the "License");you may not use this file except in compliance with the License.You may obtain a copy of the License athttp://www.apache.org/licenses/LICENSE-2.0Unless required by applicable law or agreed to in writing,softwaredistributed under the License is distributed on an "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express orimplied.See the License for the specific language governing permissionsandlimitations under the License.}program Test;{$IFDEF FPC}{$MODE Delphi}{$ENDIF}{$APPTYPE CONSOLE}{$R *.res}usesSysUtils,Variants,uint64olevariant,MongoBson, MongoDB, GridFS; //3 个 支 持 单 元 , 分 别 是 bson(json 变 种 ),mongodb 连 接 ,gridfs 文 件 分 布 式 存 储var


: TBsonBuffer;cws : TBsonCodeWScope;b, b2, x, y, z, criteria, query, cmd : TBson;i : TBsonIterator;oid : TBsonOID;ts : TBsonTimestamp;bin : TBsonBinary;sing : Single;mongo : TMongo;j : Integer;cursor : TMongoCursor;databases : TStringArray;gfs : TGridFS;gfw : TGridfileWriter;gf : TGridfile;buf : array[0..100] of AnsiChar;ia1 : array[0..4] of Integer;ia2 : TIntegerArray;count:integer;const// 定 义 要 用 的 库 和 集 合db = 'test';ns = db + '.people';// 显 示 库 里 有 什 么 数 据 集procedure displayCollections(db : string);varcollections : TStringArray;j : Integer;begincollections := mongo.getDatabaseCollections(db);


for j := 0 to Length(collections)-1 doWriteln(collections[j]);end;// 下 载 文 件 , 参 数 1= 支 持 对 象 , 参 数 2 服 务 端 名 , 参 数 3 本 地 文 件 名// 如 果 本 地 文 件 名 缺 省 , 自 动 以 服 务 器 文 件 名 保 存procedure ExtractFile(gfs : TGridFS; gfsname : string; filename :string = '');var chunk : Integer;gf : TGridfile;f : File;b : TBson;bin : TBsonBinary;beginif filename = '' then filename := gfsname;gf := gfs.find(gfsname);Assign(f, filename);Rewrite(f, 1);for chunk := 0 to gf.getChunkCount - 1 dobeginb := gf.getChunk(chunk);bin := b.find('data').getBinary;BlockWrite(f, bin.data^, bin.len);end;Close(f);end;begintrybb := TBsonBuffer.Create(); //bb 是 bson buffer 对 象 , 用 来 处 理 json数 据 ( 二 进 制 格 式 )


ia1[0] := 5;// 整 数 数 组ia1[1] := 7;ia1[2] := 9;ia1[3] := 11;ia1[4] := 13;bb.appendArray('ia', ia1); // 添 加 整 数 数 组 到 bb缓 冲 期b := bb.finish;//b 为 bson 对 象 ,finish 后 bb 对 象 会 自 动 重 置 指 向dll 的 内 存 的 指 针 , 从 而 确 保 是 新 的 缓 冲 区i := b.iterator;//i 为 迭 代 子ia2 := i.getIntegerArray(); // 从 迭 代 子 读 到 数 组for j := 0 to Length(ia2) - 1do // 数 组 输 出WriteLn(ia2[j]);bb := TBsonBuffer.Create(); // 重 新 建 立 一 个 bufferbb.append('test', 'testing'); // 添 加 一 个 键 为 test, 值 为 testing 的 数据cws := TBsonCodeWScope.Create('Code for scope',bb.finish());//tbsoncodewscope 对 象 保 存 一 个 javascript 对 象bb := TBsonBuffer.Create(); // 建 立 一 个 新 的 bufferbb.append('name', 'Gerald');// 添 加 一 写 新 的 值bb.append('age', 35);bb.append('long', Int64(89));bb.append('bool', True);bb.append('date', StrToDatetime('1970-3-1'));//bug4bb.startObject('object');// 开 始 一 个 对 象bb.append('sub1', 'sub1' );bb.append('sub2', False);bb.finishObject();// 告 知 生 成 的 是 一 个 bson 对 象//------------------oid := TBsonOID.Create(); //Tbsonoid 是 一 个 ID 生 成 器 不 给 参 数 ,


自 动 产 生 idwriteln(oid.AsString());bb.append('oid1', oid);bb.append('oid2', TBsonOID.Create('4eb6a93dad14000000000099'));bb.appendCode('code', '{ this = is + code; }');// 添 加 javascriptbb.appendSymbol('symbol', 'symbol'); // 添 加 符 号bb.append('cws', cws);bb.append('regex', TBsonRegex.Create('pattern', 'options'));// 正规 表 达 式 建 立ts := TBsonTimestamp.Create(now, 21);// 用 当 前 时 间 和 随 机 数 种 子 作 为一 个 时 间 戳 ( 和 mssql 的 不 同 , 那 个 是 个 数 字 )bb.append('timestamp', ts);bb.appendBinary('binary', 0, @ts, sizeof(ts)); // 存 储 格 式 还 是 象mssql timestampb := bb.finish;Writeln(b.size());b.display(); // 递 归 的 显 示 此 bson 内 部 结 构 , 使 用 内 部 函 数 _displayWriteln(b.value('long')); // 按 key=long 显 示 为 89, 可 见 新 建 buffer并 不 和 tbson 对 象 冲 突 , 一 个 是 buffer, 一 个 是 保 存 多 个 buffer 值 的 对 象i := b.find('oid1');WriteLn(i.getOID().AsString());i := b.find('binary');bin := i.getBinary(); // 将 前 面 时 间 戳 的 bin 格 式 放 bin 变 量WriteLn(bin.len);sing := 3.14159;// 用 BSON 辅 助 函 数 来 自 动 生 成 一 个 bson 对 象b2 := BSON(['test', 'testing', 'age', 32,'subobj', '{','single', sing,


'}','int64', Int64ToOleVar(1234567890123),'double', 98.7, 'null', Null, 'logical', False, 'now', now ]);b2.display();// 不 给 参 数 将 自 动 连 接 到 127.0.0.1 27017 这 个 mongodbmongo := TMongo.Create();if mongo.isConnected() then begin // 有 没 有 连 接 上mongo.setTimeout(0); // 超 时 设 置WriteLn('Timeout = ', mongo.getTimeout());// 得 到 本 连 接 是 否 超 时设 置WriteLn('Primary = ', mongo.getPrimary());// 主 服 务 的 urlWriteLn('IsMaster = ', mongo.isMaster()); // 是 否 主 服 务WriteLn('Socket = ', mongo.getSocket());// 客 户 端 用 的 哪 个 端 口WriteLn('Check = ', mongo.checkConnection());// 检 测 连 接 是 否 断开 ,true-- 在 线WriteLn('disconnect');mongo.disconnect();// 断 开WriteLn(' Check = ', mongo.checkConnection());WriteLn('reconnect');mongo.reconnect();// 重 连WriteLn(' Check = ', mongo.checkConnection());// 获 取 数 据 库 名 字 列 表databases := mongo.getDatabases();for j := 0 to Length(databases)-1 doWriteln(databases[j]);// 显 示 库 中 所 有 文 档 集 合displayCollections(db);// 改 文 档 集 合 的 名 字mongo.rename(ns, 'test.renamed');


再 显 示displayCollections(db);// 改 回 去mongo.rename('test.renamed', ns);displayCollections(db);// 删 除 集 合WriteLn('Drop = ', mongo.drop(ns));{* display hosts for a TMongoReplset *}//Count := mongo.getHostCount();// WriteLn('Replset Host Count = ', Count);//for j := 0 to count - 1 do// WriteLn('Host = ', mongo.getHost(j));{**}(* insert the collage document *)// 将 文 档 插 入 集 合mongo.insert(ns, b);(* Insert a couple more people *)bb := TBsonBuffer.Create(); // 添 加 一 个 人 ( 文 档 ) 到 集 合bb.append('name', 'Abe');bb.append('age', 32);bb.append('city', 'Washington');x := bb.finish;x.display();// 控 制 台 显 示Writeln(mongo.insert(ns, x)); // 显 示 插 入 结 果bb := TBsonBuffer.Create();bb.append('name', 'Joe');bb.append('age', 35);bb.append('city', 'Natick');x := bb.finish;


x.display();Writeln(mongo.insert(ns, x));// 再 插(* Batch insert 3 people *) // 一 批 查 3 个bb := TBsonBuffer.Create();bb.append('name', 'Jeff');bb.append('age', 19);bb.append('city', 'Florence');x := bb.finish;x.display();bb := TBsonBuffer.Create();bb.append('name', 'Harry');bb.append('age', 36);bb.append('city', 'Fort Aspenwood');y := bb.finish;y.display();bb := TBsonBuffer.Create();bb.append('name', 'John');bb.append('age', 21);bb.append('city', 'Cincinnati');z := bb.finish;z.display();Writeln(mongo.insert(ns, [x, y, z])); // 插 入 进 去// 建 立 一 个 索 引 ,bug 修 正 了mongo.indexCreate(ns,'name',indexDropDups,'name');//indexUnique); //BUG1(* update Joe's document with a new one *) // 更 新 一 个 人 员bb := TBsonBuffer.Create();bb.append('name', 'Joe');bb.append('age', 36);


.append('city', 'Austin');x := bb.finish;criteria := BSON(['name', 'Joe']);x.display();Writeln(mongo.update(ns, criteria, x));// 注 意 更 新 指 令(* do an upsert *)bb := TBsonBuffer.Create();bb.append('name', 'Paul');bb.append('age', 53);bb.append('city', 'Seattle');x := bb.finish;criteria := BSON(['name', 'Paul']);criteria.display();x.display();Writeln(mongo.update(ns, criteria, x, updateUpsert));// 没 有 这 个 人就 插 入 , 否 则 更 新(* Remove a record *)WriteLn(mongo.remove(ns, BSON(['name', 'John'])));// 删 除 一 个 文档 , 也 就 是 一 个 记 录(* successful findOne *)x := mongo.findOne(ns, criteria); // 查 找1 个x.display();(* unsuccessful findOne *)x := mongo.findOne(ns, BSON(['name', 'unknown']));// 再 找 , 返 回 找不 到x.display();(* display all people *)cursor := TMongoCursor.Create();// 有 cursor 游 标 显 示 所 有 人if mongo.find(ns, cursor) then


while cursor.next() docursor.value.display();(* display all people age 36 *) // 查 找 年 龄 为 36 的 人query := BSON(['age', 36]);cursor := TMongoCursor.Create(query); // 也 就 是 默 认 为 = 查 找if mongo.find(ns, cursor) thenwhile cursor.next() docursor.value.display();//3 种 计 数WriteLn(mongo.count(ns));cmd := BSON(['count', 'people']);b := mongo.command(db, cmd);// 计 算 人 数 量 , 实 际 为 文 档 数 量 (/ 或 叫记 录 数 量 )WriteLn(b.value('n'));b := mongo.command(db, 'count', 'people');// 和 上 面 一 样 ,WriteLn(b.value('n'));WriteLn(int(mongo.count(ns, query)));// 方 法 3(* get distinct names *)x := mongo.distinct(ns, 'name'); // 相 当 于select distinct name***i := x.find('values').subiterator;while i.next dowriteln(i.value);(* add a user to database 'admin' *)mongo.addUser('Gerald', 'P97gwep16'); // 添 加 用 户(* authenticate with correct credentials *)WriteLn(mongo.authenticate('Gerald', 'P97gwep16')); // 认 证 用 户(* try authenicate with bad password *)WriteLn(mongo.authenticate('Gerald', 'BadPass21')); // 故 意 错 误 密


码(* try authenticate with bad user *)WriteLn(mongo.authenticate('Unsub', 'BadUser67')); // 故 意 错 误 人 员// 错 误 处 理 方 面b := BSON(['name', 'dupkey']);mongo.insert(ns, b);mongo.insert(ns, b);b := mongo.getLastErr(db); // 总 是 用 getLastErr 方 法b.display();b := BSON(['name', '{', '$badop', true, '}' ]);b2 := mongo.findOne(ns, b);b2.display(); // 故 意 用 错 误 的 操 作b := mongo.getLastErr(db);b.display();// 故 意 用 错 误 的 操 作b := mongo.getPrevErr(db); // 获 取 之 前 的 错 误b.display();WriteLn(mongo.getServerErr());WriteLn(mongo.getServerErrString());mongo.resetErr(db); // 恢 复 会 话 的 错 误 为 无 错b := mongo.getLastErr(db); // 获 取 错 误b.display(); // 显 示 错 误 信 息// 文 件 上 传 方 面 grid 是 一 个 数 据 库gfs := TGridFS.Create(mongo, 'grid');WriteLn('Store test.exe = ', gfs.storeFile('test.exe')); // 存 文件 , 就 是 这 个 执 行 程 序WriteLn('Store bin = ', gfs.store(bin.data, bin.len, 'bin'));gfs.removeFile('bin');gfw := gfs.writerCreate('writer');gfw.write(bin.data, bin.len);


gfw.write(bin.data, bin.len);gfw.finish();gf := gfs.find('writer');WriteLn('name = ', gf.getFilename());WriteLn('length = ', gf.getLength());WriteLn('chunkSize = ', gf.getChunkSize());WriteLn('chunkCount = ', gf.getChunkCount());WriteLn('contentType = ', gf.getContentType());WriteLN('uploadDate = ', DateTimeToStr(gf.getUploadDate()));WriteLN('md5 = ', gf.getMD5());b := gf.getDescriptor();b.display();gf.read(@j, sizeof(j));WriteLn(j);gf := gfs.find('test.exe');cursor := gf.getChunks(1, 5);while cursor.next() doWriteln(cursor.value.size());WriteLn(gf.seek(100000));//BUG ../../ 没 有 这 个 文 件gfs.storeFile('MongoDB.pas', 'MongoDB.pas');gf := gfs.find('MongoDB.pas'); //BUG2gf.seek(100);gf.read(@buf, 20);buf[20] := Chr(0);WriteLn(buf);ExtractFile(gfs, 'MongoDB.pas');//BUG3WriteLn('Done');ReadLn;


endelseWriteLn('No Connection, Err = ', mongo.getErr());excepton E: Exception doWriteln(E.ClassName, ': ', E.Message);end;end.


5. 第 二 个 测 试 demo 的 注 意 事 项第 二 个 是 基 于 GUI 的 地 址 簿 程 序 , 对 于 中 文 , 需 要 注 意 将 显 示 数 据 到 界 面的 地 方 用 utfencode 进 行 编 码 。当 然 也 可 以 通 过 修 改 底 层 驱 动 程 序 , 实 现 。


第 九 十 五 章 数 据 类 型 的 长 度代 码 如 下procedure TMyApplication.DoRun;varErrorMsg: String;a:byte;b:shortint;c:smallint;d:integer;e:longint;f:word;g:qword;h:cardinal;i:int64;string1:string;ansi1:ansistring;wide1:widestring;uni1:unicodestring;begin// quick check parametersErrorMsg:=CheckOptions('h','help');if ErrorMsg'' then beginShowException(Exception.Create(ErrorMsg));Terminate;Exit;end;// parse parameters


if HasOption('h','help') then beginWriteHelp;Terminate;Exit;end;{ add your program here }writeln(inttostr(sizeof( a))+': byte');;writeln(inttostr(sizeof(writeln(inttostr(sizeof(writeln(inttostr(sizeof(writeln(inttostr(sizeof(writeln(inttostr(sizeof(b))+':shortint');;c))+':smallint');;d))+':integer');;e))+':longint');;f))+':word');;writeln(inttostr(sizeof( g))+':qword');writeln(inttostr(sizeof(writeln(inttostr(sizeof(h))+':cardinal');i))+':int64');string1 := ' 汉 字 ';writeln(inttostr(sizeof(string1)),'sizeof string');writeln(inttostr(length(string1)),'length of string');writeln;ansi1 := string1;writeln(inttostr(sizeof(ansi1)),'sizeof ansistring');writeln(inttostr(length(ansi1)),'length of ansistring');writeln;wide1 := string1;writeln(inttostr(sizeof(wide1)),'sizeof widestring');writeln(inttostr(length(wide1)),'length of widestring');writeln;uni1 := string1;writeln(inttostr(sizeof(uni1)),'size of unistring');writeln(inttostr(length(uni1)),'length of unistring');


eadln;// stop program loopTerminate;end;输 出 如 下 ====================1: byte1:shortint2:smallint4:integer4:longint2:word8:qword4:cardinal8:int644sizeof string6length of string4sizeof ansistring6length of ansistring4sizeof widestring3length of widestring4size of unistring3length of unistring我 们 可 以 看 到 汉 字 , 每 个 占 用 了 3 个 字 节 , 而 widestring ,unistring 都 是 字符 数 量 ( 实 际 字 节 数 要 乘 以 2), 那 么 明 明 只 有 2 个 字 , 为 什 么 占 用 3 个 长 度 ?原 来 是 我 们 先 赋 值 给 string 的 是 utf8 格 式 ( 在 IDE 输 入 的 汉 字 ), 所 以unicodestring 和 widestring 都 存 放 的 是 utf8 字 符 的 wide 或 unicode 编 码 。我 们 用 新 的 代 码 测 试 :string1 := utf8decode(' 汉 字 '); // 这 里 进 行 解 码 到 本 地 代 码 页writeln(inttostr(sizeof(string1)),'sizeof string');writeln(inttostr(length(string1)),'length of string');


writeln;ansi1 := string1;writeln(inttostr(sizeof(ansi1)),'sizeof ansistring');writeln(inttostr(length(ansi1)),'length of ansistring');结 果 是 :1: byte1:shortint2:smallint4:integer4:longint2:word8:qword4:cardinal8:int644sizeof string4length of string4sizeof ansistring4length of ansistring4sizeof widestring2length of widestring4size of unistring2length of unistringLength 测 量 ansistring,string 长 度 为 4 字 节 , 而 unicode,wide 都 保 存 的 是 2个 字 符 。


第 九 十 六 章 重 载 的 研 究我 们 知 道 , 面 向 对 象 编 程 , 比 如 涉 及 到 重 载 , 而 重 载 的 条 件 是 函 数 名 相 同 ,而 参 数 个 数 , 或 参 数 类 型 不 同 。 我 们 来 看 一 段 代 码 :unit Unit1;{$mode objfpc}{$H+}interfaceusesClasses, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs;type{ TForm1 }TForm1 = class(TForm)private{ private declarations }publicprocedure foo(param:TDatetime);override;procedure foo(param:double);override;{ public declarations }end;varForm1: TForm1;implementation{$R *.lfm}{ TForm1 }procedure TForm1.foo(param: TDatetime);beginend;procedure TForm1.foo(param: double);begin


end;end.上 面 代 码 没 有 任 何 意 义 , 我 们 查 找 Tdatetime 是 在 systemh.inc 文 件 定 义 为double, 相 似 的 代 码 在 delphi 里 面 也 可 以 , 既 然 tdatetime 和 double 是 一 样 的 , 为什 么 重 载 还 能 够 继 续 呢 ? 这 就 是 pascal 语 言 的 强 类 型 检 查 在 帮 助 我 们 实 现 , 虽 然底 层 数 据 类 型 一 样 , 而 高 层 数 据 类 型 不 一 样 , 也 可 以 实 现 重 载 的 功 能 。


第 九 十 七 章RxDBGrid 的 使 用准 备 :1. 首 先 我 们 需 要 安 装 有 <strong>Lazarus</strong> 1.x( 废 话 );2. 然 后 我 们 需 要 ZeosDBO 7.0 ( 还 是 废 话 );3. 建 一 个 数 据 库 addressbook.fdb , 里 面 有 一 个 表 addressbook, 字 段 有id integer,fullname varchar(20),telphone varchar(20),mobilevarchar(20);并 且 在 firebird 的 alias.conf 设 置 数 据 库 别 名 addressbook;4. 然 后 我 们 还 需 要 安 装 rxNew 这 个 组 件 , 是 从 RxLib 移 植 过 来 的 。先 感 谢 一 下 移 植 的 作 者 :AO ROSNO,Master-Bank 这 两 位 大 大 , 给 了 我们 这 么 优 秀 的 免 费 组 件 , 祝 他 们 身 体 健 康 ( 快 入 正 题 吧 ~~~)。好 了 , 现 在 我 们 开 始 :步 骤 :1. 首 先 我 们 需 要 创 建 一 个 application, 经 典 的 Project 菜 单 ->New->Application->OK;2.Form1 改 名 frmAddressBook (frm 作 为 一 个 Form 类 的 前 缀 , 这 点 和其 他 许 多 资 料 推 荐 的 AdressBookForm 风 格 不 一 样 );3. 我 们 从 Zeos Acess 面 板 拖 一 个 Zconnection 到 刚 才 新 建 的Application 的 Form 上 , 名 字 conAddressBook, 分 别 设 置user=sysdba,password=masterkey,transactionIsolationLevel=tiReadCommitted,protocol=firebird-2.1,port=3050,hostname=localhost,database=addressbook;4. 继 续 添 加 ZQuery 2 个 , 分 别 名 字 是 qryAddressBook,qryTemp, 都设 置 connection 为 conAddressBook;5. 继 续 添 加 5 个 按 钮 , 分 别 是btnAdd,btnModify,btnDelete,btnSave,btnFind;6. 继 续 添 加 4 个 label, 分 别 修 改 caption 为


ID姓 名电 话手 机7. 继 续 添 加 4 个 TEdit, 设 置 text 属 性 为 空 , 分 别 命 名 为edtID,edtFullName,edtTelphone,edtMobile;8. 再 添 加 一 个 datasource 组 件 到 form 上 , 名 字 是 dsAddressbook, 其dataset 属 性 设 置 为 qryAddressbook;9. 最 后 我 们 添 加 一 个 TRDBGrid, 名 字 是 grdAddressBook, 设 置 4 个 列 ,如 下 图 :首 先 选 中 组 件 , 然 后 点 击 左 边 属 性 面 板 中 Columns 的 后 面 的 ... 的 那 个 按 钮 ,弹 出 下 图 的Editing RxDBGrid1.Columns 对 话 框 , 里 面 点 击 Add 按 钮 添 加 4 个 列


然 后 我 们 将 整 个 项 目 保 存 为 addressbook, 而 这 个 主 窗 口 保 存 为uAaddressbook; 我 们 的 窗 口 设 计 效 果 , 就 象 这 样 :10. 然 后 我 们 来 写 一 个 代 码 , 双 击 form, 默 认 会 打 开 代 码 编 辑 器 , 并 且 自 动产 生 FORM 的 FormCreate 事 件 框 架 ; 在 里 面 添 加 代 码 , 如 下 :


11. 然 后 我 们 给 按 钮 也 写 上 代 码最 终 我 们 的 代 码 如 下 :unit uAddressbook;{$mode objfpc}{$H+}interfaceusesClasses, SysUtils, db, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,rxdbgrid, ZConnection, ZDataset,LCLType, DBGrids;type{ TfrmAddressBook }TfrmAddressBook = class(TForm)btnAdd: TButton;btnModify: TButton;btnSave: TButton;btnDelete: TButton;btnFind: TButton;dsAddressBook: TDatasource;edtFullName: TEdit;


edtMobile: TEdit;edtID: TEdit;edtTelephone: TEdit;Label1: TLabel;Label2: TLabel;Label3: TLabel;Label4: TLabel;qryTemp: TZQuery;RxDBGrid1: TRxDBGrid;conAddressBook: TZConnection;qryAddressBook: TZQuery;procedure btnAddClick(Sender: TObject);procedure btnDeleteClick(Sender: TObject);procedure btnFindClick(Sender: TObject);procedure btnModifyClick(Sender: TObject);procedure btnSaveClick(Sender: TObject);procedure FormCreate(Sender: TObject);procedure RxDBGrid1CellClick(Column: TColumn);private{ private declarations }public{ public declarations }end;varfrmAddressBook: TfrmAddressBook;implementation{$R *.lfm}{ TfrmAddressBook }procedure TfrmAddressBook.FormCreate(Sender: TObject);begin


qryAddressbook.close;qryAddressbook.sql.text := 'select * from addressbook';qryAddressbook.open;end;procedure TfrmAddressBook.RxDBGrid1CellClick(Column: TColumn);beginend;procedure TfrmAddressBook.btnAddClick(Sender: TObject);beginedtID.text := '';edtFullName.text :='';edtTelephone.text := '';edtMobile.text := '';edtID.enabled := false;end;procedure TfrmAddressBook.btnDeleteClick(Sender: TObject);beginif qryAddressbook.isempty then exit;if application.messagebox(' 是 否 删 除 ( 将 不 可 以 恢 复 )?',' 确 认',MB_YESNO)=IDNO then exit;qryAddressbook.delete;end;procedure TfrmAddressBook.btnFindClick(Sender: TObject);beginqryAddressBook.close;qryAddressBook.sql.text := 'select * from addressbook where 1=1';// 注 意 这 里1=1 只 是 为 了 后 期 组 合 字 符 串// 条 件 1if edtFullName.text '' thenqryAddressBook.sql.add(' and fullname like ''%' +edtFullName.text + '%''');


条 件 2if edtTelephone.text '' thenqryAddressbook.sql.add(' and telephone like ''%' + edtTelephone.text + '%''');// 条 件 组 合 完 毕 , 查 询qryAddressBook.open();// 用 函 数 风 格 也 可 以end;procedure TfrmAddressBook.btnModifyClick(Sender: TObject);beginif qryAddressbook.isempty then exit;edtID.text := qryAddressbook.fieldbyname('id').asstring;edtFullName.text :=qryAddressbook.fieldbyname('fullname').asstring;edtTelephone.text := qryAddressbook.fieldbyname('telephone').asstring;edtMobile.text := qryAddressbook.fieldbyname('mobile').asstring;edtID.Enabled:= false;end;procedure TfrmAddressBook.btnSaveClick(Sender: TObject);var vID,vFullName,vTelephone,vMobile:string;beginvIDvFullName:= edtID.text;:= edtFullName.text;vTelephone := edtTelephone.text;vMobile:= edtMobile.text;// 验 证 必 须 输 入 的 信 息if vFullName = '' thenbeginshowmessage(' 没 有 填 写 姓 名 怎 么 保 存 ?');exit;end;if vID = '' then // 自 动 认 为 是 新 建 的begin


假 设 为 单 机 版 本qrytemp.close;qrytemp.sql.text := 'select max(id) from addressbook';qrytemp.open;if qrytemp.fields[0].asstring='' thenvId := '0' // 注 意 这 里 不 能 有 ;elsevID := qrytemp.fields[0].asstring;vID :=inttostr( strtoint(vID) + 1 ); // 自 动 增 长 1qrytemp.close;qrytemp.sql.text := 'insert intoaddressbook(id,fullname,telephone,mobile)values(:id,:fullname,:telephone,:mobile)';endelsebeginqrytemp.close;qrytemp.sql.text := 'update addressbook setfullname=:fullname,telephone=:telephone,mobile=:mobile where id=:id';end;qrytemp.parambyname('id').asstring := vid;qrytemp.parambyname('fullname').asstring := vFullname;qrytemp.parambyname('telephone').asstring := vTelephone;qrytemp.parambyname('mobile').asstring := vMobile;tryqrytemp.ExecSQL;showmessage(' 保 存 成 功 !');exceptshowmessage(' 保 存 失 败 !');end;end;end.


然 后 我 们 F9, 看 我 们 的 作 品 吧 。执 行 效 果 图 :


第 九 十 八 章 代 码 比 较 工 具 windiff这 个 软 件 下 载 地 址 :http://www.grigsoft.com/download-windiff.htm作 者 是 :Grig Software有 源 码介 绍 这 个 软 件 , 是 因 为 软 件 开 发 离 不 开 代 码 修 改 , 而 不 同 的 版 本 之 间 比 较 是比 较 麻 烦 的 , 怎 么 知 道 修 改 了 哪 里 ? 修 改 的 地 方 是 否 导 致 问 题 ? 这 就 需 要 文 件 比较 工 具 , 这 个 工 具 能 以 图 形 化 方 式 显 示 修 改 的 地 方 , 用 鼠 标 就 能 够 很 好 定 位 修 改处 。红 色 显 示 为 你 比 较 的 时 候 输 入 的 第 一 个 参 数 。黄 色 显 示 的 为 你 选 择 的 输 入 第 二 个 参 数 。对 于 习 惯 用 字 符 模 式 进 行 比 较 的 用 户 , 他 每 行 修 改 处 以 指 出 第 2 参 数 指 定 的 文 件 修 改 处 。我 们 举 例 , 看 mongo lazarus 的 两 个 版 本 驱 动 有 什 么 区 别第 一 步 选 择 菜 单 file ->compare directories然 后 在 参 数 里 面 输 入 两 个 版 本 的 目 录然 后 点 击 ok 按 钮


第 二 步 查 看 文 件 是 否 相 同 的 列 表其 中 的 identical 表 示 完 全 相 同Only in 表 示 其 中 一 个 目 录 有 文 件 , 另 外 一 个 没 有Differcent 表 示 文 件 不 同 , 我 们 重 点 来 看 红 色 的 。双 击 , 第 7 行 。红 色 部 分 , 并 且 用 表 示 的 , 是 dir2 里 面 同 名 文 件 的 行 , 每 对 不 同 的 行 , 都 是 临 近进 行 比 较 的 。让 我 们 非 常 容 易 看 到 代 码 的 不 同 点 。


第 九 十 九 章 案 例 : 商 品 单 价 模 块 (price) 单机 版首 先 用 lazarus 新 建 一 个 项 目 Price1然 后 我 们 可 以 看 到 还 可 以 创 建 控 制 台 程 序 ,Apache 的 模 块 ,CGI 等 等 .


建 立 一 个 新 的 文 件 夹 来 保 存 我 们 的 项 目起 名 Price1.lpi, LPI 是 项 目 信 息 文 件同 时 也 将 unit1 保 存 。


属 性我 们 将 拖 放 2 个 控 件 , 一 个 zconnection, 一 个 zquery 到 form 上 , 分 别 设 置 其我 们 将 fbclient.dll 放 在 c:\windows\system32 下然 后 我 们 用 Ibexpert 建 立 一 个 数 据 库 ,price.fdb , 再 建 立 表 goods , 有字 段 GoodsIDInteger,GoodsName varchar(50),Price numeric(15,2)然 后 丢 一 个 datasource 到 form 上 , 设 置 其 dataset 为 zquery1


然 后 我 们 用 TDBgrid 来 显 示 。设 置 其 Datsource 为 datasource1在 添 加 一 个 TDbNavigator , 设 置 datasource 为 datasource1,然 后 设 置 zquery1. 的 sql 为select * from goods再 设 置 tdbgrid 3 个 字 段 , 分 别 为 goodsid,goodsname,price在 dbgrid1 上 点 击 右 键 , 在 弹 出 窗 口 上 设 置然 后 我 们 给 form 的 oncreate 设 置 事 件 代 码Zquery1.open; // 意 思 是 自 动 连 接 数 据 库 , 并 查 询 goods 表 , 显 示 到 dbgrid恭 喜 , 这 个 模 块 你 编 写 出 来 了 。F9 执 行 吧 。那 么 有 的 童 鞋 说 , 你 没 有 使 用 insert 指 令 , 也 没 有 用 update,delete , 只 用 了select , 数 据 又 是 怎 么 保 存 的 呢 ?这 就 是 zquery 组 件 在 起 作 用 。 他 自 己 生 成 insert,update,delete 指 令 , 那 么 他 生成 的 语 句 是 什 么 呢 ?-- 是 按 主 键 作 为 条 件 的 更 新 , 以 可 插 入 字 段 , 生 成 全 部 数 据


的 insert.所 以 这 样 写 出 来 模 块 , 只 能 满 足 一 般 应 用 , 因 为 他 是 最 小 条 件 限 制 的 .本 章 这 个 程 序 只 能 适 合 单 用 户 使 用 , 或 者 基 于 最 后 一 个 用 户 修 改 总 是 对 的 ,这 样 一 个 假 设 来 的 。如 果 , 最 后 一 个 用 户 并 不 一 定 是 正 确 的 , 比 如A,B 都 打 开 本 模 块 , 然 后 A 修 改 单 价 为 20, B 修 改 为 30, 可 是 真 正 正 确 的是 20. 可 是 用 户 却 没 有 得 到 告 知 。 这 就 是 并 发 问 题 的 丢 失 更 新 问 题 。 解 决 此 问 题有 两 个 方 案 :1. 真 实 数 据 保 护 字 段 ;2. 版 本 号 保 护 字 段 ;我 们 在 下 章 用 真 实 数 据 保 护 字 段 来 实 现 。 这 个 方 案 对 所 有 sql 数 据 库 , 无 论什 么 语 言 其 实 都 是 一 样 的 。


第 一 百 章 案 例 : 商 品 单 价 模 块 (price) 网 络 版我 们 将 上 一 章 的 例 子 程 序 复 制 一 份 , 到 price2 文 件 夹 。然 后 去 掉 Tnavigator然 后 添 加 这 些 四 个 edit ,3 个 button分 别 命 名 为edtGoodsidedtGoodsNameedtPriceedtOldPricebtnNewbtnEditbtnSave其 中 edtOldPrice 为 不 可 见 (visible := false)再 添 加 一 个 tzquery 组 件 名 字 zquery2然 后 给 他 们 3 个 按 钮 分 别 设 置 onclick 代 码procedure TForm1.btnEditClick(Sender: TObject);beginedtgoodsid.text := zquery1.fieldbyname('goodsid').asstring;edtGoodsname.text :=zquery1.fieldbyname('goodsname').asstring;edtprice.text := zquery1.fieldbyname('price').asstring;edtoldprice.text := zquery1.fieldbyname('price').asstring;end;procedure TForm1.btnNewClick(Sender: TObject);beginedtgoodsid.text := '';edtGoodsname.text := '';


edtprice.text := '0';edtoldprice.text := '0';end;procedure TForm1.btnSaveClick(Sender: TObject);beginif edtgoodsid.text = '' thenbeginZQuery2.close;ZQuery2.sql.text :='insert intogoods(goodsname,price)values(:goodsname,:price)';zquery2.parambyname('goodsname').asstring :=edtgoodsname.text;zquery2.parambyname('price').asstring := edtprice.text;endelsebeginzquery2.Close;zquery2.sql.text := 'update goods setgoodsname=:goodsname,price=:price where goodsid=:goodsid andprice=:oldprice';zquery2.parambyname('goodsname').asstring :=edtgoodsname.text;zquery2.parambyname('price').asstring := edtprice.text;zquery2.parambyname('goodsid').asstring := edtgoodsid.text;zquery2.parambyname('oldprice').asstring := edtoldprice.text;end;tryzquery2.ExecSQL;showmessage(' 保 存 成 功 !');except


showmessage(' 保 存 失 败 , 可 能 是 别 的 用 户 修 改 了 价 格 !');end;zquery1.refresh;end;这 是 设 计 器 界 面这 是 运 行 期


有 几 个 地 方 需 要 改 进 的 是界 面 设 计 排 列只 读 edtgoodsid数 字 用 专 门 输 入 控 件保 护 gridGrid 里 面 数 字 字 段 格 式命 名好 的 , 这 章 , 我 们 讲 解 了 多 用 户 并 发 情 况 下 的 设 计 问 题 , 但 是 这 个 例 子 , 我们 也 基 于 了 最 后 修 改 用 户 对 goodsname 的 修 改 总 是 正 确 的 , 这 样 一 种 假 设 。否 则 要 将 这 个 字 段 进 行 保 存 。并 发 问 题 中 丢 失 更 新 的 这 个 问 题 是 比 较 严 重 的 , 一 般 大 家 都 没 有 去 注 意 他 ,处 理 这 个 问 题 要 根 据 业 务 的 需 求 , 做 一 定 合 理 的 假 设 的 情 况 下 去 做 , 不 是 任 何 时候 都 需 要 做 , 否 则 系 统 会 很 慢 , 同 时 开 发 速 度 也 会 慢 起 来 。


第 一 百 零 一 章 游 戏 ,ClickMe通 过 这 个 程 序 , 我 们 可 以 学 习 到 :1.Form设 计 器 ;2. 对 象 属 性 面 板 ;3. 单 元 局 部 变 量 ;4. 字 符 串 数 组 ;5.Timer组 件 , 和 其 OnTimer 事 件 ;6.Mod操 作 符 ;7. 按 钮 的 onMouseEnter, OnMouseClick 事 件 ;8.IF语 句 ;9. 赋 值 语 句 ;10.Sender;11.As操 作 符 ;12.Form 的 OnFormCreate 事 件 ;首 先 我 们 打 开 <strong>Lazarus</strong>.然 后 我 们 点 击 Standard 面 板 上 的 Button 按 钮并 且 点 击 默 认 新 建 的 Form 上


然 后 再 放 一 个 Ttimer 组 件 到 form 上


然 后 选 中 button, 给 他 设 置 Caption 如 上 图之 后 我 们 设 置 一 个 单 元 变 量 ticker , 来 记 录 timer 计 数 的 秒 数VarForm1:Tform1 ;// 这 个 地 方 的 变 量 , 在 单 元 外 可 以 访 问 , 只 要 引 用 了 这 个 单 元, 相 当 于 c 语 言 Main 函 数 外 面 的 变 量Implementation // 实 现 节{$R *.lfm} // 高 数 编 译 器 这 个 类 的 属 性 静 态 设 置 文 件 是 和 本 单 元 名 字 相 同 ,后 缀 为 lfm 的 文 件 ,( 类 属 性 持 久 化 )


{ TForm1 } // 这 个 是 备 注 下 面 是 一 个 TForm1 类 的 实 现 , 派 生 于 Tformvar ticker:integer; // 这 个 是 声 明 一 个 单 元 内 变 量 ticker , 类 型 是 Integer ( 数 字 啦 )cap:array [0..4] of string; // 这 里 声 明 一 个 名 字 叫 做 cap 的 变 量 , 他 是 一 个 数 组 ,里 面 记 录 了 5 个 元 素 , 都 是 字 符 串然 后 我 们 给 Tform1 的 oncreate 设 置 代 码ticker :=0; // 给 ticker 变 量 初 始 值cap[0] := ' 你 点 不 到 我 的 *^_^*'; // 给 数 组 元 素 [0] 赋 值 , 下 面 赋 值 其 他 4 个cap[1] := ' 来 呀 , 点 我 呀 ';cap[2] := ' 我 闪 ';cap[3] := ' 我 再 闪 ';cap[4] := ' 一 闪 一 闪 , 亮 晶 晶 ';然 后 给 timer1 设 置 ontimer 事 件 的 代 码var s:string;// 这 个 地 方 声 明 一 个 变 量 ,pascal 语 法 比 较 严 谨 , 不 能 导 出 声 明变 量begininc(ticker); // 让 全 局 变 量 自 己 加 1, 相 当 于 c 语 言 的 ticker ++ , 数 据 库 的 自 加 1的 字 段 类 型 缩 写s := cap[ticker mod 5]; // 这 句 意 思 是 ticker 取 余 于 5 , 得 到 总 是 0..4 的 值 ,从 而 没 有 超 过// 数 组 cap 的 下 标 , 可 以 取 得 相 应 的 字 符 串 值button1.caption := s;// 然 后 我 们 将 得 到 的 值 给 button1 的 属 性 Caption, 属 性是 映 射 到 一 个 过 程 setCaption(s:string); 的 ( 由 编 译 器 处 理 , 我 们 不 管 ), 然 后 我 们 就看 到 button 的 文 字 绘 制 成 新 的 了 。最 后 , 也 是 这 个 游 戏 的 核 心 部 分 , 当 我 们 将 鼠 标 移 动 到 按 钮 里 面 的 时 候 , 我们 让 按 钮 跑 到 另 外 一 个 位 置 , 从 而 让 他 和 我 们 捉 迷 藏 . 给 按 钮 的 onMouseEnter


设 置 事 件 代 码 :(sender as tbutton).top := (sender as tbutton).top + 20; // 这 句 意 思 是 让 按 钮的 上 面 坐 标 自 增 20 个 点if (sender as tbutton).top > self.heightthen // 这 里 是 说 , 当 按 钮 移 动 到 超 过form 的 高 度//self 表 示 的 是 当 前 类 ,Tform1就 是 一 个 类(sender as tbutton).top := (sender as tbutton).top -40; // 那 么 就 让 他 反 着 跑当 然 有 漏 洞 , 是 为 了 玩 家 能 获 胜 。然 后 我 们 切 换 到 Events 面 板 , 双 击 设 置 按 钮 的 OnClick 事 件在 代 码 编 辑 器 里 面 输 入


第 1 行 表 示 停 止 timer, 游 戏 结 束 , 并 且 告 诉 游 戏 玩 家 。(sender as Tbutton) 表 示 消 息 发 送 者 是 Tbutton 类 型 的 , 并 设 置 其 caption 属性 , 这 个 属 性 会 被 编 译 器 翻 译 到 一 个 过 程 , 这 段 过 程 程 序 会 导 致 Button 文 字 的 重绘 。至 此 , 游 戏 开 发 完 毕 ,F9执 行 。 玩 一 下 吧 。


第 一 百 零 二 章 C 语 言 的 位 域我 们 知 道 c 语 言 支 持 struct 类 型 里 面 , 有 位 域 (bit fields ) 概 念 , 那 么 lazarus 是 否 支 持 呢 ?废 话 少 说 , 直 接 上 代 码 :program bitfields;{$BITPACKING+} // 开 启 位 域 支 持Type// 声 明 一 个 结 构 体 , 里 面 带 的 是 位 段TSomeBitLevelStructure = bitpacked recordOneBit: 0..1;TwoBits: 0..3;FourBits: 0..15;EightBits: 0..255end;var t:tsomebitlevelStructure;Begint.onebit := 2; // 这 个 超 过 了 1 位 溢 出 , 所 以 变 成 了 0WriteLn (utf8toansi(' 位 域 onebit 值 :') , t.onebit);writeln(utf8toansi(' 整 个 结 构 体 字 节 大 小 :'),sizeof(t)); //sizeof 得 到 结 构 体 大 小readln;End.输 出 是可 见 lazarus 是 支 持 位 域 的 。


附 录 A相 关 社 区<strong>Lazarus</strong>http://www.lazarus.freepascal.orghttp://www.fpccn.comDelphihttp://www.2ccc.comhttp://www.delphifans.comFirebirdhttp://www.firebirdsql.orghttp://www.firebird.net.cnZEOSDBO(zeoslib)http://www.zeoslib.sourceforge.nethttp://zeos.firmos.at


附 录 B:<strong>Lazarus</strong>是 否 做 好 编 写 商 业 软 件 的准 备 了 ?作 者 :Zeljan简 体 中 文 翻 译 :delphicn@163.com此 文 章 来 自 于 欧 洲 Pascal 杂 志 2010 年 9 月 刊 :http://www.blaisepascal.eu/由 于 本 人 水 平 有 限 , 翻 译 中 难 免 有 错 误 , 请 大 家 谅 解 。 欢 迎 批 评 指 正 。 希 望这 篇 文 章 可 以 增 加 大 家 使 用 <strong>Lazarus</strong> 的 信 心 。编 辑 备 注 :这 篇 文 章 举 例 说 明 了 因 为 内 核 开 发 组 专 注 的 工 作 而 使 得 <strong>Lazarus</strong> 取 得 了 巨 大的 进 步 :它 显 示 了 <strong>Lazarus</strong> 如 今 在 许 多 方 面 和 Delphi 同 样 优 秀 。 在 个 别 关 键 应 用 方 面<strong>Lazarus</strong> 已 经 远 远 超 过 了 Delphi(64 位 编 译 执 行 , 多 平 台 和 多 系 统 , 允 许 移 动 应 用和 嵌 入 式 系 统 的 开 发 )。当 然 它 也 并 非 与 Delphi 完 全 一 样 , 几 乎 非 常 便 宜 - 这 个 可 以 参 考 Lazarsu USB优 盘 的 价 格 。 所 以 任 何 人 都 买 得 起 并 且 你 可 以 立 即 开 始 开 发 而 不 需 要 安 装 要 求 。你 可 以 创 建 曾 经 想 要 的 任 何 应 用 软 件 和 很 多 能 够 使 用 的 控 件 。 所 以 这 个 答 案 是 :是 的 。 可 完 全 完 美 的 用 于 商 业 应 用 软 件 开 发 。以 下 部 分 为 作 者 自 述 :我 开 始 我 的 工 作 在 2001 年 , 在 一 家 克 罗 地 亚 名 叫 Holobit 的 公 司 。 在 那 时 候Holobit 是 一 家 拥 有 十 二 个 客 户 的 相 当 的 小 公 司 。我 主 要 的 任 务 是 进 行 当 时 公 司 C++ 应 用 软 件 的 转 换 开 发 , 使 其 运 行 于 Linux和 Windows, 使 用 的 是 Borland 公 司 的 Delphi 和 Kylix 的 CLX 技 术 来 开 发 的 。 在 发 展了 多 年 之 后 C/C++ 代 码 在 linux 中 面 向 对 象 看 上 去 非 常 简 单 和 很 有 组 织 。 在 工 作了 二 个 月 之 后 , 我 非 常 肯 定 Borland 拥 有 伟 大 的 产 品 , 写 代 码 的 时 间 比 用 VI 编 辑器 写 C/C++(gtk+,qt) 代 码 的 时 间 短 了 许 多 。 无 论 如 何 , 在 3 个 月 内 我 们 的 商 业 应用 软 件 转 换 到 了 CLX 并 且 公 司 开 始 销 售 用 于 Linux 和 Win32 平 台 。 所 有 的 开 发 是 使用 Kylix 2 和 Delphi 6 来 完 成 的 。( 后 来 升 级 为 K3 和 D7)。


创 建 Linux 本 地 应 用 是 非 常 好 的 决 定 , 所 以 客 户 数 量 开 始 迅 速 成 长 。我 们 的 客 户 非 常 高 兴 在 桌 面 PC 中 可 以 选 择 Linux 或 Windows 客 户 端 应 用 程 序 ,因 为 它 可 以 节 约 成 本 并 且 创 造 了 一 个 更 好 更 安 全 的 运 行 环 境 。第 二 步 的 转 换 问 题 看 上 去 更 加 复 杂 - 在 那 时 - 是 数 据 库 。 当 我 开 始 转 换 我们 的 应 用 软 件 时 , 它 们 都 使 用 的 是 Foxpro, 而 我 对 Foxpro 却 非 常 失 望 , 因 为 我 已经 在 Linux 上 使 用 PostgrSQL 了 。 那 么 你 可 以 猜 测 到 我 们 移 植 我 们 所 有 的 应 用 软 件到 PostgreSQL 是 非 常 正 确 的 。在 那 时 我 不 知 道 诸 如 Zeos 一 类 的 第 三 方 组 件 , 所 以 我 编 写 了 我 自 己 的PostgreSQL 驱 动 并 且 使 用 了 它 数 年 之 久 。后 来 我 发 现 了 Zeos - 好 得 让 人 惊 讶 - 我 立 即 开 始 使 用 它 。 这 样 到 了 2004年 , 传 言 说 Kylix 将 不 再 升 级 和 退 出 市 场 , 从 Borland 处 没 有 任 何 消 息 - 如 此 安静 .... 是 的 它 将 要 退 出 了 : 可 耻 的 Borland, 不 是 因 为 你 把 Kylix 扔 进 了 坟 墓 ,而 是 因 为 你 欺 骗 了 你 的 用 户 。多 年 以 来 , 我 们 和 Borland 产 品 一 起 战 斗 。( 同 时 ,Kylix 不 再 能 运 行 于 任 何的 Glibc 高 于 2.4.X 的 分 发 版 本 之 上 ) 如 此 , 直 到 我 看 见 有 人 已 经 开 始 Qt 界 面 构 件库 用 于 <strong>Lazarus</strong> 项 目 , 并 且 那 个 家 伙 是 Felipe, 非 常 感 谢 Den Jean 做 的 QT C 绑 定 ,因 为 没 有 C 绑 定 的 话 我 们 不 能 拥 有 内 置 于 <strong>Lazarus</strong> 的 QT 界 面 构 件 库 。在 这 之 前 我 观 察 过 <strong>Lazarus</strong> 好 几 次 , 但 是 在 以 前 它 对 我 没 有 吸 引 力 , 因 为 它只 支 持 Gtk1 界 面 构 件 库 , 并 且 它 看 上 去 比 使 用 QT2 的 Kylix 糟 糕 , 所 以 现 在 我 有 理由 的 下 载 <strong>Lazarus</strong> trunk 并 且 查 明 真 相 , 它 是 如 何 和 QT 一 起 工 作 。( 以 前 我 测 试 过Gtk)。很 好 , 就 像 前 面 说 的 一 样 , 在 QT 界 面 构 件 库 的 工 作 只 是 刚 刚 开 始 , 这 个 结 果是 需 要 很 多 改 进 , 所 以 它 不 能 工 作 。在 快 速 的 查 看 完 <strong>Lazarus</strong> 的 原 理 之 后 ,<strong>Lazarus</strong> 组 件 库 (LCL) 和 界 面 构 件 库 是相 连 接 到 LCL 的 , 我 开 始 贡 献 给 <strong>Lazarus</strong> 开 发 组 一 些 主 要 的 我 当 时 取 得 可 以 运 行 的QT 界 面 构 件 库 代 码 。我 的 第 一 个 补 丁 是 发 给 了 Felipe。 他 说 我 的 代 码 写 得 很 标 准 ( 嗨 , 嗨 ), 那是 因 为 我 修 复 并 且 更 改 我 的 代 码 标 准 为 <strong>Lazarus</strong> 的 标 准 。不 管 怎 样 , 一 年 后 QT 界 面 构 件 库 开 始 可 以 用 了 - 在 同 时 <strong>Lazarus</strong> 开 发 组 给 了


我 SVN 写 入 的 权 根 - 所 以 不 再 需 要 等 待 Felipe 和 其 它 人 帮 我 提 交 我 的 补 丁 了 。在 同 一 时 间 - 由 于 Kylix 和 Delphi 程 序 设 计 引 起 的 商 业 难 题 使 得 公 司 管 理层 考 虑 移 植 全 部 的 代 码 到 Java 或 者 .Net。 当 公 司 管 理 层 决 定 移 植 修 改 必 须 快 速完 成 时 我 表 示 反 对 。我 不 是 很 乐 意 这 样 做 。 不 是 因 为 这 个 应 用 软 件 的 原 因 , 是 因 为 在 我 们 的 应 用软 件 中 使 用 了 大 量 的 第 三 方 组 件 (ZeosLib,FastReports,TMS 表 格 ,VritualTress等 等 ) 。 我 说 我 们 没 有 必 要 花 费 很 长 的 时 间 和 资 源 去 移 植 我 们 的 代 码 到Java 或 .Net 并 且 这 样 做 的 结 果 不 一 定 是 可 靠 的 。 我 被 这 个 商 业 决 策 给 打 乱 了 ( 并且 已 经 准 备 更 换 工 作 了 ), 所 以 有 一 天 我 询 问 我 的 主 管 , 是 否 他 们 可 以 允 许 让 我花 费 一 些 时 间 用 <strong>Lazarus</strong> 来 开 发 代 码 , 并 且 承 诺 在 几 个 月 后 我 将 展 示 我 们 的 一 些应 用 可 以 在 QT4 上 运 行 。这 样 , 努 力 奋 斗 开 始 了 ...我 开 始 和 时 间 赛 跑 , 我 不 得 不 修 复 QT-LCL 并 且 转 换 一 个 我 们 公 司 的 应 用 软 件到 LCL( 只 是 一 小 部 分 )。 那 可 不 是 一 个 轻 松 的 任 务 , 因 为 Qt-lcl 仍 然 未 完 成 并 且许 多 事 情 还 没 有 处 理 。用 于 <strong>Lazarus</strong> 的 Zeos 已 经 有 了 , 但 是 对 于 一 个 简 单 的 应 用 程 序 我 还 得 拥 有FastReports 和 TMS 表 格 。 这 样 , 我 使 用 了 三 个 月 的 时 间 使 得 Qt 能 在 <strong>Lazarus</strong> 中 使用 , 转 换 FastReports 和 TMS 代 码 ( 都 使 用 CLX 授 权 )...在 花 了 好 几 百 个 小 时 的 编 码 后 , 这 一 天 终 于 来 了 。 在 2008 年 二 月 未 期 我 展 示了 我 的 工 作 。 我 给 公 司 管 理 层 作 了 一 个 运 行 于 Linux,32 位 Windows 和 Mac OSX 的陈 述 , 公 司 管 理 层 感 到 很 高 兴 和 很 满 意 。当 然 那 儿 仍 然 有 错 误 并 且 一 些 特 性 还 未 实 现 , 但 是 他 们 很 欣 赏 我 的 主 要 论点 。 如 果 我 们 移 植 到 <strong>Lazarus</strong> 我 们 可 以 运 行 于 其 它 ( 甚 至 更 多 ) 支 持 的 平 台 , 并 且同 样 因 为 <strong>Lazarus</strong> 是 一 个 开 放 源 代 码 的 项 目 , 我 们 不 需 要 像 过 去 一 样 等 待 别 的 公司 的 决 定 ( 如 Borland) 来 损 害 我 们 的 利 益 。接 下 来 的 几 年 是 我 的 工 作 生 涯 中 很 愉 快 的 日 子 。 我 制 订 我 们 的 应 用 软 件 移 植到 <strong>Lazarus</strong> 预 算 表 和 时 间 需 求 。 现 在 我 拥 用 一 个 合 理 的 时 间 (15 个 月 ) 来 转 换 到<strong>Lazarus</strong> 并 且 为 <strong>Lazarus</strong> 重 写 公 司 的 应 用 软 件 ( 并 且 安 排 其 它 每 天 任 务 )。在 2008-2009 之 间 我 转 换 了 所 有 的 第 三 方 组 件 , 完 成 了 我 们 所 有 的 应 用 软 件


转 换 到 FPC/<strong>Lazarus</strong>, 同 样 给 <strong>Lazarus</strong> 项 目 组 贡 献 了 许 多 补 丁 。目 标 完 成 - <strong>Lazarus</strong> 比 Kylix 3 更 好 并 且 我 们 已 经 开 始 布 置 了 LCL 应 用 软 件超 过 3500 个 客 户 地 点 。由 于 在 所 有 平 台 上 我 们 的 应 用 看 上 去 都 是 本 地 的 , 所 以 我 们 得 到 了 用 户 的 肯定 。自 从 我 们 首 次 给 他 们 安 装 本 地 应 用 ( 他 们 使 用 Parsllels + Linux VM), 一 些Mac OSX 的 用 户 也 非 常 高 兴 。哇 , 多 美 好 的 一 天 啊 。 我 们 真 的 不 再 需 要 Borland 的 产 品 了 。现 在 我 们 使 用 FPC/<strong>Lazarus</strong> 和 PostgreSQL RDBMS 完 成 了 所 有 软 件 的 开 发 工作 :1. HoloERP - ERP 系 统 > 400 个 模 块 ( 窗 体 )2. Cafeman - 咖 啡 吧 和 餐 馆 后 台 管 理 系 统 和 POS 系 统3. TSuS - 小 型 商 店 后 台 管 理 系 统 和 POS 系 统4. Cinema - 电 影 院 软 件 ( 预 约 , 票 务 等 等 )5. ArhStudio - 建 筑 师 文 档 数 据 库 。所 有 这 些 软 件 使 用 了 以 下 第 三 方 组 件 :· ZeosLib· FastReports (CLX 接 口 )· TMS Grids (CLX 接 口 , 但 我 们 拥 有 一 个 新 的 VCL 授 权 和 同 样 的 接 口 )· TMS Planner (CLX 接 口 , 后 来 是 VCL)· FlexCell (LCL 授 权 许 可 , 是 的 , 它 们 是 LCL 版 本 )· 我 们 自 己 开 发 的 组 件结 论 :<strong>Lazarus</strong> 已 经 准 备 好 商 业 开 发 应 用 了 , 特 别 是 针 对 以 前 的 Kylix3/Delphi 7代 码 。我 个 人 的 看 法 当 前 (0.9.29 分 支 ) 的 <strong>Lazarus</strong> QT 比 K3/D7 更 优 秀 , 并 且 开 发 者将 非 常 乐 意 使 用 新 版 本 0.9.30.为 什 么 ?· 这 个 OOP RAD 支 持 如 此 多 的 平 台 。


· 志 愿 者 坚 持 不 懈 的 开 发 , 它 不 依 赖 于 商 业 决 策 所 以 可 以 避 免 破 产 。· 除 了 花 费 精 力 和 时 间 , 几 乎 没 有 成 本 。· 如 果 它 不 适 合 你 的 需 求 , 你 可 以 修 改 它 并 且 分 发 。· 如 果 那 里 有 错 误 Bug - 你 可 以 修 复 它 并 且 分 发 它 , 或 者 至 少 你 可 以 打 开<strong>Lazarus</strong> 问 题 追 踪 系 统 来 查 找 你 的 答 案 。


版 )附 录 C浴 火 重 生 的 Firebird(HTML[ 原 文 ]http://firebird.net.cn/forum_view.asp?forum_id=4&view_id=2970“ 火 鸟 是 传 说 中 的 不 死 鸟 , 它 可 以 穿 越 时 空 , 不 死 不 灭 , 阿 拉 伯 人 叫 它 费 利克 斯 , 中 国 人 则 称 它 们 为 凤 凰 , 火 鸟 不 会 死 亡 , 它 们 会 在 火 中 重 生 ……”—— 手 冢 治 虫Firebird( 火 鸟 ) 是 一 个 “ 开 放 源 代 码 ” 的 大 型 关 系 数 据 库 管 理 系 统 , 具 有跨 平 台 、 高 并 发 、 高 性 能 等 特 点 , 被 很 多 应 用 系 统 采 用 。 其 独 创 的 多 代 体 系 结 构 ,与 目 前 流 行 的 其 他 关 系 数 据 库 管 理 系 统 截 然 不 同 。Firebird 自 1984 年 诞 生 以 来 ,稳 步 向 前 发 展 , 历 经 几 次 名 称 变 更 , 如 传 说 中 的 火 鸟 , 每 次 都 在 烈 火 中 重 生 、 升华 。发 展 历 程Firebird 见 证 了 关 系 数 据 库 从 无 到 有 , 从 发 展 到 壮 大 的 历 史 进 程 。 让 我 们回 到 过 去 吧 , 亲 身 感 受 一 下 Firebird 的 次 次 烈 火 重 生 !上 世 纪 70 年 代 , 在 数 据 库 领 域 , 网 状 数 据 库 和 层 次 数 据 库 占 绝 对 统 治 地 位 。1970 年 ,IBM 的 研 究 员 E.F.Codd 博 士 在 刊 物 Communication of CAM 上 发 表 了“A Relational Model of Data for Large Shared Data Banks” 论 文 , 奠 定 了关 系 模 型 的 理 论 基 础 。 从 此 以 后 , 很 多 厂 商 、 学 校 加 入 关 系 数 据 库 的 研 发 热 潮 。1975 年 , 一 个 编 写 关 系 数 据 库 的 机 会 驱 使 Jim Starkey 来 到 了 DEC 公 司 ,在 此 期 间 ,Jim Starkey 负 责 设 计 编 写 了 Datatrieve( 一 个 运 行 在 平 面 文 件 和DBMS-32 上 的 关 系 查 询 语 言 )。DEC 公 司 的 关 系 数 据 库 设 计 小 组 一 直 忙 于 在 开 会 、研 究 文 献 、 争 论 问 题 , 没 有 写 一 行 代 码 。Jim Starkey 等 得 不 耐 烦 了 , 就 自 行 研究 数 据 影 像 技 术 。 在 一 次 早 晨 沐 浴 时 , 当 他 透 过 浴 室 多 重 窗 户 看 到 外 面 的 树 林 时 ,灵 感 突 现 , 意 识 到 数 据 影 像 技 术 也 是 防 止 数 据 更 改 冲 突 以 及 取 消 失 败 事 务 的 灵 丹妙 药 。Jim Starkey 发 明 了 “ 多 代 体 系 结 构 ”(Multi GenerationalArchitecture)! 随 后 , 在 兴 趣 的 驱 使 下 , 他 以 多 代 结 构 为 核 心 , 开 始 设 计 自 己的 数 据 库 管 理 系 统 ——JRD。 当 DEC 的 管 理 层 发 现 公 司 内 部 存 在 两 个 关 系 数 据 库


项 目 时 , 一 场 “ 战 争 ” 不 可 避 免 地 爆 发 了 。 结 果 是 , 政 治 谋 杀 了 JRD。“ 如 果 注 定 要 痛 苦 , 那 么 我 宁 愿 忍 受 自 己 的 错 误 ( 而 不 是 别 人 的 错 误 ) 造 成的 痛 苦 ”。1984 年 8 月 ,Jim Starkey 离 开 了 工 作 近 10 年 的 DEC 公 司 。1984 年 9月 4 日 , 他 独 立 创 业 , 成 立 了 Groton Database Systems( 扩 展 名 gds 的 由 来 )公 司 , 开 发 通 用 型 关 系 数 据 库 管 理 系 统 ,JRD 获 得 了 新 生 ,JRD 变 成 了 Groton。后 来 , 受 到 客 户 启 发 , 公 司 改 名 为 InterBase, 其 产 品 由 Groton 改 名 为 InterBase。他 的 太 太 Ann Harrison 也 加 入 了 公 司 , 负 责 公 司 的 日 常 运 营 , 而 Jim Starkey则 专 注 于 开 发 。1986 年 ,InterBase 推 出 2.0 版 ;1988 年 推 出 3.0 版 ;1989 年 ,VAX/VMS 平 台 上 的 版 本 推 出 ; 到 1991 年 ,HP-UX、DG/UX、Ultrix、SunOS/Solaris、AIX、SCO 平 台 上 的 版 本 也 相 继 推 出 。InterBase 在 当 时 获 得 了 巨 大 成 功 , 数 千 美 元 一 份 , 附 带 几 个 很 少 的 命 令 行工 具 。 没 有 利 用 外 资 ,InterBase 自 食 其 力 , 独 立 发 展 了 5 年 。 同 一 年 代 ,ORACLE于 1979 年 夏 天 发 布 了 第 一 个 版 本 的 商 用 SOL 关 系 数 据 库 系 统 , 用 于 DEC 公 司 的PDP-11 计 算 机 , 不 支 持 事 务 处 理 。1983 年 ,IBM 公 司 第 一 次 推 出 关 系 数 据 库 产品 ——DB2 for MVSV1。1984 年 Sybase 公 司 成 立 , 获 得 了 数 千 美 元 的 风 险 投 资 ,于 1987 年 5 月 推 出 第 一 个 关 系 数 据 库 产 品 Sybase SQLServer 1.0, 提 出 了Client/Server 数 据 库 体 系 结 构 思 想 。 微 软 公 司 与 Sybase 公 司 签 订 了 合 作 协 议 ,于 1989 年 发 布 了 SQL Server 1.0 版 。 从 此 以 后 , 随 着 技 术 的 成 熟 和 完 善 , 关 系数 据 库 日 益 流 行 和 普 及 。当 时 ,InterBase 能 够 在 ORACLE、DB2、Sybase SQLServer、Informix、MS SQLServer 等 的 夹 缝 中 自 力 更 生 , 顽 强 生 存 了 5 年 , 真 是 个 奇 迹 。1991 年 ,Ashton-Tate 公 司 购 买 了 全 部 的 InterBase。 随 后 ,InterBase 便扩 展 到 了 18 个 操 作 系 统 平 台 上 运 行 。 公 司 管 理 层 不 仅 好 大 喜 功 , 不 切 实 际 地 要求 InterBase 超 过 同 时 代 的 dBase 和 Sybase, 而 且 还 三 心 二 意 , 同 时 投 资 支 持Sybase 公 司 。 随 后 ,Jim Starkey 独 自 离 开 了 约 65 人 的 InterBase 开 发 团 队 ,这 一 去 便 是 10 多 年 。1992 年 Borland 收 购 了 Ashton-Tate 公 司 ,InterBase 成 为 Borland 产 品 中的 重 要 一 员 。 伴 随 着 Borland 公 司 的 开 发 工 具 ,InterBase 在 全 球 遍 地 开 花 。1994年 ,Borland 公 司 发 布 了 Interbase 4.0, 直 到 1997 年 12 月 1 日 才 发 布 Interbase


5.0。 让 全 世 界 人 们 吃 惊 的 是 ,2000 年 7 月 25 日 Borland 竟 宣 布 Interbase 6.0公 开 源 代 码 , 在 全 世 界 关 系 数 据 库 领 域 中 掀 起 了 一 股 开 源 热 潮 。条 件 已 经 成 熟 , 准 备 迎 接 Firdbird 时 代 吧 !拥 抱 开 源摆 脱 了 禁 锢 的 Firebird, 海 阔 天 空 , 自 由 翱 翔 吧 !火 山 岩 熔 积 聚 太 久 , 即 将 喷 发 。InterBase 的 命 运 应 该 由 用 户 决 定 。 由 于 开源 的 Interbase 6.0 不 允 许 外 部 开 发 者 参 与 ,2000 年 7 月 31 日 ,Mark O'Donohue和 一 群 InterBase 狂 热 爱 好 者 遵 循 IPL(InterBase Public License)v.1.0 协议 , 在 Source Forge 网 站 上 建 立 了 FirebirdSQL Project 项 目 。 自 由 开 放 的Firebird 诞 生 了 。 刚 开 始 处 境 艰 难 , 他 们 手 中 只 有 “ 只 读 ” 的 Interbase 6.0源 文 件 ,Borland 未 公 布 “makefile” 等 其 它 技 术 细 节 , 不 能 直 接 编 译 运 行 。 另外 , 缺 乏 资 金 支 持 , 毕 竟 程 序 员 也 要 吃 饭 。2000 年 7 月 28 日 ,InterBase 元 老 级 人 物 Ann Harrison 从 Borland 公 司 辞职 。8 月 23 日 , 她 和 Paul Beach 带 领 几 个 InterBase 开 发 人 员 成 立 了 IBPhoenix组 织 , 对 Firebird 用 户 提 供 咨 询 、 支 持 服 务 , 赞 助 Firebird 开 发 。 随 后 , 加 拿大 公 司 BroadView 也 加 入 了 赞 助 商 的 行 列 。 为 了 更 好 地 开 展 工 作 ,2002 年 12 月12 日 FirebirdSQL 基 金 会 成 立 , 一 个 非 赢 利 组 织 , 目 的 是 提 供 一 个 非 商 业 性 基础 设 施 , 用 来 收 取 、 支 付 基 金 , 推 进 和 支 持 FirebirdSQL 项 目 和 子 项 目 的 开 发 。加 入 该 组 织 需 要 每 年 交 付 会 费 ,IBPhoenix 和 BroadView 均 是 金 牌 会 员 。FirebirdSQL 基 金 会 的 委 员 会 决 定 基 金 的 使 用 , 他 们 把 资 金 给 予 那 些 在 关 键 领域 、 主 线 开 发 的 Firebird 开 发 人 员 。万 事 俱 备 , 全 世 界 那 些 天 才 的 开 发 人 员 开 始 发 力 ,Firebird 该 为 世 人 表 演那 精 美 绝 伦 的 舞 蹈 了 !2002 年 3 月 12 日 ,Firebird 1.0 发 布 。V1.0 开 发 完 成后 , 工 作 重 心 转 到 “ 将 代 码 从 C 移 植 到 C++” 上 面 ,Firebird 1.5 项 目 成 立 。 经过 了 三 个 版 本 , 到 2004 年 12 月 25 日 , 正 式 发 布 了 V1.52。2001 年 春 天 , 一 群 俄 罗 斯 人 自 立 门 户 , 在 Firebird 基 础 上 , 发 布 了 一 个 商业 关 系 数 据 库 ——Yaffil, 专 注 于 Windows 平 台 , 增 强 了 系 统 性 能 , 只 支 持 俄 语 ,服 务 本 民 族 用 户 。 令 人 高 兴 的 是 ,2003 年 11 月 ,Yaffil 主 动 回 到 了 Firebird怀 抱 ,Yaffil 新 的 功 能 将 会 融 入 到 Firebird 2.0 中 。2003 年 冬 天 发 生 了 Firebird


历 史 上 最 重 要 的 一 件 事 : 阔 别 10 多 年 的 InterBase 之 父 Jim Starkey 又 回 来 了 。20 年 来 , 他 所 创 建 的 核 心 构 架 一 直 没 有 变 动 。 他 要 带 领 旧 部 大 干 一 场 , 为 未 来的 20 年 再 重 新 搭 建 一 个 新 的 基 础 构 架 ! 他 们 进 行 的 项 目 被 称 为 “Vulcan”。Firebird 2.0 项 目 已 于 2005 年 2 月 份 开 发 完 成 ,2005 年 5 月 发 布 。 下 面 列举 一 些 Firdbird 2.0 新 增 加 的 功 能 :1、 对 SQL 标 准 支 持 增 强 : 支 持 SQL200X 标 准 定 义 的 “ 派 生 表 ”(derivedtables)、 为 了 和 SQL-99 标 准 一 致 , 引 进 了 “SEQUENCE”, 用 来 代 替 “GENERATOR”;2、 经 典 结 构 模 式 (Classic architecture) 支 持 全 部 API;3、 支 持 64 位 操 作 系 统 平 台 ;4、 内 置 函 数 增 加 ;5、 存 储 过 程 语 言 (PSQL) 增 强 : 支 持 “ 显 式 游 标 ”、 存 储 过 程 支 持 默 认 参 数 、支 持 “LEAVE 标 号 ” 语 法 、 将 用 户 自 定 义 函 数 (UDF) 作 为 存 储 过 程 调 用 等 ;6、 索 引 得 到 增 强 :252 字 节 限 制 取 消 、 支 持 “ 表 达 式 索 引 ” 等 ;7、 改 进 的 优 化 器 ;8、 安 全 增 强 : 安 全 数 据 库 结 构 改 变 、 口 令 加 密 更 安 全 、 远 程 不 能 访 问 安 全数 据 库 、 阻 止 “ 暴 力 破 解 ” 行 为 ;9、 在 线 增 量 备 份 。Vulcan 是 和 Firebird 2.0 并 行 开 发 的 项 目 , 已 于 2004 年 底 开 发 完 成 。Firebird 2.0 正 式 发 布 后 ,Vulcan 和 Firebird 2.0 合 并 , 成 为 Firebird 3.0。目 前 最 新 的 发 布 版 本 是 Firebird 2.1。 下 面 列 举 一 些 Vulcan 新 增 加 的 功 能 特 性 :1、 支 持 SMP: 在 一 台 机 器 上 ,Vulcan 在 4 处 理 器 上 的 基 准 测 试 成 绩 是 单 处理 器 的 3.5 倍 。2、 统 一 数 据 库 存 取 体 系 结 构 : 根 据 目 前 流 行 软 硬 件 技 术 , 核 心 体 系 进 行 了重 新 梳 理 更 新 ; 原 来 的 “ 超 级 服 务 器 模 式 ”、“ 经 典 模 式 ”、“ 嵌 入 模 式 ” 得 到 统 一 ,用 户 可 根 据 配 置 文 件 指 定 使 用 何 种 模 式 。3、 配 置 文 件 显 著 更 新 : 支 持 级 联 配 置 文 件 。4、 安 全 管 理 器 可 自 定 义 配 置 : 不 同 单 位 需 要 不 同 级 别 的 用 户 权 限 管 理 , 可由 用 户 加 载 安 全 管 理 器 。5、 数 据 库 引 擎 集 成 SQL:DSQL 集 成 到 数 据 库 引 擎 内 部 , 更 加 高 效 。


Firebird 3.0 那 些 新 增 加 的 诱 人 的 特 性 , 为 Firebird 挺 进 高 端 市 场 又 增 加了 一 块 重 要 砝 码 。 随 着 Firebird 的 成 功 表 现 , 一 些 商 业 数 据 库 也 纷 纷 拥 抱 开 源 ,多 米 诺 骨 牌 效 应 产 生 了 。 许 多 IT 公 司 对 开 放 源 代 码 的 立 场 已 经 从 抵 触 、 怀 疑 、观 望 转 变 为 参 与 直 至 推 动 。2004 年 8 月 10 日 ,CA 公 司 公 布 了 数 据 库 Ingres r3的 源 代 码 。 接 着 IBM 公 司 向 Apache 捐 献 了 关 系 数 据 库 Cloudscape, 也 公 开 了Cloudscape 源 代 码 。 另 外 , 据 说 DB2 也 要 走 向 开 源 。功 能 特 性Firebird 具 备 一 个 完 整 关 系 型 数 据 库 管 理 系 统 (RDBMS) 的 全 部 优 点 , 下 面列 举 了 一 些 特 性 :1、 支 持 SQL 标 准 。Firebird 完 全 符 合 SQL-92 标 准 要 求 , 并 与 许 多 ANSI SQL-99、SQL-2003 标 准 项 目 兼 容 。 通 过 机 连 操 作 、 更 新 视 图 、 外 连 结 , 它 支 持 声 明引 用 完 整 性 。Firebird 服 务 器 提 供 了 大 量 的 程 序 库 , 支 持 嵌 入 式 SQL 和 DSQL 客户 端 应 用 程 序 开 发 。 在 所 有 的 平 台 上 , 客 户 端 应 用 程 序 能 够 写 成 Firebird API形 式 , 通 过 它 向 数 据 库 服 务 器 发 送 操 作 请 求 。Firebird 还 支 持 扩 展 SQL 特 性 ,部 分 已 经 达 到 了 SQL99、SQL2003 的 标 准 , 包 括 存 储 过 程 、 触 发 器 、SQL 角 色 、BLOB段 、 序 列 、 派 生 表 等 。2、 多 代 体 系 结 构 (MGA)。 Firebird 采 用 了 多 代 体 系 结 构 (Multi-Generational Architecture:MGA), 这 是 其 区 别 于 其 它 任 何 大 型 关 系 数 据 库 的显 著 特 点 , 也 是 使 性 能 大 幅 提 升 的 关 键 所 在 。 在 MGA 体 系 中 , 独 创 了 版 本 事 务 模式 (Versioning Model), 与 其 它 数 据 库 系 统 传 统 的 加 锁 方 式 比 较 而 言 , 应 该 说这 是 目 前 最 先 进 的 解 决 多 用 户 并 发 访 问 的 方 法 之 一 。 在 多 代 结 构 中 , 会 为 记 录 保留 多 个 记 录 版 本 , 它 的 卓 越 之 处 在 于 “ 长 的 读 事 务 不 会 堵 塞 写 事 务 ”, 因 而 特 别适 合 涉 及 到 大 量 客 户 的 大 型 在 线 事 务 处 理 (OLTP) 和 需 要 海 量 数 据 的 数 据 决 策 支持 (DSS) 的 混 合 应 用 系 统 。3、 卓 越 的 多 数 据 库 管 理 功 能 以 及 自 动 两 阶 段 提 交 和 分 布 式 两 阶 段 提 交 恢 复机 制 。Firebird 是 一 个 多 数 据 库 的 RDBMS, 一 个 数 据 库 引 擎 可 以 同 时 运 行 并 管 理多 个 数 据 库 , 每 个 数 据 库 都 包 含 自 己 的 数 据 库 对 象 和 事 务 日 志 。 在 跨 越 2 个 以 上的 数 据 库 事 务 操 作 中 ,Firebird 提 供 了 良 好 的 两 阶 段 提 交 和 两 阶 段 提 交 恢 复 机制 , 确 保 了 每 个 数 据 库 数 据 的 一 致 性 。


4、 最 简 单 的 安 装 配 置 。Firebird 是 目 前 世 界 上 安 装 最 快 捷 、 最 简 单 的 大 型关 系 数 据 库 。 点 击 几 个 “Next” 便 可 在 5 分 钟 内 完 成 全 部 安 装 。 建 立 数 据 库 配 置完 成 后 ,Firebird 自 动 调 节 成 最 优 状 态 运 行 , 无 需 专 职 数 据 库 管 理 员 , 几 乎 是零 维 护 。5、 自 动 化 管 理 、 零 维 护 。Firebird 可 以 及 时 根 据 用 户 的 使 用 情 况 、 操 作 系统 的 运 行 状 况 , 在 底 层 自 动 调 节 自 身 的 多 项 参 数 以 保 证 其 始 终 运 行 在 最 优 状 态 。这 种 卓 越 特 性 使 得 即 便 没 有 专 职 数 据 库 管 理 员 , 整 个 数 据 库 系 统 也 可 以 高 枕 无 忧地 运 行 使 用 , 达 到 了 零 维 护 。6、 齐 全 的 数 据 库 对 象 。Firebird 支 持 几 乎 所 有 大 型 关 系 数 据 库 都 有 的 对 象 ,包 括 数 据 库 、 表 、 列 、 索 引 、 视 图 、 存 储 过 程 、 增 强 的 触 发 器 、 缺 省 、 规 则 、 约束 、 用 户 自 定 义 函 数 (UDF) 等 , 具 备 丰 富 的 字 段 数 据 类 型 , 特 别 是 支 持 18 位 大型 精 确 数 字 类 型 , 全 面 满 足 金 融 财 会 等 关 键 业 务 需 求 ; 还 支 持 用 户 自 定 义 数 据 类型 ( 域 )、 支 持 数 组 字 段 、 大 容 量 的 无 格 式 二 进 制 数 据 (BLOB) 字 段 , 与 其 它 某些 数 据 库 系 统 不 同 ,Firebird 的 BLOB 数 据 完 全 是 在 事 务 的 控 制 下 操 作 的 , 并 且连 同 其 它 数 据 一 起 存 放 在 同 一 个 数 据 库 中 , 确 保 了 对 大 型 数 据 操 作 的 一 致 性 和 效率 。7、 卓 越 的 跨 平 台 特 性 、 支 持 多 种 网 络 协 议 。Firebird 可 以 在 所 有 的 Windows操 作 系 统 、 各 种 Linux 发 行 版 本 、 各 种 Unix 及 Unix 的 后 代 等 操 作 系 统 平 台 上 安装 运 行 , 其 优 越 性 不 仅 仅 在 于 这 些 平 台 的 透 明 性 , 更 重 要 的 是 这 些 平 台 间 数 据 的无 缝 连 接 , 你 只 要 使 用 简 单 的 备 份 和 恢 复 操 作 , 就 可 以 把 一 种 平 台 中 的 数 据 顺 利移 植 到 另 一 种 平 台 中 正 常 使 用 , 一 点 都 不 需 要 其 它 复 杂 转 换 。Firebird 支 持 多种 网 络 协 议 , 所 有 平 台 的 Firebird 均 支 持 TCP/IP;Windows 平 台 上 的 Firebird支 持 NetBEUI/named pipes; 服 务 器 版 的 Firebird 和 所 有 Windows 客 户 端 均 支持 IPX/SPX。8、 最 方 便 的 客 户 端 安 装 。Firebird 的 嵌 入 式 版 本 一 张 软 盘 容 量 , 既 可 以 作为 本 地 单 机 版 的 服 务 器 , 也 可 以 作 为 远 程 服 务 器 的 客 户 端 , 可 以 将 这 几 个 文 件 打包 到 应 用 程 序 安 装 盘 中 。 应 用 程 序 安 装 后 系 统 即 可 连 接 远 程 服 务 器 运 行 , 不 用 再单 独 安 装 Firebird 的 客 户 端 。9、 灵 活 性 、 高 可 靠 性 、 安 全 性 和 可 扩 充 性 。Firebird 具 备 完 善 的 用 户 管 理


和 权 限 管 理 , 确 保 了 数 据 库 的 安 全 , 其 强 大 的 联 机 事 务 处 理 功 能 可 以 边 进 行 数 据库 操 作 边 进 行 数 据 库 备 份 。Firebird 的 异 步 取 消 机 制 可 以 让 用 户 方 便 地 取 消 正在 执 行 的 操 作 , 特 别 是 当 运 行 较 长 的 或 复 杂 的 查 询 影 响 数 据 库 性 能 时 。XML 功 能可 以 让 用 户 直 接 从 Firebird 数 据 库 中 创 建 XML 文 档 。Firebird 的 自 动 崩 溃 恢 复能 力 使 得 在 断 电 或 其 它 故 障 导 致 系 统 崩 溃 时 完 全 可 以 在 没 有 专 职 数 据 库 管 理 员的 干 预 下 自 动 、 及 时 、 快 速 地 进 行 数 据 恢 复 , 用 户 需 要 做 的 就 是 接 通 电 源 让 数 据库 工 作 , 其 他 一 切 都 交 给 Firebird 处 理 。 此 外 , 可 以 为 数 据 库 创 建 分 布 式 镜 像 ,进 一 步 确 保 Firebird 的 可 靠 性 。 无 论 是 单 用 户 应 用 还 是 企 业 级 应 用 、 无 论 桌 面版 还 是 服 务 器 版 ,Firebird 均 使 用 统 一 的 底 层 代 码 , 极 大 地 方 便 了 用 户 的 扩 展 。10、 最 广 泛 的 管 理 工 具 、 开 发 工 具 的 支 持 。 其 范 围 之 广 、 数 量 之 多 , 是 其 他数 据 库 所 不 能 比 的 。Firebird 与 其 它 所 有 关 系 数 据 库 的 最 大 区 别 是 “ 多 代 体 系 结 构 (MGA)”, 其“ 长 的 读 事 务 不 会 堵 塞 写 事 务 ” 的 特 性 使 得 Firebird 在 相 同 的 硬 件 条 件 下 性 能优 于 传 统 “ 加 锁 事 务 ” 机 制 的 数 据 库 。 我 们 经 常 看 到 许 多 使 用 了 商 业 数 据 库 的 大型 应 用 系 统 , 为 了 提 高 系 统 性 能 和 并 发 度 , 往 往 采 用 两 台 数 据 库 服 务 器 , 一 台 为主 业 务 数 据 库 , 另 一 台 为 查 询 数 据 库 , 这 种 情 况 在 Firebird 身 上 是 不 会 发 生 的 。在 企 业 级 的 中 端 市 场 , 同 其 他 商 业 数 据 库 相 比 ,Firebird 具 有 极 强 的 综 合 竞 争力 ; 在 低 端 嵌 入 式 市 场 , 其 地 位 是 DB2、Oracle、Sybase 所 无 法 撼 动 的 。 唯 有 高端 大 型 主 机 集 群 领 域 ,Firebird 现 在 还 底 气 不 足 。Firebird 的 前 身 Interbase 在 全 球 拥 有 数 百 万 商 业 用 户 , 驰 骋 疆 场 15 载 ,是 一 个 成 熟 稳 定 的 企 业 级 产 品 , 这 一 点 是 其 它 开 源 关 系 数 据 库 (PostGreSql、MySQL、BerkelyDB 等 ) 所 不 能 比 的 。总 结Firebird 历 经 重 重 艰 难 险 阻 , 现 在 终 能 昂 首 自 由 飞 翔 。 在 全 世 界 开 源 自 由爱 好 者 的 推 动 下 ,Firebird 六 年 来 飞 速 发 展 。 作 为 一 个 成 熟 的 企 业 级 商 业 关 系数 据 库 的 后 代 ,Firebird 可 应 用 于 各 种 领 域 , 胜 任 关 键 性 任 务 。 其 独 创 的 “ 多代 版 本 体 系 ” 使 得 系 统 短 小 精 悍 , 高 效 健 壮 。 各 种 完 备 的 开 发 接 口 技 术 , 适 合 各种 开 发 环 境 。 然 而 , 目 前 Firebird 在 中 国 没 有 流 行 开 来 , 这 和 开 源 软 件 没 有 进行 商 业 广 告 宣 传 有 很 大 的 关 系 。 我 免 费 使 用 Firebird 多 年 , 未 对 其 作 出 多 大 贡


献 , 本 文 就 算 是 一 种 补 偿 吧 。 愿 国 内 同 行 积 极 评 估 、 使 用 Firebird, 提 高 产 品的 竞 争 力 ; 有 能 力 者 加 入 Firebird 开 发 团 队 , 锦 上 添 花 。Firebird 3.0 发 布 后 ,Jim Starkey 会 在 Firebird 中 嵌 入 Java 虚 拟 机 来 支 持 触 发 器 、 存 储 过 程 、 用 户自 定 义 函 数 。 可 以 预 见 , 在 Jim Starkey 的 领 导 下 , 未 来 的 Firebird 会 越 飞 越高 。文 / 田 永 利来 源 :http://blog.sina.com.cn/s/blog_4c83c6bf010009lu.Html

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!