在 上 期 中 我们 讨 论 了
在Master/Detail 数 据 窗 口 中, 当Master 数 据 窗 口 没 有使 用"Retrieve as Needed" 选 项 时, 两 个
数 据 窗 口 同 时 滚动 的 问 题。 可 是 当Master 数 据 窗 口 使 用 了"Retrieve as Needed" 选 项 时, 我 们 却
遇 到 了 麻 烦。 在 点 击dw_2 的 滚 动条 时, 如 果dw_1 从 数 据 库 中 取 得 了 新 数 据, 将 导 致dw_2 的复
位,dw_2 就 不 能 显 示 正 确 的 结 果 了。 解 决 这 个 问 题,我 们 最 容 易 想 到 的 解 决 方 法 就 是 利 用dw_2 在scrollvertical
事件 中 获 得 的dw_2 当 前 滚 动 条 的 位 置, 对dw_2 进 行 重 新 赋值。
即 对dw_1 的SCROLLVERTICAL 事 件 编 程 如下:
integer vmax_1, vpos_1,vmax_2, vpos_2
string r_code
decimal vmax_1_percent
vmax_1 = integer(dw_1.describe("datawindow.verticalscrollmaximum"))
vpos_1 =integer(dw_1.describe("datawindow.verticalscrollposition"))
vmax_2 = integer(dw_2.describe("datawindow.verticalscrollmaximum"))
vmax_1_percent = vpos_1 / vmax_1
vpos_2 = vmax_1_percent * vmax_2
r_code = dw_2.modify("datawindow.verticalscrollposition="+string(vpos_2))
// 检 验 是 否 修 改 成 功
if r_code <> "" then
beep(6)
mle_1.text = "dw_1scroll = "+r_code+" vpos_2 = "+string(vpos_2)
//在scrollvertical事件中无法使用MessageBox弹出错误信息框
end if
对dw_2 的SCROLLVERTICAL 事 件 编 程 如 下:
integer vmax_1, vpos_1,vmax_2, vpos_2
string r_code
decimal vmax_2_percent
vmax_2 = integer(dw_2.describe("datawindow.verticalscrollmaximum"))
vpos_2 = integer(dw_2.describe("datawindow.verticalscrollposition"))
vmax_1 =integer(dw_1.describe("datawindow.verticalscrollmaximum"))
vmax_2_percent = vpos_2 / vmax_2
vpos_1 = vmax_2_percent * vmax_1
r_code = dw_1.modify("datawindow.verticalscrollposition="+string(vpos_1))
// 检 验 是 否 修 改 成 功
if r_code <> ""then
beep(6)
mle_1.text = "dw_1 mod "+r_code
end if
r_code = dw_2.modify("datawindow.verticalscrollposition="+string(vpos_2))
// 检 验 是 否 修 改 成 功
if r_code <> "" then
beep(6)
sle_1.text = "dw_2 mod" + r_code
end if
键 入 上 述 代码 后, 运 行 时 你 就 会 发 现 点 击dw_2 时 运
行 的 结 果 是 正 常的, 然 而 点 击dw_1 的 滚 动 条 却 发 生 了 错 误。 这 是 为 什 么呢 ?
首 先 我 们 还是 对 用 户 点 击dw_1 的 滚 动 条 向 下 滚 动
时, 系 统 进 行 了 哪些 操 作 进 行 一 下 仔 细 地 分 析: 当 用 户 点 击 鼠 标 使dw_1 滚动 到 了 最 后 一 行 时, 这 时
系 统 没 有 立 即 进 行 显 示 滚 动的 操 作, 它 首 先 发 现 数 据 窗 口 的Primary! 缓 冲 区 的 数 据 已经 告 罄, 于
是 就 向 后 台 的 数 据 库 中 攫 取 数 据, 取 得 新的 数 据 后, 系 统 会 将 与dw_1 共 享 数 据 的dw_2 复 位, 使 之
回到 显 示 第 一 条 记 录 的 位 置。 这 就 触 发 了dw_2 的scrollvertical 事 件( 我 们 称 之 为 事 件 一)。 在 这
个 事 件 中, 由 于 此时dw_2 显 示 的 是 第 一 条 记 录, 它 将 修 改dw_1 的 滚 动 条 位置, 使 之 也 显 示 第 一 条 记
录。 并 立 即 触 发dw_1 的scrollvertical 事 件 二。 在 事 件 二 中,dw_1 又 根 据 自 己 的 位 置 修 改dw_2,但
是 由 于dw_2 修 改 前 后 的 位 置 相 同, 所 以 没 有 对 系 统 造成 什 么 影 响, 又 回 到 了 事 件 一。 在 事 件 执 行
完 毕 后,系 统 开 始 响 应 用 户 的 下 滚dw_1 的 操 作, 首 先 将dw_1 向 下 滚动 一 条 记 录, 这 样dw_1 显 示 的 是
第 二 条 记 录, 并 触 发 了dw_1 的scrollvertical 事 件 三。 当 事 件 三 执 行 时, 将dw_2 也 滚 动 到第 二 条
记 录, 并 触 发 了dw_2 的scrollvertical 事 件 四, 不 过 这一 事 件 四 也 不 会 对 任 何 一 个 数 据 窗 口 造 成
影 响, 最 后返 回 执 行 完 事 件 三。 这 就 完 成 了 用 户 点 击 鼠 标 后 的 一连 串 响 应。 但 是 最 后 两 个 数 据 窗 口
却 显 示 的 是 第 二 条记 录。 有 兴 趣 的 读 者 可 以 仔 细 分 析 这 一 系 列 事 件 发 生的 顺 序。
用 户 点 击 滚动 条 而 使 得 上 述 代 码 对 各 个 事 件 触 发
及 其 执 行 过 程虽 然 十 分 复 杂, 并 不 是 每 一 个 人 都 有 兴 趣 对 其 分 析 清楚, 但 是 这 个 代 码 的 错 误 却 是
一 目 了 然 的, 只 须 稍 加测 试 就 可 发 现。 可 是 令 人 不 解 的 是 这 段 代 码 在 美 国 却几 乎 被 视 作 经 典, 而 且
向 美 国PowerSoft 技 术 支 持 中 心 提出 这 个 问 题, 那 里 的 工 作 人 员 也 会 引 用 这 段 代 码 作 为回 答。
事 实 上 解 决这 个 问 题 的 方 法 并 不 十 分 复 杂, 我 们 只
需 将 修 改 滚 动条 位 置 的 时 间 稍 加 改 变 就 可 以 得 到 正 确 的 结 果。 首 先我 们 在 这 两 个 数 据 窗 口 中 各 声
明 一 个ue_scrollvertical 的 用户 自 定 义 事 件 事 件。 传 递 一 个 参 数, 参 数 名 为vpos,integer 型, 通
过 传 值 法 传 递。 然 后 键 入 下 列 代 码:
对dw_1 的SCROLLVERTICAL 事 件 编 程 如 下:
integer li_vmax_1, li_vpos_1,li_vmax_2, li_vpos_2
decimal ld_vmax_1_percent
li_vmax_1 = integer(dw_1.describe("datawindow.verticalscrollmaximum"))
li_vpos_1 = integer(dw_1.describe("datawindow.verticalscrollposition"))
li_vmax_2 = integer(dw_2.describe("datawindow.verticalscrollmaximum"))
ld_vmax_1_percent = li_vpos_1 / li_vmax_1
li_vpos_2 = ld_vmax_1_percent * li_vmax_2
if abs( li_vpos_2 - integer(dw_1.describe
("datawindow.verticalscrollposition")) ) > 1 then
//如dw_2应显示的位置与dw_2的当前位置不符,产生修改dw_2的事件
event post ue_scrollvertical( li_vpos_2 )
end if
对dw_1 的UE_SCROLLVERTICAL 事 件 编 程 如 下:
事 件: 自 定 义ue_scrollvertical
参 数:vpos integer 型
返 回 值:integer
string ls_ret_code
dw_2.modify("datawindow.verticalscrollposition="+string(vpos))
if ls_ret_code <> "" then
beep(6)
sle_1.text = "dw_1scroll = " + ls_ret_code + " vpos = " + string(vpos)
// 在scrollvertical 事 件 中 将 不 能 弹 出 错 误 信 息 框
end if
return 1
对dw_2 的SCROLLVERTICAL 事 件 编 程 如 下:
integer li_vmax_1, li_vpos_1,li_vmax_2, li_vpos_2
string ls_ret_code
decimal ld_vmax_2_percent
li_vmax_2 = integer(dw_2.describe("datawindow.verticalscrollmaximum"))
li_vpos_2 = integer(dw_2.describe("datawindow.verticalscrollposition"))
li_vmax_1 =integer(dw_1.describe("datawindow.verticalscrollmaximum"))
ld_vmax_2_percent = li_vpos_2 / li_vmax_2
li_vpos_1 = ld_vmax_2_percent * li_vmax_1
event post ue_scrollvertical(li_vpos_1)
//由于dw_1使用了retreive-as-needed,可能会自动将dw_2
滚回第一行,表现重新设置dw_2
ls_ret_code = dw_2.modify
("datawindow.verticalscrollposition="+string(li_vpos_2))
// 检 验 是 否 修 改 成 功
if ls_ret_code <> "" then
beep(6)
sle_1.text = "dw_2 mod" + ls_ret_code
end if
对dw_2 的UE_SCROLLVERTICAL 事 件 编 程 如 下:
事 件: 自 定 义ue_scrollvertical
参 数:vpos integer 型
返 回 值:integer
string ls_ret_code
ls_ret_code = dw_1.modify("datawindow.verticalscrollposition="+string(vpos))
// 检 验 是 否 修 改 成 功
if ls_ret_code <> ""then
beep(6)
sle_1.text = "dw_1 mod " + ls_ret_code
end if
我 们 再 分 析一 下 上 述 代 码 执 行 的 过 程: 用 户 点 击
了dw_1 的 滚 动 条,使dw_1 将 滚 动 到 最 后 一 行, 产 生 了dw_1 的scrollvertical 事 件一, 但 并 没 有 立 即
执 行, 只 放 在 了 事 件 队 列 的 后 面。系 统 首 先 发 现 数 据 窗 口 的Primary! 缓 冲 区 中 数 据 为 空, 向后 台 数
据 库 取 数 据, 并 使dw_2 复 位, 回 到 显 示 第 一 条 记录 的 位 置。 这 触 发 了dw_2 的scrollvertical 事 件
二, 在 首 先 执行 的 这 个 事 件 二 中,PowerBuilder 根 据dw_2 当 前 显 示 的 是 第 一条 记 录 这 一 条 件, 产 生
一 个ue_scrollvertical 事 件 三, 将dw_1 也滚 回 显 示 第 一 条 记 录, 但 是 这 个 事 件 三 并 没 有 立 即 触发
执 行, 而 是 放 在 了 事 件 队 列 的 最 后。 当 事 件 二 执 行完 毕 后, 系 统 响 应 用 户 对dw_1 进 行 的 向 下 翻 页
的 操 作,并 触 发dw_1 事 件 一 的 执 行。 这 时dw_1 显 示 的 是 用 户 希 望 看到 的 正 确 的 记 录,PowerBuilder
根 据dw_1 的 当 前 位 置, 计 算 出dw_2 与 之 相 对 应 的 位 置, 将 修 改dw_2 位 置 的 操
作ue_scrollvertical 事 件 四 放 在 了 事 件 队 列 的 最 后。 这 时 该 执 行 事 件 三了, 事 件 三 修 改dw_1 滚
动 条 的 位 置 至 第 一 条 记 录, 这 一操 作 触 发 了dw_1 的scrollvertical 事 件 五, 此 时 两 个 数 据 窗 口均
显 示 的 是 第 一 条 记 录。 在 这 一 事 件 中,PowerBuilder 经 过计 算, 得 到 了dw_2 应 显 示 的 位 置 与 当 前
位 置 相 等 的 结论, 因 此 不 产 生ue_scrollvertical 事 件, 事 件 五 没 有 对 系 统 产生 任 何 影 响。 接 下 来
执 行 的 是 事 件 队 列 中 仅 存 的 事 件四, 在 这 个 事 件 里, 系 统 将dw_2 滚 动 至 正 确 的 显 示 位 置上, 并 触 发
了dw_2 的scrollvertical 事 件 六。 在 事 件 六 中, 系 统又 产 生dw_2 的ue_scrollvertical 事 件 七, 但
是 这 两 个 事 件 均 没有 对 显 示 造 成 任 何 影 响, 这 两 个 事 件 执 行 过 程 中 也 没有 再 产 生 新 的 事 件, 这 一
系 列 的 响 应 便 最 终 结 束 了。而 最 终 的 结 果 是 两 个 数 据 窗 口 都 是 停 在 了 正 确 的 结果 上 了。
同 理, 我 们对 用 户 滚 动dw_2 后 系 统 的 响 应 进 行 细 致
地 分 析, 也 可 以看 到 上 述 代 码 的 正 确 性, 这 里 就 不 再 赘 述 了。
我 们 在 本 篇中 编 写 的 代 码 可 能 并 不 一 定 在 您 开 发
的 软 件 中 使 用得 上, 但 是 如 果 您 能 够 对 这 一 代 码 执 行 的 过 程 全 部 自行 分 析 清 楚, 或 者 有 足 够 的 耐
性 看 明 白 了 上 面 文 章 的分 析, 那 么 您 对PowerBuilder 的 事 件 一 定 会 有 更 深 的 理 解。
|