PowerBuilder应用开发系列讲座(1)

鬼谷子
PowerBuild 的高级菜单设计技术
武警学院计算机中心 程连孚
  做为事件驱动的系统,菜单所起的作用是明显的。一个好的菜单,能给程序起到锦上添花的作用。
PowerBuild 5.0(以下简称PB5)在这方面给用户提供了很大的灵活性,使用户能根据自已的爱好和需求设计出各
种不同风格的菜单。下面就谈谈如何在PB5中实现两种别致的菜单:动态菜单和声音菜单。
一、动态菜单
如果一个程序的选项复杂,那么菜单项也会相应地增多。在主界面上设置过多的菜单项会影响界面的简洁,有时也
会使用户无所适从。如果将菜单设置成动态菜变化的菜单,在一个功能下只显示相应的菜单,那么用户使用起来会
效果更好。菜单在PB5中是窗口的一个属性,我们可在通过改变这种属性来改变窗口菜单的显示。我们假设在已存
在一个库test.pbl,该库中有一个标准的File菜单(m_file),
窗口上有一个按钮"Change to Another Applicatiuon",按下后,程序将启动另一个应用模块,该模块将用自
己的菜单来替代现有的菜单。我们可以通过下面的方法来实现这一功能。
1、在菜单模板下,创建一个菜单,设为 m_test,它与前面的file菜单有完全不同的设置
2、利用"Change to Another Application"按钮的脚本来改变菜单的显示。单现"Script"按钮,在其中添加如
下的语句:
Parent.ChangeMenu(m_test)
3、运行程序,即可得到结果。
需要说明地是,改变菜单项必须通过ChangeMenu( )函数,而不能通过标准的"."来无成,因为在PB5中,菜单
对窗口来说是保护(protected)属性,该属性只能通过界面函数来访问。另外,如果在菜单项中添加脚本来动
态改变菜单,则脚本中应该使用语名:
ParentWindow.ChangeMenu(m_test)
二、为菜单添加声音
在多媒体演示产品中,我们经常会遇到这样的情形,当鼠标单击某一菜单或按钮时,音箱会发出某种音效(如
果有这种设备的话),这使得软件更加生动。在 PB中我们也可以很容易地实现这一点。
PB中没有直接调用多媒体功能的函数,要想为一个程序加入多媒体功能,必须通过调用Windows API函
数"SndPlaySound()"或"PlaySound()"来完成。假设我们己有有了一个库"test.pbl",其菜单也如前所示,具
体实现步骤
如下 :
1、在"Declare"菜单中选择"Local External Functions…",弹出的对话框中填入如下的声明语句:
Function Boolean sndPlaySound(String s_file,&
UINT u_flags) Library "WINMM.dll"
Function UINT LoadLibrary(String as_library) "kernel32.dll"
Subroutine FreeLibrary(UINT Hinstance)Library "kernel32.dll"
实际上PB中的菜单也是动态的,"Declare"必须在编辑菜单时才出现
2、为每个菜单项选择相应的声音文件" .WAV"
3、为菜单项添加脚本,驱动声音文件,以"new"菜单为例:
sndPlaySound ("new.wav",0)
sndPlaySound函数有两个参数,前面的一个为声音文件名,后面的一个为播放方式,主要用到有如下几个:
0--同步播放
1--异步播放
2--找不到声音文件即返回
4--播放声音文件在内存中的映象
声音文件最好是放在当前目录下,否则系统将按如下的顺序进行查找:当前目录,Windows目录,Windows系
统目录,PATH中列出的目录,
网络映射目录。 完成上述步骤后,运行程序即可听到菜单的声音了。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
在PB应用中实现声音与动画
珠海远都软件有限公司 卞国斌
---- 在 设 计 应 用 程 序 过 程 中, 恰 当 地 应 用 电 脑 声 音 与 动画 技 术, 可 以 为 用 户 提 供 更
加 直 观、友 好、 引 人 注 目 的 操 作 界 面。 下 面 笔 者 介 绍 一 下 在PowerBuild 应 用 中 实
现 声 音 与 动 画 的 一 种 简 便 方 法:
1.作 为 举 例, 创 建 一 个MDI 风 格 的 窗 口w_audani。 在 这 个 窗 口 上 放 置 一 个 含 声 音、
动 画 两 个 带 图 标 的 菜 单 项 的 菜 单m_audani, 一 个 图 象 框p_1。 整 个 窗 口 的 外 观 如
下:
2.制 备 声 音 和 图 象 文 件。 本 例 中 选 用 了 一 个adu.wav 的 声 音 文 件 和 四 个ani1.bmp、
ani2.bmp 、ani3.bmp、ani4.bmp 用 于 动 画 素 材 的 分 离 图 象 文 件。
3.定 义 程 序 编 制 中 要 用 到 的 变 量: (1) 定 义 一 个 整 型 实 例 变 量, 用 作 图 象 计 数
integer picturenub (2) 定 义 一 个 外 部 函 数, 使 在PowerBuild 编 程 中 可 以 调 用Windows 32-
bit API 声 音 播 放 函 数
function boolean sndplaysounda
(string soundname, uint flags) &
library "winmm.dll"
4.为 窗 口w_audani 编 制 事 件 处 理 程 序。 程 序 行 中// 后 的 为 说 明 文 字。
(1) 在 窗 口 的 打 开(Open) 事 件 下 输 入 程 序:
//声音菜单项置选中属性
m_audani.m_1.m_aud.checked = true
//动画菜单项置选中属性
m_audani.m_1.m_ani.checked = true
//图象计数器置初值
picturenub = 1
//定义每隔半秒钟触发一次窗口的timer事件
timer(0.5,this)
---- (2) 在 窗 口 的 计 时 器(Timer) 事 件 下 输 入 程 序:
---- // 如 果 声 音 菜 单 项 被 选 中, 则 调 用Windows 32-bit API 声 音 播 放 函 数 播 放 声 音 文
件。 函 数 第 一 个 参 数 指 出 要 播 放 的 声 音 文 件 名, 第 二 个 指 出 函 数 播 放 属 性, 属 性3
为 异 步、 不 缺 省
IF m_audani.m_1.m_aud.checked = true THEN
sndplaysounda("aud.wav",3)
END IF
//如果动画菜单项被选中,则播放动画
IF m_audani.m_1.m_ani.checked = true THEN
CHOOSE CASE picturenub
//当图象计数为1时,播放第1张图象
CASE 1
p_1.picturename = "ani1.bmp"
//当图象计数为2时,播放第2张图象
CASE 2
p_1.picturename = "ani2.bmp"
//当图象计数为3时,播放第3张图象
CASE 3
p_1.picturename = "ani3.bmp"
//当图象计数为4时,播放第4张图象
CASE 4
p_1.picturename = "ani4.bmp"
//恢复图象计数
picturenub = 0
END CHOOSE
//图象计数增1
picturenub ++
END IF
5.为 菜 单m_audani 编 制 事 件 处 理 程 序:
(1) 在 菜 单 项 声 音(m_aud) 的 单 击(Clicked) 事 件 下 输 入 程 序: // 使 该 菜 单 项 的 选 中 属
性 反 转 起 到 开 关 的 作 用, 即 原 来为 选 中 的 变 为 不 选 中, 未 选 中 的 则 现 在 变 成 选 中
this.checked = not this.checked
(2) 在 菜 单 项 动 画(m_ani) 的 单 击(Clicked) 事 件 下 输 入 程 序:
//同样,使该菜单项的选中属性反转
this.checked = not this.checked
6.执 行 该 程 序 的 大 致 情 况 是:
(1) 启 动 程 序 后, 自 动 打 开 以 上 图 示 的 窗 口;
(2) 窗 口 计 时 器 按 每 半 秒 钟 触 发 一 次 事 件 处 理 程 序, 播 放 声 音 和 图 象 文 件, 周 而
复 始 以 产 生 动 画 效 果;
(3) 单 击 声 音 或 动 画 菜 单 项( 工 具 图 标), 可 以 控 制 声 音 或 动 画 是 否 播 放。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder应用开发系列讲座(1)
数 据 库 的 事 务 管 理
华 天 新 技 术 开 发 公 司 张 健 姿
北 京 友 谊 宾 馆 30538 室 100873
Email: sjhzyz@public.bta.net.cn
---- 在 数 据 库 中, 所 谓 事 务 是 指 一 组 逻 辑 操 作 单 元, 使 数 据 从 一 种 状 态 变 换 到 另
一 种 状 态。 为 确 保 数 据 库 中 数 据 的 一 致 性, 数 据 的 操 纵 应 当 是 离 散 的 成 组 的 逻
辑 单 元: 当 它 全 部 完 成 时, 数 据 的 一 致 性 可 以 保 持, 而 当 这 个 单 元 中 的 一 部 分 操
作 失 败, 整 个 事 务 应 全 部 视 为 错 误, 所 有 从 起 始 点 以 后 的 操 作 应 全 部 回 退 到 开 始
状 态。
---- 对 事 务 的 操 作 是 这 样 进 行 的: 先 定 义 开 始 一 个 事 务, 然 后 对 数 据 作 修 改 操 作,
这 时 如 果 提 交(COMMIT), 这 些 修 改 就 永 久 地 保 存 下 来, 如 果 回 退(ROLLBACK), 数 据 库
管 理 系 统 将 放 弃 您 所 作 的 所 有 修 改 而 回 到 开 始 事 务 时 的 状 态。 此 外 有 些 数 据
库 支 持 事 务 的" 存 储 点(savepoint) 这 一 概 念: 即 在 一 个 事 务 进 程 中 任 意 一 点 您 都 可
以 进 行 当 前 状 态 的 存 储, 回 退 时 只 是 回 到 你 所 设 定 的 存 储 点, 而 不 必 退 回 全 部 的
事 务。 如 果 您 的 事 务 可 以 分 成 几 组 对 数 据 库 的 修 改, 那 就 可 以 设 置 多 个 存 储 点,
根 据 需 要 您 可 以 回 退 到 任 意 一 个 存 储 点, 而 不 使 所 有 事 务 的 修 改 数 据 全 部 丢
失。
---- 正 确 地 管 理 事 务 可 以 保 证 数 据 的 完 整 性, 当 您 所 做 的 工 作 全 部 完 成 和 得 到
确 认 之 前, 没 有 任 何 数 据 物 理 地 写 进 数 据 库。 让 我 们 来 看 这 样 一 个 实 例, 我 们 有
这 样 一 个 银 行 应 用 系 统, 前 台 使 用 者 作 出 将 储 户 甲 的 一 百 元 存 款 划 归 储 户 乙 帐
下 的 操 作; 在 后 台 的 数 据 库 中, 这 两 个 客 户 的 记 录 分 储 在 两 张 表 中, 当 使 用 者 在
屏 幕 上 作 出 如 上 操 作 时, 在 后 台 需 要 对 两 张 表 进 行 修 改。 如 果 在 数 据 库 中 对 甲
用 户 存 款 余 款 作 减 去 一 百 元 修 改 后, 对 乙 用 户 加 一 百 元 的 操 作 修 改 却 失 败 时, 前
一 张 表 也 必 须 回 到 修 改 前 的 状 态, 否 则 数 据 库 的 内 容 不 统 一, 甲 储 户 白 白 损 失 一
百 元, 信 息 必 然 是 不 正 确 的。 因 此 进 行 事 务 管 理 是 必 须 的。
---- 传 统 地, 我 们 认 为 一 个 事 务 包 括 了 对 一 个 或 多 个 表 的 修 改, 而 随 着 分 布 式 数
据 库 和 数 据 仓 库 的 发 展, 事 务 可 能 包 括 了 对 一 个 或 多 个 数 据 库 的 修 改。 在 上 例
中 甲 乙 两 用 户 就 可 能 是 异 地 用 户, 信 息 分 储 在 不 同 地 域 的 不 同 数 据 库 中, 上 述 的
一 个 事 务 就 涉 及 到 了 对 不 同 数 据 库 的 操 作 。
PowerBuilder 中 的 事 务 管 理
---- 作 为 数 据 库 的 前 台 开 发 工 具Power-Builder 支 持 事 务 管 理 的 操 作。 在Power-
Builder 中 有 一 种 称 作 事 务(transaction) 的 对 象, 这 个 对 象 是PowerBuilder 应 用 与 数 据
库 的 通 讯 区 域。P owerBuilder 在 应 用 开 始 时 建 立 一 个 全 局 的 事 务 对 象SQLCA。 由
于 大 多 数 的 应 用 只 用 到 一 个 数 据 库, 所 以 一 般 开 发 者 主 要 也 只 用SQLCA 作 为 与 唯
一 数 据 库 连 接 的 事 务 对 象。
----PowerScript 中 常 用 的 事 务 管 理 的 语 句 有 四
个:COMMIT,ROLLBACK,CONNECT,DISCONNECT。
---- 当 您 需 要 应 用 与 数 据 库 建 立 连 接 时 使 用CONNECT 这 一 操 作 命 令, 取 消 连 接 时
执 行DISCONN ECT, 这 两 个 命 令 一 般 分 别 用 在 应 用 的 开 始 和 结 束, 也 就 是Appli-cation
的Open 和Close 事 件 中 。
---- 当 一 个 事 务 的 数 据 库 修 改 都 成 功 地 完 成 后, 修 改 须 提 交 给 数 据 库,COM-MIT 语
句 是 一 个 旧 事 务 结 束 和 一 个 新 事 务 开 始 的 界 线。 在 修 改 被 提 交 前, 数 据 库 的 数
据 并 没 有 被 真 正 地 修 改, 这 些 修 改 被 保 留 在 某 个 工 作 区, 只 有 作 修 改 的 用 户 才 能
看 到 这 些 被 修 改 后 的 值, 提 交 之 后, 则 所 有 的 用 户 就 都 可 以 看 到 新 值 了。
---- 在 事 务 的 进 程 中 发 生 某 些 错 误, 或 者 在 操 作 中 出 于 种 种 原 因 打 算 中 止 事 务,
须 用ROLLBAC K 命 令 回 退 事 务, 如 果 已 作 的 操 作 不 用ROLLBACK 命 令 取 消, 这 些 操 作
必 将 错 误 地 作 为 下 一 个 事 务 的 一 部 分 而 导 致 数 据 库 的 混 乱。
---- 如 果 您 使 用 的 是 多 窗 口 的 应 用, 却 只 用 一 个 事 务 对 象, 就 应 格 外 注 意ROLL-BACK
和COMMIT 会 影 响 事 务 的 逻 辑 一 致 性。 在 某 个 窗 口 执 行 的 这 两 个 指 令 会 使 其 他
窗 口 应 用 中 所 进 行 到 一 半 的 工 作 提 交 或 回 退。
---- 在 多 用 户 系 统 中, 修 改 和 提 交 的 时 间 越 接 近, 提 交 成 功 的 可 能 性 就 越 高。 因 为
一 个 事 务 中 所 有 的SQL 语 句 全 部 执 行 成 功 而 提 交 却 失 败 是 完 全 可 能 发 生 的, 例
如 在 您 的 事 务 过 程 中, 另 一 个 用 户 修 改 了 数 据 并 提 交, 这 很 可 能 使 您 作 出 的 修 改
无 效, 这 时COMMIT 将 失 败, 您 必 须 回 退 这 一 事 务 的 全 部。
事 务 对 象 的AutoCommit 属 性
---- 事 务 对 象 有 一 个AutoCom-mit 的 属 性 可 以 使 开 发 者 简 化 对 事 务 管 理 的 操 作, 这
一 布 尔 型 的 属 性 可 以 用TRUE 或FALSE 来 对 其 赋 值。 当 其 为 真 时,PowerBuilder 不 通 过
其 他 额 外 的 交 互 就 将 您 的SQL 语 句 传 输 给 后 台 数 据 库, 而 且 执 行 完 毕 自 动 提 交。
---- 当 然, 您 可 以 设 置AutoCommit 属 性 为 假( 缺 省 值), 使 用COMMIT 或ROLLBACK 这 样 的 关
键 词 提 交 或 回 退 事 务。 在 大 多 数 应 用 中, 一 部 分 的 数 据 库 操 作 是 要 成 组 提 交 的,
而 另 一 些 则 不 用。 因 此 我 们 可 以 利 用AutoCommit 的 特 性 来 确 定 事 务 的 起 点, 当 我
们 把AutoCommit 的 属 性 设 为Fals e 时, 系 统 设 定 此 时 为 事 务 的 起 点。 当AutoCommit 设
为 真 时, 系 统 自 动 消 取 这 一 事 务。 因 此 你 可 以 先 把AutoCommit 设 为 真, 当 您 需 要 开
始 一 个 事 务 时, 将 其 置 为false, 此 刻 即 为 事 务 起 始 点 。
----PowerBuilder 内 部 这 种 事 务 管 理 的 最 大 优 点 是 方 便。 您 不 去 考 虑 整 个 事 务, 而
只 需 把 您 所 作 的 修 改 提 交 或 滚 回 即 可。 但 是 方 便 与 可 控 性 总 是 矛 盾 的, 在Power-
Builder 中 没 有 存 储 点 和 嵌 套 事 务 管 理 的 机 制, 即 使 您 所 使 用 的 数 据 库 支 持 这 些
特 性, 在PowerBuilder 中 却 无 法 得 以 体 现。 不 过 在 普 通 的 应 用 中, 存 储 点 和 嵌 套 事
务 管 理 并 不 是 必 须 的, 一 般 的 事 务 管 理 足 以 够 用 。
用 数 据 库 的 事 务 管 理 指 令 实 现 完 全 控 制
---- 上 述 的 事 务 管 理 方 式 尽 管 简 单 方 便, 但 是 在 某 些 应 用 中, 我 们 也 的 确 需 要 利
用 所 用 的 数 据 库 系 统 的 嵌 套 事 务 和 存 储 点 的 特 性, 而PowerBuilder 内 部 的 事 务 管
理 没 有 提 供 这 样 的 功 能, 您 必 须 自 己 设 计。
---- 自 己 进 行 事 务 管 理 的 方 式 是 直 接 使 用 数 据 库 本 身 的 事 务 指 令。 当 您 使 用 自
己 的 管 理 方 式 时, 就 应 使Power-Builder 停 止 管 理 事 务, 即 设 置Auto-Commit 为TRUE, 系 统
内 部 就 不 会 自 动 建 构 事 务 处 理 的 命 令 了。 实 现 人 工 事 务 管 理 的 方 式 是 采 用
EXECUTE IMMEDIATE 这 条PowerBuild er 指 令 来 执 行 任 意 的 数 据 库 操 作。 你 所 需 做 的
是 将 数 据 库 指 令 编 辑 成 一 个 字 符 串, 您 可 以 执 行 任 何 的 数 据 定 义 语 句 如 建 表、
建 主 键、 存 储 过 程 等, 例 如 您 可 以 用
----EXECUTE IMMEDIATE BEGIN TRANSACTION trans-name
---- 这 样 的 指 令 开 始 一 个 事 务。 采 用 这 种 方 法, 只 要 您 所 用 的 数 据 库 支 持 嵌 套 事
务 和 存 储 点 等 事 务 管 理, 我 们 通 过PowerBuilder 开 发 出 的 应 用 也 就 同 样 可 以 实 现。
---- 在PowerBuilder 中 提 供 的 事 务 管 理 的 方 法 是 多 种 多 样 的, 只 要 您 灵 活 运 用, 就 一
定 能 设 计 出 优 秀 的 数 据 库 应 用 来。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder 应 用 开 发 系 列 讲 座(2)
调 用Windows 的 动 态 链 接 库
华 天 新 技 术 开 发 公 司 张 健 姿
北 京 友 谊 宾 馆 30538 室 100873
Email: sjhzyz@public.bta.net.cn
---- 许 多 熟 练 使 用C 的 程 序 员 在 使 用PowerBuilder 时 都 希 望 自 己 以 前 在C 上 做 的 工
作 可 以 被P owerBuilder 引 用, 这 是 完 全 可 以 的。 在PowerBuilder 中 你 可 以 通 过 外 部 引
用 函 数 的 形 式 来 调 用 动 态 连 接 库 中 的 函 数。
----
PowerBuilder 调 用DLL 程 序 使 用 规 则
----PowerBuilder 可 以 支 持 任 何 一 种 非PowerScript 编 写, 并 存 储 在 动 态 链 接 库 中 的 外
部 函 数 或 过 程 的 调 用。 但 外 部 函 数 的 参 数 必 须 是 符 合Pascal 规 则 的( 即 参 数 压 栈
顺 序 从 前 至 后)。
---- 在 函 数 调 用 前, 因 先 作 函 数 声 明,PowerBuilder 支 持 以 下 两 种 外 部 函 数 类 型:
---- · 全 局 函 数: 可 以 在 应 用 的 任 意 位 置 调 用;
---- · 局 部 外 部 函 数: 在window,menu,user object 或 用 户 自 定 义 函 数 等 对 象 中 定 义。
---- 外 部 函 数 声 明 的 语 法 是:
----{Access}FUNCTION ReturnDataType Function-Name({REF}{DataTypel Arg1,...,Data TypeN
ArgN})LIBRARY LibName
---- 外 部 过 程 声 明 的 语 法 是:
----{Access}SUBROUTION Subroutine({REF}{DataType1 Arg1,...,DataTypeN ArgN})
---- 如 果 您 使 用 的 是 局 部 外 部 函 数 的 声 明, 您 还 可 以 指 定 对 象 的 访 问 权
限:Public,Private, Protected。 对 局 部 函 数 权 限 访 问 的 限 制 同 对 对 象 的 实 例 变 量 的
限 制 相 同。 您 可 以 指 定 对 象 名 加 函 数 名 的 方 式 调 用 外 部 函 数:
----object.function(arguments)
---- 如 在window 的w_emp 上 调 用 局 部 外 部 函 数Recog(), 就 可 这 样 使 用:
----w_emp.Recog()
----
如 何 在PowerBuilder 与DLL 之 间 传 递 参 数
---- 在PowerBuilder 的script 中 调 用DLL 中 的 函 数, 缺 省 情 况 下 是 通 过 传 值 法 来 传 递 参
数(pa ssed by value), 也 就 是 说PowerBuilder 将 对 要 传 递 的 参 数 做 一 份 拷 贝, 然 后 通 过
堆 栈 将 这 份 拷 贝 传 递 给 函 数。 如 果 你 希 望DLL 中 的 函 数 可 以 改 变 调 用 参 数 的 原
值, 就 可 以 通 过 参 考 传 值 法 (passed by reference) 来 传 递 参 数, 即 在 参 数 类 型 前 面 加
REF 关 键 字 来 声 明 该 参 数 将 要 用 参 考 传 值 法。
---- 在 使 用DLL 时 有 一 些 基 本 规 则
---- 在MS Windows 中, 一 个DLL 在 被 装 入 内 存 后, 只 会 有 一 个 实 例, 不 会 因 为 多 个 程 序
使 用 同 一 个DLL 而 在 内 存 中 产 生 多 个DLL 拷 贝。 每 个DLL 只 有 一 个 最 大 为64K 的 数
据 段。 缺 省 情 况 下,Po werBuilder 都 是 使 用 传 值 法 来 传 递 参 数。 当 你 在 函 数 应 用 说
明 时 使 用 了REF 关 键 字,PowerBu ilder 将 传 递 一 个32 位 的 地 址 指 针( 段 地 址+ 偏 移 量)
给 被 调 用 的 函 数, 而 不 是 只 传 递 偏 移 量, 这 才 能 保 证DLL 中 的 函 数 能 得 到
PowerBuilder 中 数 据 的 正 确 地 址。 在PowerBuilder 中 使 用 的 数 据 类 型 与C 语 言 支 持
的 数 据 类 型 不 尽 相 同,C 中 不 支 持 的 数 据 类 型 应 在 调 用 前 先 进 行 转 换。
---- 对 于 结 构, 要 在C 和PowerBuilder 中 做 相 等 的 说 明。
----PowerBuilder 不 支 持 函 数 指 针 的 传 递, 因 此 在PowerBuilder 中 不 能 使 用 回 调 函 数
(callb ack funcion)。 如 果DLL 的 参 数 需 要 空 指 针(NULL), 你 可 以 向 函 数 传 递 一 个 值 为0
的 长 整 型。
----Windows 中 使 用 的 有 些 数 据 类 型C 中 并 不 支 持, 但 一 般 在C 的 预 编 译 器 中 用
TYPEDEF 作 预 定 义, 同 时PowerBuilder 接 口 也 应 当 作 适 当 转 换。
----
使 用DLL 的 常 见 错 误 和 需 要 注 意 的 地 方
----1. 导 致 保 护 性 错(general protection fault)
---- 在Windows 中, 如 果 你 企 图 访 问 不 是 属 于 你 的 应 用 程 序 的 内 存 将 导 致 保 护 性
错。 导 致 保 护 性 错 的 原 因 可 能 有 以 下 几 点:
----a. 向DLL 中 的 函 数 传 递 了 不 正 确 的 参 数。 这 种 错 误 是 比 较 难 调 试 的, 因 为
PowerBuilder 的 调 试 器 不 能 跟 踪 到C 程 序 中。 你 可 以 通 过 在C 中 使 用MessageBox 函
数 显 示 调 用 参 数 的 方 法 来 检 查 参 数 传 递 的 正 确 性。 更 全 面 的 方 法 是 使 用
Windows 的 调 试 版 本( 带 有 调 试 信 息 的Windows 环 境) 和 功 能 更 强 的 调 试 器(Soft-ice
for windows 或CodeView 等);
----b.C 中 对 数 组 的 访 问 超 出 了PowerBuilder 中 申 请 的 边 界。 在C 中 是 不 作 数 组 边 界
检 查 的, 这 可 能 是 导 致 保 护 性 错 的 最 常 见 的 原 因;
----c. 使 用 了 已 经 释 放 的 内 存 指 针。 你 最 好 把 已 经 释 放 的 内 存 指 针 置 为NULL, 以
便 在 使 用 前 进 行 判 断。
----2. 使 用 远 指 针
---- 在C 中, 所 有 的 静 态 变 量 和 全 局 变 量 都 是 在 程 序 的 数 据 堆 中 分 配 的, 其 他 变 量
都 是 在 栈 中 分 配 的。DLL 可 以 有 自 己 的 数 据 段, 但 是 它 没 有 堆 栈 段, 使 用 的 是 调 用
程 序 的 堆 栈。 这 就 意 味 着 寄 存 器DS 指 向 的 是DLL 数 据 段,SS 指 向PowerBuilder 应 用 程
序 的 堆 栈。 而 一 般 的Windows 应 用 程 序 中,DS 和SS 是 相 同 的, 你 可 以 使 用 近 指 针, 但
在 调 用DLL 中 引 用 远 堆 的 变 量 必 须 使 用32 位 的 远 指 针。 如 果 使 用 任 何 与 内 存 寻
址 有 关 的C 函 数, 都 要 使 用C 中 的far 版 本。 例 如 字 符 串 拷 贝 函 数, 应 该 用_fstrcpy 而 不
要 用strcpy。
----3. 注 意 静 态 变 量 的 使 用
---- 无 论 有 多 少 实 例 调 用 同 一 个DLL, 在 内 存 中 只 有 一 份DLL 代 码。 由 于Windows 是
多 任 务 的 环 境, 因 此DLL 中 的 静 态 变 量 可 能 由 于 其 他 实 例 对 此DLL 的 调 用 而 改 变。
----4. 不 要 试 图 共 享 文 件 句 柄
---- 在Windows 环 境 下, 不 可 能 在 应 用 程 序 和DLL 间 共 享 文 件 句 柄。 每 个 应 用 有 各
自 的 文 件 句 柄 表, 如 果 两 个 应 用 通 过 一 个DLL 来 访 问 同 一 个 文 件, 它 们 必 须 分 别
打 开 这 个 文 件。
----5. 及 时 释 放 使 用 过 的 资 源
---- 如 果 你 的DLL 中 使 用 了GDI 对 象, 一 定 要 及 时 释 放 它 们, 否 则 会 使Windows 因 申 请
GDI 资 源 失 败 而 死 机; 例 如 你 建 立 了 一 个 逻 辑 字 体 或 逻 辑 笔, 在 使 用 完 后, 要 用
DeleteObject 来 删 除 它。
----6. 为 使PowerBuilder 应 用 在Windows 环 境 下 正 常 运 行,DLL 应 放 在 下 列 目 录 之 中:
当 前 目 录
目 录
Windows System 目 录
在DOS 的 路 径 中 包 括 的 目 录

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder 应 用 开 发 系 列 讲 座(3)
PowerBuilder面 向 对 象 的 程 序 设 计
华 天 新 技 术 开 发 公 司 张 健 姿
北 京 友 谊 宾 馆 30538 室 100873
Email: sjhzyz@public.bta.net.cn
---- 在PowerBuilder 的 应 用 开 发 中, 运 用 面 向 对 象 技 术 不 是 必 须 的, 但 是 对 于 一 个 大
型 复 杂 应 用 系 统 的 开 发, 如 果 采 用 了 面 向 对 象 技 术, 则 开 发 效 率 会 大 大 提 高。
---- 用PowerBuilder 开 发 的 好 处 是, 即 使 您 不 懂 得 什 么 是 面 向 对 象 技 术, 您 也 可 能 会
下 意 识 地 用 到 面 向 对 象 技 术 的 一 些 特 性, 但 是 如 果 您 对 这 一 技 术 有 了 充 分 的 了
解, 那 对 您 所 设 计 程 序 的 可 重 用 性, 可 维 护 性 和 其 他 各 方 面 的 质 量 都 会 有 大 幅 度
提 高。
----
PowerBuilder 的 对 象
----PowerBuilder 对 象 有 三 个 部 分 元 素: 属 性、 函 数 和 事 件。
----(1) 属 性: 也 就 是 数 据。 包 括 系 统 属 性 和 用 户 定 义 属 性 两 类, 描 述 该 对 象 的 各 种
特 性。 如 在 窗 口 对 象 中 的 系 统 属 性 包 括 标 题、 高 度、 宽 度 等, 用 户 定 义 的 属 性 可
以 是 实 例 变 量 或 共 享 变 量, 对 这 种 属 性 的 访 问 同 系 统 属 性 相 同, 只 是 在 封 装 性 上
有 所 不 同。
----(2) 事 件:PowerBuilder 中 的 事 件 与Windows 的 事 件 存 在 着 映 射 关 系。 当 用 户 的 操
作 或 系 统 本 身 产 生 了Windows 的 标 准 事 件, 就 转 化 成PowerBuilder 中 的 事 件。 例 如
命 令 按 钮 有 一 个 叫 Clicked 事 件, 当 用 户 按 按 钮 时 触 发, 操 作 系 统 首 先 检 测 到 鼠 标
被 点 击, 并 把Clicked 这 一 消 息 转 给 该 按 钮,PowerBuilder 运 行 时 的 工 作 引 擎 翻 译 了 这
一 事 件, 并 执 行 适 当 的PowerScript 语 句。PowerBuilder 中 大 部 分 的 事 件 都 是 可 以 映 射
成 由 用 户 激 发 的Windows 事 件。 另 一 类 事 件 是 用 户 定 义 事 件, 这 种 事 件 是 用 户 声
明 并 可 以 在 任 何 时 刻 由 用 户 触 发 的,Power-Builder 中 保 留 了75 个 用 户 事 件 可 由 程
序 员 使 用。
----(3) 函 数: 用 户 通 过 函 数 来 使 对 象 完 成 某 些 操 作。Pow-erSoft 公 司 建 议 用 户 通 过
调 用 对 象 事 件 和 函 数 来 修 改 对 象 而 不 要 直 接 修 改 对 象 属 性, 以 满 足 对 象 封 装 的
要 求, 例 如 采 用Window. hide() 而 不 要 用Window.visi-ble=false 来 使 窗 口 不 可 见。
----
PowerBuilder 面 向 对 象 的 特 性
---- 提 到 一 门 语 言 的 面 向 对 象 特 性, 它 应 当 具 有 继 承 性、 多 态 性 和 封 装 性, 如 缺 少
其 中 的 一 个 则 只 能 称 其 为 基 于 对 象 的 系 统, 而 不 是 面 向 对 象 的 系 统, 而
PowerBuilder 则 很 好 地 具 备 了 全 部 三 个 特 性。
---- · 继 承:
----PowerBuilder 中, 窗 口、 菜 单 和 用 户 对 象 是 可 以 继 承 的, 而 其 他 对 象 则 都 不 能。
当 您 继 承 了 一 个 对 象, 那 您 得 到 的 子 类 将 具 有 父 类 的 属 性、 实 例 变 量、 共 享 变
量、 控 件、 用 户 自 定 义 事 件、 对 象 级 函 数、 事 件 和 代 码(script)。 也 就 是 说 当 您 继
承 了 一 个 类, 您 几 乎 得 到 了 这 个 类 的 全 部, 不 过 有 一 点 值 得 注 意, 您 不 能 在 子 类 中
删 除 任 何 一 个 继 承 到 的 特 性。
---- 在 继 承 了 祖 先 类 后, 您 可 以 在 子 类 中 扩 展 或 覆 盖 祖 先 的 元 素。 例 如 代 码, 在
PowerBuilde r 中 缺 省 的 是 采 用 扩 展 方 式, 先 执 行 继 承 到 的 祖 先 代 码, 后 执 行 子 类 的
扩 展 代 码。 您 也 可 以 选 择 菜 单Compiler|Override Ancestor Script 选 项, 只 执 行 子 类 的
代 码, 并 可 在 代 码 中 的 任 意 位 置 调 动 祖 先 代 码 如CALL w_l ∷open。
---- 重 载 函 数 是 面 向 对 象 程 序 设 计 的 重 要 特 性, 即 同 一 函 数 名 却 有 着 不 同 的 参
数 和 返 回 值。 在 运 行 时, 系 统 自 动 寻 找 执 行 参 数 相 匹 配 的 那 个 函 数, 例 如 我 们 常
用 的MessageBox() 这 个 函 数 就 有12 个 不 同 参 数 的 重 载 函 数。 遗 憾 的 是, 对Power-
Builder 我 们 不 能 在 同 一 个 继 承 对 象 中 定 义2 个 不 同 参 数 的 重 载 函 数, 只 能 在 后 继
的 类 中 定 义 重 载 函 数, 这 使 我 们 对 重 载 函 数 的 定 义 带 来 了 很 大 的 不 便, 这 不 能 不
说 是PowerBuilder 的 缺 陷。( 不 过 在 即 将 发 布 的PowerBuilder5.0 中, 正 是 支 持 了 函 数 重
载 这 一 特 性。)
---- 对 于 对 象 的 继 承,PowerBuilder 中 所 有 对 象 都 有 其 共 同 的 基 类PowerObject, 从 这
一 个 基 类 下 面 分 成 继 承 类Graph-icObject 和NonVisualObject 等。 它 们 的 继 承 关 系 和 扩
展 函 数 及 属 性 如 下 表:
---- · 多 态 性:
---- 在PowerBuilder 中 有 大 量 的 多 态 函 数 如print()、TriggerEvent() 等, 在 运 行 过 程 中, 您
只 需 要 指 出 对 象 和 函 数 名 即 可。 在 有 些 函 数 中, 即 使 不 知 道 对 象 类, 也 可 以 用
Class Name() 函 数 得 到 对 象 类, 或 得 到 实 例 名, 将 对 象 名 作 为 函 数 参 数 调 用 该 函
数。
---- · 封 装 性:
---- 封 装 的 目 的 是 为 了 实 现 数 据 隐 藏 和 数 据 保 护, 封 装 的 目 标 是 为 对 象 提 供 一
个 对 外 操 作 的 接 口, 使 其 他 对 象 通 过 函 数 来 访 问, 而 不 允 许 直 接 操 纵 对 象 的 属
性。 在PowerBuilder 中 有 三 种 访 问 类 型Public、Protect、Private, 这 三 种 访 问 控 制 类 型
可 以 用 在 对 象 的 变 量 和 函 数 上, 缺 省 的 实 例 变 量 和 对 象 函 数 都 是public 类 型 的。
为 了 保 护 数 据, 应 尽 可 能 多 地 使 用private 和p rotect 类 型, 前 者 只 允 许 对 象 内 部 的 元
素 来 访 问, 后 者 可 以 接 受 对 象 内 部 和 继 承 类 的 元 素 访 问 。
----
PowerBuilder 面 向 对 象 程 序 设 计 的 过 程
---- 事 实 上 用 户 在 运 用Power-Builder 进 行 程 序 设 计 的 一 开 始, 就 已 经 开 始 进 行 对 象
类 的 设 计 : 例 如 在 建 立 窗 口 时 可 以 用 窗 口 画 笔(painter) 建 立 一 个 新 窗 口, 命 名 为
w_emp。 建 立 的 窗 口 就 是 从PowerBuilder 的 窗 口 对 象 继 承 下 来 的, 所 以 窗 口 会 自 动
具 备 一 些 属 性, 例 如X 和Y 的 坐 标、 高 度、 宽 度、 窗 口 类 型、 标 题 等。 当 用 窗 口 画 笔
建 立 窗 口 时, 您 给 这 些 属 性 赋 了 值, 你 还 可 以 增 加 窗 口 的 函 数 和 事 件。 当 窗 口 被
保 存 时, 你 就 建 立 了 一 个 新 的 窗 口 继 承 类, 称 为:w_emp。 输 出 对 象 的 句 法 显 示 的
部 分 程 序 如 下:
----global type w_emp from Window
----int X=200
----int Y=233
----int Width=2405
----int Height=1285
----boolean TitleBar=true
----string Title="Employee Mainte-nance"
----string MenuName="m_emp"
----long BackColor=12632256
----boolean ControlMenu=true
----boolean MinBox=true
----boolean MaxBox=true
----boolean Resizable=true
----.
----.
----.
----end type
----global w_emp w_emp
---- 请 注 意 系 统 在 这 里 做 了 什 么: 首 先 定 义 了w_emp 窗 口 类 是 从window 类 继 承 而
来, 接 着 定 义 这 一 对 象 类 的 各 属 性 值, 在 句 法 的 最 后 一 行 声 明 了 一 个 全 局 变 量, 变
量 的 类 型( 对 象 类) 是w_e mp, 变 量 名( 对 象 实 例) 也 是w_emp。 也 就 是 说 在 您 建 立 了
w_emp 这 一 窗 口 对 象 后, 系 统 就 具 有 了 w_emp 这 一 对 象 类 和w_emp 这 一 全 局 变
量。 这 个 变 量 是 引 用 变 量, 也 就 是 在 有 些 语 言 称 之 为 指 针 的 变 量 类 型。 引 用 变
量 并 不 真 正 含 有 窗 口 实 例 的 属 性, 而 是 包 含 了 一 个 位 置 或 是 内 存 中 的 一 个 地 址,
在 那 儿 你 可 以 找 到 实 例 的 实 际 属 性 和 程 序。 但 在 应 用 的 开 始 时 这 一 指 针 为 空,
因 为 在 内 存 中 并 没 有 一 个 这 样 的 窗 口 实 例。 当 系 统 执 行 了Open(w_emp) 后, 系 统
在 内 存 中 复 制 了 一 份w_emp 对 象 类 的 拷 贝 或 实 例,w_emp 这 一 参 照 变 量 指 向 了 这
一 地 址。 由 于 窗 口 对 象 的visibl e 等 属 性 都 是Public 类 型, 所 以 继 承 类 也 都 具 有 了 这
些 属 性。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder应用开发系列讲座(4)
并 发 控 制
华 天 新 技 术 开 发 公 司 张 健 姿
北 京 友 谊 宾 馆 30538 室 100873
Email: sjhzyz@public.bta.net.cn
---- 并 发 能 力 是 指 多 用 户 在 同 一 时 间 对 相 同 数 据 同 时 访 问 的 能 力。 一 般 的 关 系
型 数 据 库 都 具 有 并 发 控 制 的 能 力, 但 是 这 种 并 发 功 能 也 会 对 数 据 的 一 致 性 带 来
危 险。 试 想 若 有 两 个 用 户 都 试 图 访 问 某 个 银 行 用 户 的 记 录 并 同 时 要 求 修 改 该
用 户 的 存 款 余 额 时, 情 况 将 会 怎 样 呢? 我 们 可 以 对PowerBuilder 中 的DataWindow 进 行
设 置 来 进 行 并 发 控 制。 所 谓 并 发 控 制 就 是 指 在 用 户 数 据 修 改 的 过 程 中 保 证 该
数 据 不 被 覆 盖 或 改 变 的 方 式, 在 下 面 的 例 子 中 我 们 将 看 到 如 何 设 置Da taWindow
来 控 制 开 发 访 问。 为 了 说 明 问 题, 我 们 举 这 样 一 个 简 单 的 银 行 系 统 中 的 例 子, 某
用 户 的 存 款 状 况 如 右:
---- 我 们 假 设 事 情 的 经 过 是 这 样 的: 公 司 的 某 员 工 在 银 行 前 台 取 款2,000 元, 银 行
出 纳 查 询 用 户 的 存 款 信 息 显 示 银 行 存 款 余 额20,000 元; 正 在 这 时, 另 一 银 行 帐 户
转 帐 支 票 支 付 该 帐 户5,0 00 元, 机 器 查 询 也 得 到 当 前 用 户 存 款20,000 元, 这 时 银 行
的 出 纳 员 看 到 用 户 存 款 超 过 了 取 款 额 , 就 支 付 了 客 户2,000 元 并 将 用 户 存 款 改 为
18,000 元, 然 后 银 行 的 另 一 名 操 作 员 根 据 支 票, 将 汇 入 的5,000 元 加 上, 把 用 户 的 余
额 改 为25,000 元, 那 么 数 据 库 管 理 系 统 是 否 可 以 接 受 这 些 修 改 呢?
---- 在DataWindows 的 设 计 中, 我 们 选 择 菜 单Rows|Update …, 会 出 现Specify Update
Charac teristics 的 设 置 窗 口, 在 这 个 窗 口 中 我 们 设 置Update 语 句 中Where 子 句 的 生
成, 以 此 来 进 行 开 发 控 制。 在 这 里 有 三 个 选 项, 我 们 分 别 看 一 看 在 本 例 中 这 三 个
选 项 的 结 果:
----(1)Key Columns: 生 成 的Where 子 句 中 只 比 较 表 中 的 主 键 列 的 值 与 最 初 查 询 时 是
否 相 同 来 确 定 要 修 改 的 记 录。 在 上 述 的 例 子 中, 转 帐 支 票 的 操 作 将 覆 盖 出 纳 员
作 出 的 修 改, 这 样 银 行 损 失 两 千 元。
----(2)Key and Updateable Columns: 生 成 的Where 子 句 比 较 表 中 主 键 列 和 可 修 改 列 的
值 与 最 初 查 询 时 否 是 相 同。 在 上 例 中 两 次 查 询 出 的 结 果 都 是 有 两 万 余 额, 当 第
一 个 人 修 改 余 额 时 , 余 额 仍 是 二 万 元, 所 以 修 改 成 立, 而 支 票 转 帐 操 作 时 余 额 已
不 是 二 万, 所 以 该 列 不 匹 配, 修 改 失 败。
----(3)Key and Modified Columns:Where 子 句 比 较 主 键 和 将 要 修 改 的 列, 在 本 例 中, 结 果
与 Key and Updateable Columns 的 选 择 相 同, 因 为 余 额 已 改 变, 不 再 与 最 初 的 查 询 相
同, 因 此 仍 然 不 能 修 改。
---- 让 我 们 作 另 外 一 个 假 设, 我 们 把 银 行 后 台 作 支 票 转 帐 操 作 改 为 冻 结 用 户 存
款, 即 把 状 态 字 段 的 值 改 为 冻 结, 而 且 事 件 发 生 的 次 序 如 下 表, 那 么 表 中 的 次 序4
… 前 台 出 纳 的 修 改 能 不 能 成 立 呢:
----1.Key Columns:Where 子 句 只 比 较 主 键 值, 显 然 出 纳 员 的 修 改 是 允 许 的。
----2.Key and Updateable Columns: 生 成 的Where 子 句 包 括 比 较 所 有 可 修 改 的 列, 因 此
出 纳 修 改 时Statue 字 段 为 冻 结 与 出 纳 查 询 时 的tive 不 符, 修 改 失 败, 同 时 显 示 错 误
信 息。
----3.Key and Modified Columns:Where 子 句 的 比 较 包 括 主 键 和 要 修 改 的 列, 由 于 本 列
中 修 改 列 仍 为20,000 元 没 有 变 化, 所 以 出 纳 的 修 改 可 以 成 立。
---- 在 本 例 中, 我 们 可 以 看 到Key and Updateable Columns 的 选 项 最 严 格, 可 以 避 免 出
现 状 态 列 发 生 改 变 时 余 额 作 修 改 的 错 误, 但 是 这 也 会 禁 止 我 们 作 一 些 本 当 允 许
的 并 发 修 改, 如 出 纳 修 改 存 款 余 额, 而 业 务 员 修 改 用 户 的 联 系 地 址 等。 因 此 我 们
应 当 根 据 实 际 情 况, 选 择 适 当 的Upd ate 设 置。
---- 根 据 我 们 使 用 数 据 库 的 不 同, 我 们 还 有 一 些 其 他 的 控 制 并 发 访 问 和 修 改 的
选 择 方 案, 如 对 数 据 加 锁。 锁 是 一 个 用 户 避 免 其 他 用 户 对 指 定 行 作 修 改 的 操
作。 在 结 束 一 个 事 务 如 执 行com mit,rollback,disconnect 等 语 句 时 自 动 将 锁 释 放。 如
果 您 使 用 的DBMS 支 持 锁 的 操 作, 在Pow er-Builder 的DataWindow 设 计 时,Select 语 句 可 在
from 子 句 中 加 上with holdlock: 即 在data Window 的SQL Window 中, 在 表 窗 口 的 标 题 处
点 击 右 鼠 标, 弹 出 菜 单 的 最 后 一 个 选 项 即 为Hold lock。 选 择 该 项, 生 成 的SQL 语 句 将
在re-trievel() 函 数 执 行 后 将 所 查 询 的 数 据 加 锁, 以 避 免 其 他 用 户 的 修 改 访 问, 直 至
commit,rollback 等 事 件 发 生 后 解 锁。 这 种 方 式 带 来 的 问 题 是, 当 用 户 查 询 完 数 据 后
可 能 离 开 计 算 机 长 时 间 不 用, 这 段 时 间 内 其 他 用 户 均 无 法 修 改 数 据。 此 外 有 些
DBMS 如Sybase 等 不 支 持 行 级 锁, 也 就 是 说 当 你 对 某 一 行 查 询 时 更 多 的 行 都 被 上
了 锁, 这 就 更 增 加 了 并 发 处 理 的 局 限 性。 另 一 个 值 得 注 意 的 问 题 是 在 多 窗 口 应
用 中 某 一 个 窗 口 的 事 务 提 交 将 会 导 致 使 用 一 事 务 中 其 他 数 据 窗 口 的 查 询 行 解
锁, 这 时 修 改 将 可 能 发 生 错 误。 某 些DBMS 系 统 支 持 一 个 称 作" 时 间 戳(timestamp)" 的
数 据 项 来 控 制 并 发 性。 每 张 表 中 都 有 一 个 时 间 戳 的 数 据 列, 当Insert 语 句 或Update
语 句 对 数 据 行 作 修 改 时 该 列 自 动 被 修 改 为 当 前 时 间。 当 你 要 作 修 改 时,where 子
句 可 检 查 时 间 戳 列 在 查 询 时 和 修 改 时 两 个 值 是 否 相 符, 以 此 来 确 保 您 作 出 的 修
改 不 会 覆 盖 别 人 的 修 改, 因 此 这 种 确 认 方 式 与key and Updateable Columns 选 项 相
同 。 即 使 两 个 用 户 对 同 一 行 的 不 同 列 作 修 改, 后 一 个 修 改 者 也 将 失 败。 在 常 用
的 关 系 型 数 据 库 中Sybase 和Microsoft 的SQL Server 支 持 时 间 戳 的 使 用。 而 在
PowerBuilder 中, 不 管 用 户 后 台 连 接 何 种 数 据 库, 只 要 表 中 带 有timestamp 的 列 名 且
数 据 类 型 为datetime,PB 将 自 动 忽 略Upda te characteristics 的 选 项, 而 在where 子 句 中 生
成 主 键 和 时 间 戳 列 的 比 较。
---- 如 果 您 所 用 的 数 据 库 不 支 持 时 间 戳 但 支 持 触 发 器, 您 也 可 以 在 表 中 增 加 一
列 整 数 型 的 列 。 当 有 对 表 中 某 种 记 录 作 修 改 时, 该 列 自 动 加1。 下 列 使 用 的 是
Watcom 数 据 库, 对Shipper 表 增 加Updcnt 字 段 并 作 两 个 触 发 器, 这 样 任 何 用 户 或 进 程
试 图 修 改 某 行 记 录 时, 该 字 段 均 可 发 生 变 化。
---- 对INSERT 触 发 器 的 编 写 如 下:
----DROP TRIGGER INS —SHIPPER’
----CREATE TRIGGER SHIPPER BEFORE INSERT ON SHIPPER
----REFERENCING NEW AS Newvalue
----FOR EACH ROW
---- BEGIN
---- SET newvalue.UpdCnt=newvalue.UpdCnt+1;
---- END'
---- 同 理 可 编 写UPDATE 触 发 器。
---- 在 您 的PowerBuilder 应 用 之 中, 除 表 的 主 键 外, 必 须 再 加 上 这 一 列 作 为 检 测 列 加
入Updat e 语 句 中 的Where 子 句 中, 这 样 再 作Update 操 作 时, 后 台 数 据 库 会 比 较 修 改
时 与 用 户 作Retriev e 操 作 时 数 据 是 否 相 等, 以 确 认 是 否 能 作 修 改。 在DataWindows
中 在Specify Update Charact eris-tics 的 对 话 框 的 右 下 角 的Unique key column(s) 中 加 上
Updcnt 一 项, 同 时 注 意where c lause 中 选 择Key columns, 这 样PowerBuilder 在 构 造where
子 句 时 就 会 认 为Updcnt 亦 是 表 的 主 键, 而 成 为 检 测 项。
---- 当 数 据 窗 口 的Update 函 数 被 调 用 后, 触 发 器 将 修 改 过 记 录 中 的Updcnt 列 表 为 新
值, 为 保 证 下 一 次 修 改 能 够 有 效, 您 应 当 立 即 作Retrieve() 以 使DataWindow 缓 冲 区 中
Updcnt 的 值 与 数 据 库 相 同。 显 然 修 改 后 立 即 查 询 的 代 价 要 比 其 他 任 何 一 种 并
---- 发 控 制 的 代 价 要 小 得 多。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder 应 用 开 发 系 列 讲 座(5)
DataWindow 的 打 印 输 出
华 天 新 技 术 开 发 公 司 张 健 姿
北 京 友 谊 宾 馆 30538 室 100873
Email: sjhzyz@public.bta.net.cn
---- 在PowerBuilder 应 用 程 序 的 开 发 中, 各 种 报 表 的 打 印 功 能 是 必 不 可 少 的。Power-
Builde r4.0 提 供 了 大 量 与 打 印 机 进 行 通 信 的 内 部 函 数, 用 于 各 种 打 印 输 出。 运 用
这 些 函 数, 您 不 仅 可 以 打 印 常 见 的DataWindow 对 象, 还 可 以 打 印 字 符 串、 位 图、 图
形 对 象, 甚 至 是 全 屏。
----DataWindow 的 两 种 打 印 方 法:
---- 在PowerBuilder 中 我 们 可 以 有 两 种 方 法 打 印DataW-indows。 一 种 最 简 单 的 方 法
就 是 直 接 地 将DataWindow 提 交 给 打 印 机, 另 一 种 方 法 是 将 大 量 的DataWindow( 或 混
合 其 他 的 对 象) 放 在 一 起 作 为 一 个 单 一 的 打 印 作 业 提 交 输 出。
---- 法 一: 不 指 定 打 印 作 业, 而 发 送 一 个 单 一 的DataW-indow。 将 报 表 传 给 打 印 机 输
出 的 最 简 单 的 方 式 是 使 用DataWindow 对 象 的Print() 函 数, 您 只 需 简 单 指 明 您 打 印 的
DataWindow 控 件 的 名 字 就 可 以 得 到 该DataWindow 生 成 的 报 表 了。 例:
----dw_data.print({cancel dialog})
----Print() 函 数 不 需 要 任 何 参 数, 但 是 它 有 一 个 可 选 参 数, 可 以 控 制PowerBuilder 是 否
显 示 Print Cancel 对 话 框 窗 口( 缺 省 为 自 动 出 现, 如 图1 所 示)。Cancel dialog 参 数 是 一
个 布 尔 型 变 量, 其 缺 省 值 为 真。
---- 一 Print:HP LaserJet HP on LPT1:
----Preparing page 1 of 2
---- Cancel
---- 图1: 除 非 特 别 指 定, 否 则 将 在 打 印 时 缺 省 出 现Print Cancel 对 话 框。Print() 函 数 还
有 一 些 格 式 可 控 制 打 印 正 文 字 符 串, 但 是 它 们 要 求 首 先 打 开 一 个 打 印 作 业。 这
些 格 式 将 在 后 面 解 释。
---- 法 二: 集 成 多 个DataWindow 作 为 一 个 打 印 作 业。 您 可 以 将 提 交 打 印 的 多 个
DataWindow 作 为 一 个 单 一 的 打 印 指 令。 为 实 现 这 一 功 能 必 须 打 开 一 个 所 谓 打
印 作 业(Print job), 即 发 送 给 打 印 机 一 个 单 一 工 作 单 元, 其 中 可 以 包 含 多 个 子 任
务。 在PowerBuilder 中 一 个 打 印 作 业 由 它 的 作 业 代 号 唯 一 指 定。 我 们 使 用PrintOpen
({job name}) 函 数 打 开 一 个 作 业, 并 得 到 打 印 作 业 号。PrintOpen() 函 数 有 一 个 可 选
参 数, 就 是 打 印 作 业 名 称, 这 个 作 业 名 字 将 作 为Windows 3. x 的Print Manager 作 业 集
中 的 名 字。 当 您 使 用PrintOpen() 函 数 时, 系 统 将 另 起 一 页 开 始 打 印 。 当 然 在 打 印
作 业 中, 您 还 可 以 使 用 其 他 函 数 换 页, 比 如 将 在 后 面 讲 述 的PrintPage() 函 数。
---- 在 您 打 开 了 一 个 作 业 号 后, 就 可 以 在 这 个 作 业 内 使 用 下 列 函 数 继 续 其 他 各
种 各 样 的 打 印 项 目。
----1) 在 打 印 作 业 中 加 入 字 符 串:
---- 我 们 也 可 以 使 用 另 外 一 个 与Print() 函 数 略 微 不 同 的 函 数 来 打 印 字 符 串:
----PrintText(print_job_number,string,x,y{,font_number})
---- 这 个 函 数 将 包 含 在string 参 数 中 的 正 文 字 符 串 当 作 一 个 对 象 进 行 打 印。 这 个
打 印 的 字 符 串 在 由X,Y 参 数( 以 千 分 之 一 寸 为 单 位) 指 定 的 坐 标 处 开 始。font_number
参 数 是 一 个 可 选 参 数 , 缺 省 使 用 当 前 字 型, 否 则font_number 的 值 可 以 从0 到8,0 是 打
印 机 缺 省 的 字 型,1-8 是 使 用 后 面 讲 述 的PrintDefineFont() 函 数 定 义 的 字 型。 这 个 函
数 不 像 其 他 指 定 坐 标 的 函 数, 它 将 改 变 打 印 光 标 的 位 置。 这 个 函 数 的 返 回 值 是
打 印 光 标 的 新X 坐 标, 但 它 不 改 变Y 坐 标。
在 打 印 作 业 中 打 印 对 象
---- 下 面 的 这 些 函 数 可 以 使 您 在 打 开 的 打 印 作 业 中 打 印 不 同 的 对 象。 这 些 函 数
中 的 任 一 个 指 定X、Y 坐 标 的 函 数 都 不 会 改 变 当 前 打 印 光 标 位 置。
----objectname.Print(print_job_number,x,y {,width,height})
---- 这 个 函 数 可 以 将 任 何 一 个object_name 指 定 的 对 象 放 在print_job_number 定 义 的
打 印 作 业 中 打 印, 这 个 对 象 可 以 是 一 个 窗 口 也 可 以 是 一 个DragObject 类 的 继 承 类(
包 括 了 所 有 的 窗 口 控 件)。X、Y 参 数 指 定 了 一 页 中 的 坐 标, 您 可 以 指 出 所 打 印 对
象 出 现 的 位 置( 以 千 分 之 一 寸 为 单 位)。Width 和Height 参 数 是 可 选 的 参 数, 用 来 指 明
你 所 需 的 打 印 对 象 的 宽 和 高( 仍 以 千 分 之 一 寸 为 单 位)。 如 果 缺 省,PowerBuilder 将
使 用 对 象 本 身 的 尺 寸 打 印。
----PrintBitmap(print_job_number,bitmap,x,y,width,height)
---- 这 个 函 数 将 在 由X,Y 参 数( 千 分 之 一 寸 为 单 位) 指 定 的 打 印 区 域 上 打 印 一 个 位
图。bitmap 参 数 是 一 个 包 含 要 打 印 位 图 的 文 件 名 的 字 符 串( 例:BRUSH.BMP)。Width 和
Height 参 数 指 定 位 图 显 示 的 宽 和 高, 这 个 参 数 并 不 是 可 选 的。 输 入0 值, 意 味 着 位
图 按 它 本 身 的 值 打 印。
----PrintDataWindow(print_job_number,datawindowcontrol)
---- 这 个 函 数 将 一 个DataWindow 控 件 的 内 容 作 为 这 个 指 定 的 打 印 作 业 的 一 部 分
来 打 印。 由 于 Power-Builder 使 用 在DataWindow 对 象 中 定 义 的 字 型,Print-DefineFont() 和
PrintSet-Font () 函 数 不 对 其 产 生 影 响。Powersoft 建 议 如 用PrintDataWindow, 那 么 在 这
个 打 印 作 业 中 就 不 需 要 使 用 其 它 函 数。 因 为 这 个 函 数 将 使 用 整 张 纸, 每 一 次 调
用PrintDataWidnow, 您 打 印 的 下 一 项 都 将 另 起 一 页。
----PrintLine(Print_job_number,X1,Y1,X2,Y2,thickness)
---- 这 个 函 数 将 打 印 一 指 定 宽 度 的 线。 这 条 线 将 在 由X1,Y1 参 数( 以 千 分 之 一 寸 为
单 位) 指 定 的 坐 标 处 开 始, 在 由X2,Y2 参 数( 也 以 千 分 之 一 寸 为 单 位) 指 定 的 坐 标 处
结 束。thickness 参 数 是 一 个 整 型 变 量, 它 指 定 了 这 条 线 的 宽 度, 以 千 分 之 一 寸 为 单
位。
----PrintOval(print_job_number,x,y,width,height,thickness)
---- 这 个 函 数 打 印 一 个 椭 圆( 如 果 宽 度 和 高 度 相 同 则 形 成 一 个 圆) 它 的 轮 廓 线 的
宽 度 由thick ness 指 定。 椭 圆 都 由 一 个 想 象 的 边 框 包 围,X,Y 参 数 指 定 了 这 个 界 框 的
左 上 角 的 位 置( 千 分 之 一 寸 为 单 位),width,heigh 为 这 个 边 框 的 高 和 宽。
----PrintRect(print_job_number,x,y,width,height,thickness)
---- 除 了 它 是 打 印 一 个 矩 形 外, 这 个 函 数 与PrintOval() 函 数 完 全 一 样。
----PrintRoundRect(print_job_number,x,y,width,height,thickness)
---- 除 了 它 是 打 印 一 个 圆 角 矩 形 外, 这 个 函 数 与PrintO-val() 函 数 完 全 一 样。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder应用开发系列讲座(6)
DataWindow的打印输出续)
华天新技术开发公司 张健姿
北京友谊宾馆30538室 100873
Email: sjhzyz@public.bta.net.cn
----PowerBuilder 提 供 了 一 组 打 印 控 制 函 数 来 控 制 要 交 给 打 印 机 打 印 的 对 象。 第
一 个 函 数P rintOpen() 在 这 章 的 前 面 我 们 已 介 绍 过 了, 其 它 还 有:
----PrintCancel(print_job_number)
---- 这 个 函 数 将 中 止 打 印 作 业 号 所 打 印 的 作 业, 不 发 送 任 何 内 容 给 打 印 机。
----datawindowcontrol.PrintCancel()
---- 这 个 函 数 与 上 一 函 数 的 区 别 是: 这 个 函 数 取 消 的 是 用Datawindowcontrol.Print()
提 交 的 作 业。
----PrintClose(print_job_number)
---- 这 个 函 数 将 关 闭 指 定 的 打 印 作 业 并 且 把 它 发 给 打 印 机( 或 者 假 脱 机 程 序)。
为 了 避 免 挂 起 打 印 作 业, 所 有 打 开 的 打 印 作 业 都 应 在 应 用 的 结 束 前 被 关 闭 或 取
消。
----PrintDefineFont(print_job_number,fontnumber,facename,height,weight,font-pit
ch,fontfamily,italic,underline)
---- 你 可 以 用 这 个 函 数 定 义 字 型。Power-Builder 允 许 在 一 个 打 印 作 业 中 使 用 八 种
字 型, 用 这 个 函 数 可 定 义 其 中 的 任 一 个。 这 个 字 型 所 属 的 打 印 作 业 号 由
Print_job_number 参 数 指 定,fo nt_number 参 数 是 这 个 打 印 作 业 所 采 用 的 字 型 号(1-
8)。 其 余 的 参 数 描 述 了 字 型 如 何 显 示, 是 否 斜 体 字、 粗 体 和 下 划 线 等。facename
参 数 是 一 个 包 含 了 你 所 定 义 的 字 体 名 字 的 字 符 串( 例 :courier 100CPI)。height 参 数
是 你 所 需 的 以 千 分 之 一 寸 为 单 位 的 字 体 的 高 度( 例:250 将 是 一 个18 点 阵courier 10
CPI 字 体),height 参 数 也 可 使 用 一 负 值 来 表 示 点 阵 数 指 定 点 尺 寸( 例 :-18 是18 点 阵)。
weight 参 数 值 是 您 所 要 的 字 型 的 笔 画 权 值( 例:400 是 平 常 正 文,700 是 粗 体) 。
fontpitch 参 数 是 一 个 枚 举 数 据 类 型, 它 指 定 了 字 体 的 间 距(Default!,Fixed! 或
variable! );fontfamily 参 数 也 是 一 个 枚 举 类 型, 指 定 了 字 体 系 列
(AnyFont!,Decorative!,Mod-ern!,R oman!,Script!,Swiss!)。 这 两 种 参 数 只 在 基 于Windows
的 操 作 系 统 中 使 用, 在Macintosh 等 机 器 中 不 能 使 用。italic 参 数 是 一 个 布 尔 型 变 量,
指 定 字 体 是 斜 体(True) 或 非 斜 体(False),un derline 参 数 也 是 一 个 布 尔 值, 用 法 同 上。
----PrintOpen()
---- 这 个 函 数 已 在 这 章 的 开 始 讲 述 过 了, 它 定 义 一 个 打 印 作 业 以 便 将 所 有 的 打
印 项 成 组 发 送 给 打 印 机。 它 的 返 回 值 是 唯 一 的 打 印 作 业ID, 如 果 返 回 值 为 负, 则
意 味 着 产 生 错 误。
----PrintPage(print_job_number)
---- 这 个 函 数 将 指 定 的 打 印 作 业 的 当 前 页 传 送 给 打 印 机( 或 假 脱 机 程 序), 并 另 起
一 页 用 于 之 后 的 打 印 集。
----PrintSend(print_job_number,string{,zero_character})
---- 这 个 函 数 在 打 印 作 业 中 发 送 一 个 特 定 的 字 符 串 给 打 印 机。 这 个 字 符 串 一 般
是 一 个 包 含 转 义 字 符 的 命 令 串 用 来 启 动 或 操 作 打 印 机。 这 些 打 印 机 的 控 制 代
码 因 打 印 机 的 不 同 而 不 同, 您 应 查 询 您 的 打 印 机 手 册 来 得 到 正 确 的 代 码。
---- 这 个 与 打 印 机 进 行 通 信 的 字 符 串 应 是 一 个ASCII 码 集, 并 以ASCII 码0 来 结 束。 如
果 你 需 要 发 送ASCII 码0, 你 可 以 用 另 外 的 一 个 字 符 来 替 代0, 给 定 的 这 个 替 代 字 符
的ASCII 值 由 可 选 参 数 zero-character 来 指 定。 这 个 函 数 一 般 用 于 改 变 纸 的 定 向
(Landscape 或por-trait) 或 者 改 变 打 印 用 的 纸 盘 等。
----PrintSetFont(print_job_number,fontnumber)
---- 这 个 函 数 设 置 当 前 打 印 机 字 体, 它 是 你 使 用PrintDefineFont() 函 数 中 定 义 的 八 个
字 体 中 的 一 个。
----PrintSetSpacing(print_job_number,spacing)
---- 这 个 函 数 使 用Spacing 参 数 来 决 定 正 文 行 之 间 的 行 距。 这 个 值 乘 以 当 前 字 体
高 得 到 行 距 , 缺 省 值 是1.2。
----PrintSetup()
---- 这 个 函 数 调 用Windows 的Print Setup 对 话 框, 实 际 显 示 的Setup 窗 口 依 赖 于 你 所 安
装 的 打 印 机 驱 动 程 序。
----PrintWidth(print_job_number,string)
---- 这 个 函 数 的sting 参 数 返 回 字 符 串 的 宽 度( 以 千 分 之 一 寸 为 单 位)。 返 回 值 的 大
小 是 依 赖 于 当 前 选 择 的 字 体。
----PrintX(print_job_number)
---- 这 个 函 数 返 回 当 前 打 印 光 标 的X 坐 标( 水 平) 值。
----PrintY(print_job_number)
---- 这 个 函 数 返 回 当 前 打 印 光 标 的Y 坐 标( 垂 直) 值。
---- 除 非 特 别 说 明, 上 述 函 数 的 返 回 值1 意 味 着 成 功,-1 意 味 着 失 败。
DataWindow 控 件 的 打 印 属 性
---- 使 用modify 函 数, 我 们 可 以 改 变DataWindow 的 打 印 属 性。 在 打 印DataW-indow 之
前, 我 们 可 以 调 用 如 图 所 示 的 窗 口, 从 而 得 到 我 们 想 让 用 户 设 置 的 参 数。 这 个 窗
口 在PowerBuilder E nterprise 的 实 例 库 中, 您 也 可 以 在 直 接 调 用 它 前 对 其 显 示 界 面
进 行 汉 化 和 作 适 当 修 改。
---- 例 如, 我 们 使 用 下 面 语 句 来 改 变 我 们 想 打 印 的 份 数。
----dw_data..Modify("DataWindow.Print.Copies=3")
---- 你 可 以 使 用PowerBuilder Enterprise 打 包 软 件DWSYN40.EXE----DataWindow 语 法 生 成
器 来 建 立Modify 语 句。
---- 下 面 所 列 的 可 以 修 改 的 参 数 全 部 以DataWindow.print 为 前 缀, 后 接 这 个 属 性。
----Collate=Yes or No( 缺 省 为no, 不 作 校 对)
---- 这 个 属 性 用 来 指 示 是 否 要 对 打 印 进 行 校 对。 校 对 通 常 较 慢, 因 为 整 个 打 印 过
程 必 须 反 复 几 次 以 得 到 一 个 校 对 后 的 结 果。
----Color=1( 彩 色)or 2( 单 色)
---- 这 个 属 性 指 示 传 送 给 打 印 输 出 的 是 彩 色( 如 果 你 有 一 台 彩 色 打 印 机) 还 是 单
色。
----Columns= <an integer >( 缺 省 为1)
---- 这 个 属 性 用 来 指 示DataWindow 以 报 纸 风 格 打 印 在 一 页 上 的 栏 的 数 量。
----Columns.Width= <an integer >
---- 这 个 属 性 指 示 以 报 纸 风 格 打 印 的 栏 的 宽 度( 基 于 为DataWindow 指 定 的 单 位)。
----Copies= <an integer >
---- 这 个 属 性 指 示 你 所 需 的 打 印 的 数 量。
----DocumentName= <a string >
---- 这 个 属 性 可 以 让 你 为 文 件 设 置 一 个 名 字。 这 个 名 字 在DataWindow 传 送 给 打
印 机 时 在 打 印 序 列 中 出 现。
----Duplex=1( 单 一)or 2( 水 平)or 3( 垂 直)
---- 这 个 属 性 指 示 打 印 输 出 的 方 向。
----Filename= <filename string >
---- 这 个 属 性 仅 当 把DataWindow 输 出 为 一 个 文 件 时 才 有 用。 这 个 属 性 包 含 的 字
符 串 是 将 在 磁 盘 中 存 储 的 文 件 的 名 字。
----Margin.Bottom= <an integer >
---- 这 个 属 性 为 一 整 型 指 示 页 面 下 部 空 白 的 宽 度( 用DataWindow 指 定 的 单 位)
----Margin.Left= <an integer >
---- 功 能 与Margin.Botton 相 同, 但 指 示 的 是 左 侧 空 白 宽 度。
----Margin.Right= <an integer >
---- 功 能 与Mangin.Bottom 相 同, 但 指 示 的 是 右 侧 空 白 宽 度。
----Margin.Top= <an integer >
---- 功 能 与Mangin.Bottom 相 同, 但 指 示 的 是 顶 端 空 白 宽 度。
----Orientation=0( 打 印 机 的 缺 省 设 置) 或2( 横 向 打 印) 或3( 纵 向 打 印) 这 个 属 性 用 来 指
示 打 印 定 向。 你 可 以 使 用 打 印 机 缺 省 设 置, 或 者 设 置 成Landscape 或Portrait 模 式, 覆
盖 缺 省 的 打 印 设 置。
----Page.Range= <page range string >
---- 这 个 属 性 为 一 字 符 串 指 明 你 要 打 印 的 页 数。 在 字 符 串 中 的 数 字 用 逗 号 分 隔,
或 者 数 字 之 间 用 由 一 横 线 分 隔 表 示 一 范 围 或 两 者 同 时 使 用, 例 如:"1,2,3,6-12", 空
字 符 串 表 示 要 打 印 所 有 的 页。
----Page.RangeInclude=0( 全 部 打 印) 或1( 打 印 奇 数 页) 或2( 打 印 偶 数 页)
---- 这 个 属 性 用 来 指 示 在Page.Range 指 示 的 范 围 中 哪 些 页 要 打 印。 你 可 以 先 选 择
打 印 偶 数 页 , 然 后 将 纸 放 入 打 印 机 中, 再 选 择 奇 数 页 打 印。 这 一 功 能 像 在 打 印 书
时 那 样, 需 在 纸 的 两 面 打 印 时 非 常 有 用。
----Paper.Size= <an integer >
---- 这 一 属 性 用 来 指 示 打 印 纸 的 尺 寸。 可 接 受 的 值 如 下:
----0- 缺 省
----1-Letter 8 1/2 x 11 in
----2-LetterSmall 8 1/2 x 11 in
----3-Tabloid 17 x 11 inches
----4-Ledger 17 x 11 in
----5-Legal 8 1/2 x 14 in
----6-Statement 5 1/2 x 8 1/2 in
----7-Executive 7 1/4 x 10 1/2 in
----8-A3 297 x 420 mm
----9-A4 210 x 297 mm
----10-A4 Small 210 x 297 mm
----11-A5 148 x 210 mm
----12-B4 250 x 354
----13-B5 182 x 257 mm
----14-Folio 8 1/2 x 13 in
----15-Quarto 215 x 275 mm
----16-10 x 14 in
----17-11 x 17 in
----18-Note 8 1/2 x 11 in
----19-Envelope #9 3 7/8 x 8 7/8
----20-Envelope #10 4 1/8 x 9 1/2
----21-Envelope #11 4 1/2 x 10 3/8
----22-Envelope #12 4 x 11 1/276
----23-Envelope #14 5 x 11 1/2
----24-C size sheet
----25-D size sheet
----26-E size sheet
----27-Envelope DL 110 x 220 mm
----28-Envelope C5 162 x 229 mm
----29-Envelope C3 324 x 458 mm
----30-Envelope C4 229 x 324 mm
----31-Envelope C6 114 x 162 mm
----32-Envelope C65 114 x 229 mm
----33-Envelope B4 250 x 353 mm
----34-Envelope B5 176 x 250 mm
----35-Envelope B6 176 x 125 mm
----36-Envelope 110 x 230 mm
----37-Envelope Monarch 3.875 x 7.5 in
----38-6 3/4 Envelope 3 5/8 x 6 1/2 in
----39-US Std Fanfold 14 7/8 x 11 in
----40-German Std Fanfold 8 1/2 x 12 in
----41-German Legal Fanfold 8 1/2 x 13 in
----Paper.Source= <an integer >
---- 这 一 属 性 是 一 个 整 型 值, 指 明 纸 的 来 源。 可 接 受 的 值 如 下:
----0-Default
----1-Upper
----2-Lower
----3-Middle
----4-Manual
----5-Envelope
----6-Envelope manual
----7-Auto
----8-Tractor
----9-Smallfmt
----10-Largefmt
----11-Large capacity
----14-Cassette
----Preview=Yes( 进 入 打 印 预 览 状 态) 或No( 缺 省- 退 出 打 印 预 览 状 态)
---- 这 个 属 性 允 许 您 的DataWindow 进 入 和 退 出 打 印 预 览 状 态。 这 种 状 态 可 以 所
见 即 所 得 地 看 到 用 户 即 将 打 印 的 结 果。
----Preview.Rulers=Yes( 显 示 标 尺) 或No( 缺 省- 不 显 示 标 尺)
---- 这 个 属 性 是 指Print Preview 状 态 下, 是 否 要 在DataWindow 对 象 上 显 示 标 尺。
----Preview.Zoom= <an integer >
---- 这 个 属 性 是Print Preview 状 态 下, 为 预 览 的DataWindow 指 定 一 个 放 缩 因 子。 缺 省
值 为1 00%(Preview.zoom=100%)
----Prompt=Yes( 缺 省- 显 示 提 示) 或No( 无 提 示)
---- 这 个 属 性 可 以 控 制PowerBuilder 显 示 一 个 允 许 用 户 在 作 业 打 印 前 取 消 打 印 作
业 的 提 示。
----Quality=0( 缺 省)or 1( 高)or 2( 适 中)or 3( 低)or 4( 草 稿)
---- 这 个 属 性 可 以 选 择 打 印 输 出 的 质 量。
----Scale= <an integer >
---- 这 个 属 性 指 定 打 印 输 出 放 大 或 缩 小 的 比 例。
制 作 一 个 屏 幕 打 印: 如 何 打 印 全 屏
----PowerBuilder 4.0 的 一 个 新 特 征 是 可 以 把 屏 幕 图 像 提 交 打 印 作 业, 在 纸 上 的 任
一 点 打 印 屏 幕。 我 们 使 用PrintScreen() 函 数 实 现 这 一 功 能。
----PrintScreen() 的 语 法 如 下:
----PrintScreen(print_job_number,x,y{,width,height})
---- 执 行 这 一 函 数, 在 指 定 的 打 印 作 业 中 将 当 前 屏 在 由X,Y 参 数( 千 分 之 一 寸 为 单
位) 指 定 的 坐 标 处 打 印。width 和height 参 数 指 示 你 所 要 的 打 印 屏 幕 的 宽 和 高。 最
后 这 两 个 参 数 是 可 选 的 , 如 果 缺 省, 屏 幕 将 按 初 始 的 宽 度 和 高 度 打 印。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PowerBuilder 应 用 开 发 系 列 讲 座(7)
利 用SetActionCode 函 数 控 制 DataWindow
华 天 新 技 术 开 发 公 司 张 健 姿
北 京 友 谊 宾 馆 30538 室 100873
Email: sjhzyz@public.bta.net.cn
----DataWindow 控 件 的 一 些 事 件 有 一 个 动 作 码 操 纵 这 个 事 件 之 后 的 缺 省 动 作。 在
Pow-erBui lder 4.0 中 我 们 可 以 使 用SetAction-Code 函 数, 来 设 置 这 个 动 作 码 的 值 以 控
制 在 这 些 事 件 发 生 后 的 处 理 过 程。( 在PowerBuilder 5.0 中, 由 于 事 件 可 以 有 返 回 数
值, 所 以 采 用 返 回 一 个 整 型 数 值 来 取 代SetActionCode 函 数, 比 如 使 用return 1 取 代
SetActionCode(1), 但 基 本 的 使 用 规 则 两 者 是 相 同 的。)DataWindow 控 件 中 下 列 事 件
使 用 动 作 码:
----CLICKED
----DBERROR
----ITEMCHANGED
----ITEMERROR
----PRINTPAGE
----RETRIEVEROW
----RETRIEVESTART
----UPDATESTART
---- 有 效 的 动 作 码 值 和 应 当 的 处 理 过 程 随 事 件 的 不 同 而 不 同。
Clicked Event
---- 无 论 何 时, 当 用 户 在DataWindow 控 件 上 点 击 时,CLICKED 事 件 被 触 发。 如 果 点 击
在 一 个 有 效 的 行 上, 那 么DataWindow 将 自 动 把 此 行 作 为 当 前 行。 如 果 你 不 想 换 行,
就 可 以 使 用SetActi onCode 来 停 止。
----0 进 行 换 行 和CLICKED 事 件。( 缺 省)
----1 停 止 处 理CLICKED 事 件。
---- 例 如: 下 面 一 段 代 码 只 允 许 用 户 点 击 在 自 己 的 用 户 号 上。
----//Clicked Event
----//We'll assume there is an instance variable with the current user's
----//User ID:string is_user_id
----long ll_row
----string ls_user_id
----ll_row =GetClickedRow()
----//No need to continue if the user didn't click on a valid row
----if ll_row <1 then
----return
----end if
----ls_user_id=GetItemString(11_row,"user_id")
----//If the user_id is not the current user then disallow row change
----if ls-user-id < >is-user-id then
----beep(1)
----SetActionCode(1)
----return
----end if
ItemChanged Event
----DataWindow ITEMCHANGED 事 件 可 以 有 几 种 不 同 的 操 作: 接 受 前 一 字 段 的 新 值,
因 有 错 误 而 拒 绝 接 受 新 值, 拒 绝 新 值 但 是 继 续 其 它 的 处 理 过 程。 这 些 值 如 下:
----0 接 受 新 的 数 据 值。( 缺 省)
----1 拒 绝 新 的 数 据 值。( 启 动ItemEr-ror 事 件)
----2 拒 绝 新 的 数 据 值 但 是 焦 点 改 变。
---- 在ITEMCHANGED 事 件 中 使 用SetAction-Code 函 数 可 以 进 行 多 字 段 的 交 叉 确 认。 例
如, 银 行 系 统 中 为 确 认Account Status 是 否 可 以 转 为Inactive, 就 需 检 验Balance 字 段 是
否 为 零:
----//ItemChanged Event
----Decimal (2) ld_balance //Customer Account Balance
----Long ll_currow // Current Row Number
----String ls_column_name //The name of the column that changed
----String ls_status //Customer Account Status
----ll_currow=this.GetRow()
----ls_column_name=this.GetColumnName()
----CHOOSE CASE ls_column_name
----...
----...
----CASE "STATUS"
----ls_status=this.GetText()
----//If STATUS is Inactive
----IF ls_status= "I" THEN
---- ld_balance=this.GetItemDecimal (ll_currow,"BALANCE")
----IF ld_balance < >0 THEN
----//SET AN ERROR
----this.SetActionCode(1)
----RETURN
----ELSE
----//ACCERT THE VALUE
----this.SetActionCode(0) /* not required since 0 is default */
----RETURN
----END IF
----END IF
----END CHOOSE
---- 在 程 序 中,SetActionCode 函 数 不 一 定 要 在 最 后 一 行, 但 是 由 于 其 他DataWindow 函
数 可 能 会 重 置 动 作 码。 为 了 避 免 这 个 问 题, 一 般 在SetActionCode 后 面 立 即 执 行Re-
turn 结 束 这 个 程 序 段。
---- 在ITEMCHANGED 事 件 中 使 用SetAc-tionCode 函 数 用 途 是 可 以 给 该 字 段 一 个 新 值,
而 不 是 用 户 输 入 的 那 样。 例 如: 用 户 将 日 期 输 入 为 星 期 日, 但 是 我 们 希 望 将 其 改
为 在 此 之 后 的 第 一 个 非 休 息 日。 实 现 这 一 功 能 并 不 像 想 象 的 那 样 简 单:
----//ItemChanged Event
----date ldt_process //process date
----long ll_currow // Current Row Number
----string ls_column_name // The name of the column that changed
----ll_currow=this.GetRow()
----ls_column_name=this.GetColumnName()
----CHOOSE CASE ls_column_name
----...
----...
----CASE "process_date"
----ldt_process=f_get_next_bus_date(date(this.GetText()))
---- 错 误 this.SetText(ldt_process)
----this.AcceptText()
----...
---- 执 行 上 述 代 码, 系 统 将 进 入 死 循 环。 因 为 用AcceptText 函 数 改 变 日 期 的 同 时, 也
触 发ITE MCHANGED 事 件, 只 是 当 前 列 仍 在process-data 列 上, 这 样 就 导 致 堆 栈 溢 出。
因 此 在ITEMCHANG ED 事 件 中 不 能 使 用Ac-ceptText 函 数, 应 使 用 我 们 这 里 介 绍 的Se-
tActionCode 这 一 函 数 来 完 成 这 一 功 能:
----CASE "process_date"
---- ldt_process=f_get_next_bus_date(date(this.GetText()))
---- 正 确 this.SetItemText(ll_currow,"process_date",ldt_process)//set value i n buffer
---- this.SetActionCode(2) // reject edit control value
----RETURN
---- 在Primary!Buffer 中 将process_date 的 值 置 为ldt_process,SetActionCode(2) 摒 弃 用 户 在
edit 控 件 中 输 入 的 值( 星 期 日), 并 允 许 改 变 焦 点( 没 有 错 误 发 生)。
ItemError Event
---- 在 任 何 时 候, 当 一 个DateWindow 列 没 有 通 过 有 效 性 检 验 或 者 这 个 值 在ITEM-
CHANGED 事 件 中 被 拒 绝 时,ITEMER-ROR 事 件 启 动。 如 同ITEMCHANGED 事 件 一 样, 它 的
动 作 码 也 可 以 设 置 为 接 受 或 拒 绝 这 个 字 段 的 新 输 入 值。 它 还 可 以 在 拒 绝 新 值
时, 决 定 是 否 取 消 错 误 信 息 框 的 显 示。 ITEMERROR 事 件 的 动 作 码 可 以 是:
----0 拒 绝 新 的 数 据 值 并 且 显 示 错 误 信 息;( 缺 省)
----1 拒 绝 新 的 数 据 值 而 不 显 示 错 误 信 息;
----2 接 受 新 的 数 据 值;
----3 拒 绝 新 的 数 据 值 但 是 允 许 改 变 焦 点。
---- 如 果 我 们 想 要 在 一 特 定 区 域 显 示 一 个 用 户 自 定 义 的 错 误 信 息 来 代 替Power-
Builder 本 身 错 误 信 息 框, 我 们 可 以 使 用SetActionCode 来 取 消 标 准 的 信 息 框。 例 如,
在 前 面 例 子 中, 当 收 支 差 额 不 是0 是0 时, 我 们 就 可 以 用 这 一 方 法 显 示 一 个 错 误 信
息:
----//ItemError Event
----Long 11_Currow /* Current Row Number */
----String ls_column_name /* The name of the column that changed */
----ll_currow=this.GetRow()
----ls_column_name=this.GetColumnName
----CHOOSE CASE s_column_name
----CASE "status"
----MessageBox("Error","Account cannot be changed to Inactive"+ "Balance is no t zero.")
----this.SetActionCode(1)
----RETURN
----...
----END CHOOSE
---- 在ITEMERROR 事 件 中 使 用SetAc-tionCode, 我 们 就 可 以 有 选 择 地 忽 略DataWindow 对
象 的 一 个 列 中 输 入 的 有 效 性 规 则。 例 如, 在 收 支 差 额 中, 我 们 有 下 面 这 个 有 效 性
规 则:
----Real(GetText()) <=10000
---- 客 户 收 支 差 额 不 应 超 过10,000 元, 如 果 我 们 允 许 使 用 公 司 帐 户 的 客 户 可 以 超
过10,000, 我 们 可 以 使 用 如 下 方 式:
----//ItemError Event
----CHOOSE CASE ls_column_name
----CASE "balance"
----// Allow balance over $10,000 on Corportate accounts
----IF ld_balance not <=10000 AND ls_type="C"
----this.SetActionCode(2)
----RETURN
----END IF
----...
---- 我 们 也 可 以 像 前 面ITEMCHANGED 事 件 那 样 在Prinary!Buffer 中 拒 绝 新 输 入 的 值 并
填 入 新 值, 只 是 在 这 里 将 动 作 码 置 为3。
DBError Event
---- 在 执 行 了dw.Retrieve,dw.Update() 函 数 或 嵌 入 式SQL 语 句 并 发 生 了 一 个 数 据 库 错
误(SQ LCode 等 于-1) 时, 触 发DBError 事 件。 许 多Power-Builder 的 开 发 商 都 在 为 这 种 情
况 设 计 了 标 准 的 数 据 库 错 误 信 息 显 示。 为 了 使PowerBuilder 不 显 示 缺 省 的 数 据 库
错 误 信 息, 我 们 可 以 使 用SetActioncode。DBError 事 件 的 动 作 码 值 如 下:
----0 显 示 错 误 信 息。( 缺 省)
----1 不 显 示 错 误 信 息。
---- 例 如:
----//DBError event
----MessageBox(" 数 据 库 错 误"," 错 误 值"+string(this.DBErrorCode)+&
----" 错 误 信 息 为:"+this.DBErrorMessage(),StopSign!)
----//Supress PB generated DB Error Message.
----this.Set ActionCode(1)
----return
PrintPage
----PRINTPAGE 事 件 是 在 执 行dw.Print() 函 数 之 后, 数 据 传 送 给 打 印 机 之 前 触 发。 当 打
印 一 个 DataWindow 时, 你 可 在 打 印 之 前 设 置 动 作 码 来 跳 过 一 页。PRINT-PAGE 事 件
的 动 作 码 如 下:
----0 不 跳 过 一 页;( 缺 省)
----1 跳 过 一 页。
---- 如 您 打 算 打 印 时 跳 过 一 页, 你 可 以 在 中PRINTPAGE 编 码 如 下:
----//Printpage event
----this.SetActionCode(1)
RetrieveRow
---- 从 数 据 库 服 务 器 中 每 次 接 受 了 一 行 记 录 均 启 动REIRIEVEROW 事 件。 在 这 个 事
件 中, 你 可 以 设 置 一 动 作 码 来 停 止 检 索。 下 面 是RE-TRIEVEROW 事 件 的 有 效 动 作 码:
----0 继 续。( 缺 省)
----1 停 止 检 索。
---- 如 果 一 个DataWindow 将 命 中 很 多 行, 并 且 你 希 望 在 检 索 到 一 定 量 后 停 止。 你
可 以 在RETR IEVEROW 事 件 中 使 用SetActionCode:
----//RetrieveRow event
----//Instance variable Long il_count
----...
----IF il_count++ > 100 THEN
----// Maximum rows retrieved,stip retrieval
----this.SetActionCode(1)
----RETURN
----END IF
---- 当 用 来 给 被 检 索 行 计 数 的 临 时 变 量il_count 的 值 超 过100 时, 检 索 将 停 止。
---- 注 意: 在RETRIEVEROW 事 件 中 存 在 代 码, 那 么 检 索 每 一 行 都 会 触 发 事 件, 这 将 降
低 检 索 的 速 度。
----RetrieveStart
----RETRIEVESTART 事 件 在dw.Retrieve() 函 数 之 后, 产 生SQL 传 送 给 服 务 器 之 前 触 发。
---- 在 一 些 特 定 场 合 可 能 需 要 在 开 始 一 个 检 索 之 前 停 止 它。 在RetrieveStart 事 件
中 的 动 作 码:
----0 继 续。( 缺 省)
----1 不 检 索。
---- 例 如: 我 们 让 一 个 用 户 输 入 检 索 标 准 的 窗 口, 在RETRIEVESTART 中 判 断 返 回 行 数
是 否 太 多 , 以 决 定 停 止 检 索 并 且 让 用 户 缩 小 检 索 范 围。
----//Retrieve Start event
----Int li_count /*Expected Retrieve Count */
----...
----//Get count of Rows to be retrieved
----...
----IF li_count >1000 THEN
----MessageBox("Stop","Please narrow your search",stop!)
----This.SetActionCode(1)
----RETURN
----END IF
----...
UpdateStart
---- 这 一 在 执 行Update() 函 数 之 后, 产 生 的 修 改SQL 语 句 传 送 给 服 务 器 之 前 触 发。
---- 通 过 设 置 这 一 动 作 码, 你 可 以 阻 止 修 改 传 送 给 服 务 器。UPDATESTART 事 件 的 动
作 码 如 下:
----0 继 续。( 缺 省)
----1 不 修 改。
---- 如 果 你 要 阻 止 执 行 修 改 语 句, 在UP-DATESTART 事 件 中 使 用 下 列 代 码:
----//UpdateStart event
----...
----this.SetActionCode(1)
----RETURN
----...
综   述
---- 在 很 多 情 况 下, 设 置 动 作 码 是 非 常 有 用 的。 这 里 的 例 子, 让 你 对 其 中 几 种 情 况
有 一 个 了 解 。 当 你 对 使 用PowerScript 编 码 有 了 更 多 的 经 验 后, 你 会 发 现
SetActionCode 是 非 常 有 用 的。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然
鬼谷子
PB中数据窗口的两点应用技巧
人民银行咸宁地区中心支行 陈苇
----PowerBuilder是大家公认的、最佳的数据库前端开发工具之一,数据窗口(Datawindow)是
PowerBuilder中的关键技术,它能够灵活的组织数据库中的各种数据,用户能用一个简单的查询窗口就可以得到
丰富的查询结果,并且能够对查询结果集通过程序控制,得出各种用户想得到最终结果。如果能够熟练的运用数据
窗口这一专利技术,这无疑会给开发人员和用户带来巨大的方便。我们用PowerBuilder开发过一些应用系统,在
开发过程中也积累了一些数据窗口的应用技巧,现提供给各位,希望能够在您的开发过程中提供一定的帮助。
----在开发应用系统的时候,数据窗口中用户焦点要从一个字段转移到另外一个字段的时候,只能用Tab键来实
现,而用户通常是用回车键来改变焦点,为了保持用户的习惯,在系统中实现良好的用户操作界面,我们就必须实
现在数据窗口中用Enter代替Tab在字段间移动。实现方法:
----1)您需要创建一个可视的用户对象(UserObject),在标准(Standard)对象中选择DataWindow。
----2)选择Declare菜单项中的User Events子菜单,定义一个用户事件,取用户事件名为pb_enter(事件名
可任意指定),事件号(EventID)选择pbm_dwnprocessenter(此事件号不能任意指定)。点OK按纽退
回。
----3)在创建的用户对象上单击鼠标右键,选择弹出菜单上的Scripts项来编写程序,在select event上选择你
刚才定义的pb_enter事件,在编辑窗中输入以下两条语句后退出:
Send(Handle(this),256,9,Long(0,0))
return 1
----4)给你的用户对象取一个名字后保存即可。
----在你新建窗口需要用到数据窗口对象时,你就可以把你所定义的用户对象放入你的窗口中来代替PB提供的数据
窗口对象,它就可以实现用Enter代替Tab在字段间移动。
----我们在PowerBuilder应用程序的开发过程中,使用数据窗口时,经常会遇到某列的数据太长,不能同时全部显示
的情况.若采用自动水平滚动,操作起来又不够简便.下面介绍一种方法,实现列数据多行显示,即实现列数据的自动折
行.
具体步骤如下:
----1)打开一个数据窗口。
----2)在需设定自动折行的列上双击鼠标,弹开此列的属性窗口。
----3)选择Position标签,选中Autosize Height复选框。
----4)选择Edit标签, 不选中Auto Horz Scroll复选框。
----5)单击OK按钮,保存所做的修改。
----6)点中Detail带(写有Detail的灰色长带),单击鼠标右键,选择Properties
菜单项。
----7)选中Autosize Height复选框。
----8)单击OK按钮,保存所做的修改。
----9)保存此数据窗口。
----注意:连在一起的汉字(中间没有标点或空格分隔),系统将认为是一个单词,不会自动进行折行。

龙丘居士亦可怜
谈空说有夜不眠
忽闻河东师子吼
拄杖落手心茫然