Database 版 (精华区)

发信人: lizhenguo (夸父·追日), 信区: Database
标  题: 25,26
发信站: 哈工大紫丁香 (2001年09月26日18:46:06 星期三), 站内信件

 bbs.hit.edu.cn
PowerBuilder专栏
[回到开始][上一层][下一篇]
----------------------------------------------------------------------------
----
发信人: carsam (独自偷...), 信区: Database
标 题: PowerBuilder应用开发系列讲座(25,26)
发信站: 逸仙时空 Yat-sen Channel (Wed Jan 5 12:33:05 2000), 站内信件
PowerBuilder应用开发系列讲座(25,26)
----------------------------------------------------------------------------

----
一个代码维护的应用程序(上、下)
? 在 使 用PowerBuilder 编 程 的 过 程 中, 您 一 定 遇 到 过 一 个全 局 变
量 或 设 计 的 对 象 需 要 更 换 名 称 的 情 况, 这 个 变 量可 能 会 在 您
所 编 写 的 多 个PowerScript 中 引 用, 为 了 实 现 更 名,您 可 能 要 打 开

所 有 的 对 象, 对 其 中 所 有 进 行 过 编 码 的 事件 进 行 搜 索。 显 然,

这 是 一 个 非 常 费 时 费 力 的 工 作, 而 且一 旦 搜 寻 有 所 遗 漏, 这
点 差 错 就 可 能 成 为 您 编 写 的 应 用中 的 错 误 潜 伏 下 来, 在 测 试
或 直 到 用 户 使 用 时 才 被 发 现。
  事 实 上PowerBuilder 系 统 本 身 提 供 了 一 系 列 对 其 本 身 对象 库pb

l 进 行 操 纵 的 函 数, 如LibraryDirectory() 等。 这 些 函 数 可以 用 于 您

在 编 程 时 对 自 身 代 码 的 维 护, 还 可 以 自 动 创 建用 于 打 印 报 表
的 数 据 窗 口 等。
  这 里 我 们 介 绍 给 您 一 个 小 型 的 应 用 软 件, 用 于 自 动检 索Pow

erBuilder 的pbl 库, 搜 索 和 替 换 您 指 定 的 对 象 或 代 码。通 过 这 个
软 件, 您 将 进 一 步 了 解PowerBuilder 对 用 户 所 设 计的 对 象 的 管 理
模 式。
  我 们 首 先 设 计 一 个 用 于 浏 览 的 不 可 视 用 户 自 定 义 对象 名 叫

u_objbrowser。 这 个 对 象 的 作 用 是 在PowerBuilder 的 对 象库 中 搜 索 和

浏 览 对 象。 浏 览 的 过 程 是 先 查 询 当 前 应 用 包含 的 所 有PowerBuil
der 对 象 库, 搜 索 这 些 库 中 指 定 的 对 象 类型, 将 命 中 的 结 果 返
回。 在 这 个 对 象 中, 我 们 重 点 要 用 到的 就 是LibraryDirectory() 这 个

函 数。
  您 一 定 都 用 过 函 数ImportString() 为 数 据 窗 口 填 充 数 据。在 这
里 使 用 的LibraryDirectory() 函 数 所 得 到 的 返 回 信 息 同ImportString()

的 表 达 方 式 是 基 本 相 似: 结 果 为 一 个 字 符 串, 字 符 之 间 表达
不 同 的 列 以~t 分 隔, 不 同 的 行 以~n 分 隔。
  在u_browser 对 象 中, 我 们 声 明 实 例 变 量 如 下:
string uis_ApplicationName // 当 前 应 用 名
string uis_ApplicationLibrary // 包 含 应 用 对 象 的pbl 库 名
string uis_ApplicationDirectory // ApplicationLibrary 所 在 的 路 径
string uis_PBiniFile // pb.ini 的 文 件 名 称
  这 个 对 象 中 包 含 了 这 样 几 个 函 数:
牋牋牋 u_browser.uf_GetCurrentApplication(), 获 取 当 前 应 用 名
  这 个 函 数 是 一 个 初 始 化 函 数, 它 首 先 在WIN.INI 中 寻 找PB.INI
的 路 径, 读 取PB.INI 文 件 中 的[APPLICATION] 这 一 段, 来 获 取 当前 这
个 应 用 的 操 作 环 境。 然 后 对 两 个 变 量 赋 值:uis_ApplicationName 是

当 前 应 用 的 名 称,uis_ApplicationLibrary 是 这 个 应 用 的 应 用对 象 所

存 储 的pbl 库 名。
u_browser.uf_GetCurrentApplication()
long ll_pos1, ll_pos2
string ls_PBInitPath
// 获 取PB.INI 的 路 径
ls_PBInitPath = ProfileString (“WIN.INI”,POWERBUILDER”,
“INITPATH”,“”)
uis_PBiniFile = “PB.INI*
IF ls_PBInitPath <> “”THEN
IF Right(ls_PBInitPath, 1) <> *\” THEN
ls_PBInitPath = ls_PBInitPath + *\*
END IF
uis_PBiniFile = ls_PBInitPath + uis_PBiniFile
END IF
//从PB.INI文件中获取应用名称和所在的PBL库名
uis_ApplicationName = ProfileString(PBiniFile, "APPLICATION”,
“APPNAME”, “”)
uis_ApplicationLibrary = ProfileString(PBiniFile,“APPLICATION”,
“APPLIB”,“”)
uis_ApplicationDirectory = “”
ll_pos1 = 0
ll_pos1 = 0
ll_pos2 = Pos(uis_ApplicationLibrary, *\”)
DO WHILE ll_pos2 > 0
ll_pos1 = ll_pos2
ll_pos2 = Pos(uis_ApplicationLibrary, *\”, ll_pos1 + 1)
LOOP
IF ll_pos1 > 0 THEN uis_ApplicationDirectory = Left
(uis_ApplicationLibrary, ll_pos1)
  u_browser.uf_GetLibraryPath(): 获 取 本 应 用 所 包 含 的pbl 库名
  一 个 应 用 包 含 了 哪 几 个pbl 库, 这 样 的 信 息 并 不 是 作为applic

ation 对 象 的 一 个 属 性 存 储 在pbl 库 中 的, 而 是 包 含 在了pb.ini 文
件 中[application] 段 的$AppLib 项 等 号 后 面 的 字 符 串中, 库 名 与 库 名

之 间 以 分 号 分 隔。 在 这 里 我 们 使 用 了uf_GetLibraryPath() 函 数 读
取 这 些 信 息, 并 将 库 名 字 符 串 改 变 为 以 标 准 的~t 分隔, 作 为 函

数 的 返 回 值。
long ll_pos1
string ls_LibraryList
// 从pb.ini 中 读 取 本 应 用pbl 库 的 路 径
ls_LibraryList = ProfileString ( uis_PBiniFile,&
“Application”,“$” + uis_ApplicationLibrary +&
“(” + uis_ApplicationName + “)”, “”)
// 以~t 符 号 取 代 分 号 作 为 分 隔 符
ls_pos1 = Pos(ls_LibraryList, “;”)
DO WHILE ls_pos1 > 0
ls_LibraryList = Replace(ls_LibraryList, ll_pos1, 1,“~t~n”)
ll_pos1 = Pos(ls_LibraryList, “;”, ll_pos1 + 2)
LOOP
RETURN ls_LibraryList
  当 得 到 了 这 些 库 名 的 列 表 后, 我 们 就 可 以 在 库 中 搜索 我 们

所 须 的 任 何 一 个 特 定 的 对 象 了 ( 如Application, Window, DataWindow,
Menu, Function, Structure 或UserObject 等)。
牋牋牋 uf_GetLibraryObjects(): 获 取pbl 库 中 的 对 象
  这 个 函 数 有 三 个 参 量: 一 个 由 库 名 组 成 的 字 串, 一个LibDirT

ype 对 象 类 型, 一 个 布 尔 型 的 标 志 参 数。 布 尔 参 数用 以 指 示 是
否 只 返 回 对 象 名 称。
  其 中LibDirType 是 一 个 枚 举 数 据 类 型, 包 括 了 下 列 的 几个 值Di

rAll!, DirApplication!, DirDataWindow!, DirFunction!, DirMenu!, DirStructure

!, DirUserObject! 和DirWindow! 这 个 函 数 的 返 回 值 是 所有 与 您 指 定 的

对 象 类 型 相 匹 配 的 存 储 在 这 些 库 中 的 对 象名。 事 实 上 使 用Lib
raryDirectory() 函 数 还 将 包 含 这 些 对 象 的注 释 和 最 后 修 改 的 时 间

等 信 息, 而 在uf_GetLibraryObjects() 函数 中, 我 们 可 以 根 据 布 尔 参
数, 来 决 定 是 否 调 用uf_ParseDirectory() 函 数 将 这 些 内 容 剔 除 掉。

uf_GetLibraryObjects()
// 参 数
// 参 数
//string as_LibraryName
//LibDirType a_ObjectType
//boolean ab_ParseList
string ls_result
ls_result = LibraryDirectory (as_LibraryName, a_ObjectType)
IF ab_ParseList THEN
ls_result = This.uf_ParseDirectory (ls_result)
END IF
RETURN ls_result
  使 用LibraryDirectory() 函 数 得 到 的 对 象 信 息 有 三 个 数 据段: 对

象 名 称、 修 改 时 间 和 注 释, 这 三 个 字 段 以~t 相 隔, 不同 的 对 象
间 以~n 分 隔。uf_ParseDirectory() 函 数 将 删 除 每 一 条记 录 的 后 两 个
字 段, 只 保 留 对 象 名 称 的 信 息。uf_ParseDirectory() 函 数 的 代 码 如

下:
uf_ParseDirectory()
// 参 数:string as_LibDirectory
// 返 回:string
string ls_ObjList = “”
long ll_pos1, ll_pos2, ll_DirLen
ll_DirLen = Len(as_LibDirectory)
ll_pos1 = 1
DO WHILE ll_pos1 < ll_DirLen
// 找 到 第 一 个tab 分 隔 符
ll_pos2 = Pos (as_LibDirectory, “~t”, ll_pos1)
//分离出对象名称,并将其加入到对象列表中去
ObjList = ObjList + Mid(LibDirectory, Pos1, Pos2 - Pos1) + "~t~n*
Pos1 = Pos (LibDirectory, *~n*, Pos2) + 1
LOOP
RETURN ls_ObjList
  最 后 一 个 函 数 是uf_ConvertListToArray(), 它 接 受 一 个 由对 象 名
组 成 的 字 符 串, 将 其 分 隔 为 数 组 形 式。
uf_ConvertListToArray()
// 参 数:string as_ObjectString
// string as_ObjectOjbect
// string as_OjbectArray reference
// 返 回: 分 隔 符 的 个 数
long ll_pos1, ll_pos2, ll_count
int li_seplen
IF as_ObjectString = “” THEN RETURN 0
li_SepLen = Len(as_ObjectSeparator)
IF Right (as_ObjectString, SepLen) <> as_ObjectSeparator &
THEN as_ObjectString = as_ObjectString + as_ObjectSeparator
//确定分隔符在字串中的位置
ll_count = 0
ll_count = 0
ll_pos1 = 1
ll_pos2 = Pos (as_ObjectString, as_ObjectSeparator)
DO UNTIL ll_pos2 = 0
ll_Count ++
// 将 分 隔 符 间 的 内 容 拷 贝 在 数 组 中
as_ObjectArray[ll_count] = Mid (as_ObjectString, ll_pos1, ll_pos2 - ll_pos
1)
ll_pos1 = ll_pos2 + li_seplen
ll_pos2 = Pos (as_ObjectString, as_ObjectSeparator, ll_pos1)
LOOP
// 返 回 分 隔 符 的 个 数
RETURN ll_count
---------在此处分隔为上下两篇---------
  我 们 要 写 的 这 个 搜 索 及 替 换 的 应 用 程 序 使 用 了u_browser 这
个 用 户 对 象。 它 将 根 据 用 户 指 定 的 选 择 条 件, 搜 索 对 象的 输 出

文 本。 但 是 用 于PowerBuilder 并 不 支 持 除 数 据 窗 口 外对 象 的 动 态
输 入, 所 以 如 果 我 们 对 输 出 的 文 本 进 行 修 改后 是 无 法 存 入pbl
库 中 的, 我 们 只 能 将 其 保 存 成 为 一 个 文本 文 件, 搜 索 完 成 后,

在Library 画 笔 中 手 工 将 这 些 修 改 后的 对 象 输 入 库 中。
  我 们 要 注 意 的 问 题 是, 如 果 在 不 同 的 对 象 之 间 都 引用 了 修

改 的 文 字 时, 输 入 这 些 对 象 的 顺 序 是 十 分 重 要 的,例 如 您 修
改 了 全 局 变 量 的 名 称, 您 就 应 当 首 先 输 入application 对 象, 也 就

是 说 您 应 当 首 先 输 入 定 义 文 字 的 那 个 对 象。 另一 个 注 意 事 项
是, 您 不 能 修 改PowerBuilder 保 留 的 关 键 字, 如type,within 等。 当
您 使 用 了 这 个 搜 索 工 具 以 后, 它 会 自 动 生 成 一 个 文件 指 示 您
需 要 输 入 对 象 的 名 称、 这 个 对 象 的 库 名 和 对 象输 出 的 文 件 名。

  在 这 个 应 用 的Open 事 件 中 我 们 写 入 这 样 一 段 代 码:
Browser = CREATE u_objbrowser
Browser.ff_GetCurrentApplication()
Open(w_search_criteria)
  其 中 将 要 打 开 的w_search_criteria 窗 口 如 图 所 示:
  在 上 面 的ListBox 中 显 示 了 当 前 应 用 所 包 含 的pbl 库, 由用 户 指

定 搜 索 的 范 围, 左 下 角 为 十 个 多 选 框, 指 定 要 选 择的 对 象 名
称, 右 下 角 由 用 户 输 入 查 找 和 替 换 的 字 符 串 内容。
  在 这 个 窗 口 中 声 明 一 个wstr_SearchCriteria 结 构 的 实 例iwstr_Sea

rchCriteria,将 用 户 输 入 的 信 息 填 写 入 这 个 结 构 中。 这 个 结 构 包

括:
boolean object_type[] //用户在窗口右下角选中的对象类型
integer lib_count //用户选择对象库的个数
string lib_list[] //用户选择了的pbl库名
boolean match_case //用户是否选择了“区分大小写”的选项
此外还要对以下几个实例变量赋值:
string is_SearchFor //用户指定搜索的字符串
string is_ReplaceText //用户指定替换的字符串
integer ii_ReplaceLen = len(is_SearchFor)
integer ii_SecharLen = len(is_ReplaceText)
  当 用 户 按 下“ 开 始 查 找” 的 按 钮 以 后, 出 现 一 个 显 示进 度 的

子 窗 口。 这 个 窗 口 的 设 计 过 程 限 于 篇 幅 从 略。 在PowerBuilder4.0
的 类 库 中 有 一 个 可 以 利 于 的 用 于 显 示 进 度 的 窗 口, 通 过调 用
该 窗 口 的f_progress() 函 数 可 以 显 示 正 在 进 行 的 进 度,本 文 也 正
是 将 这 个 窗 口 进 行 改 进 后 得 到 的, 不 过 这 个 窗口 在PowerBuilder
5.0 的 类 库 中 被 取 消 了, 如 果 您 也 想 使 用 它,就 只 能 将 其 从4.0
中 升 级 得 到 了。 在 这 个 窗 口 中 我 们 使 用了 两 个 用 户 自 定 义 事
件ue_object 和ue_search 来 分 别 控 制 搜 索的 对 象 和 完 成 查 找 工 作。
  当 有 文 本 被 替 换 时, 我 们 调 用 窗 口 函 数wf_SaveExportObject(),

将 这 个 对 象 的 输 出 文 件 冠 以$PBExportHeader$objectnam e.ext~r~n 的 文

字, 并 将 其 保 存 成 为 一 个 文 件。 这 个 对 象 名 称 的 前8 个 字 符 作

为 文 件 名 称, 如 果 出 现 重 名, 将 提 示 用 户, 由 用户 进 行 确 认。
  在 这 个 进 度 窗 口 打 开 时, 我 们 声 明 一 个wstr_object 结构 的 实
例 数 组iwstr_object[], 用 以 记 录 用 户 选 中 了 的 对 象 类型。 这 个 结

构 包 括 以 下 几 个 元 素:
string libraryname //该对象将要在哪个pbl库中搜索
integer objecttype //这个对象类型
integer objectcount //在这个库中共命中了多少个该对象类型
string objectlist[] //命中对象的名称
在ue_object事件中我们要作以下初始化的工作:
int li_MaxIndex,li_LibCnt, k, j
string ls_List
libdirtype libdir[] = {dirapplication!,dirdatawindow!, &
dirfunction!,dirmenu!,dirpipeline!,dirproject!,dirquery!,&
dirstructure!,diruserobject!,dirwindow!}
long ProgressMax, ProgressCur = 0
int li_curobj, li_curobjcount
libexporttype libexport[]={exportapplication!,exportdatawindow!, &
exportfunction!,exportmenu!,exportpipeline!,exportproject!,
exportquery!,&
exportstructure!,exportuserobject!,exportwindow!}
li_MaxIndex = 0
liLibCnt = iwstr_SearchCriteria.lib_count
//对每一个用户选中的pbl库
FOR j = 1 to li_LibCnt
//对于每一个可能选择的对象类型
FOR k = 1 to 10
//如果用户选择了该对象类型
IF iwstr_searchcriterial.object_types[k] THEN
li_MaxIndex ++
//保存库名
lwstr_object[li_MaxIndex].LibraryName =&
iwstr_searchcriterial.Lib_List[j]
//保存对象类型
lwstr_object[li_MaxIndex].ObjectType = k
//获取该对象类型在库中的全部名称列表
ls_List = Browser.uf_GetLibraryObjects(&
lwstr_object[li_MaxIndex].LibraryName,&
LibDir[k], TRUE)
//将名称列表转换为数组形式
lwstr_object[li_MaxIndex].ObjectCount = &
Browser.uf_ConvertListToArray(ls_List,&
lwstr_object[li_MaxIndex].ObjectList, "~t~n")
ProgressMax = ProgressMax + &
lwstr_object[li_MaxIndex].ObjectCount
END IF
NEXT
NEXT
  // 现 在 要 搜 索 的 对 象 名 称 都 已 经 确 定, 接 下 来 我 们要 作 的

事 情 就 是 循 环 输 出 每 一 个
  // 对 象 的 文 本, 并 调 用ue_search() 事 件, 搜 索 出 指 定 的文 字。

FOR li_CurIndex = 1 to li_MaxIndex
FOR li_CurObj = 1 to lwstr_object[k].OjbectCount
// 显 示 对 象 信 息
st_library.Text = lwstr_object[li_CurIndex].LibraryName
st_object.Text = lwstr_object[li_CurIndex].ObjectList[li_CurObj]
// 将 对 象 输 出 到mle_text 中
mle_text.Text = LibraryExport(lwstr_object[li_CurIndex].LibraryName,
&
lwstr_object[li_CurIndex].ObjectList[li_CurObj], &
LibExport[lwstr_object[li_CurIndex].ObjectType])
THIS.Event ue_search()
ProgressCur ++
f_Progress( ProgressCur / ProgressMax )
NEXT
NEXT
UE_SEARCH事件将搜索与之匹配的文本,其代码如下:
int li_SearchPos = 0
boolean lb_Changed = False
DO
IF iwstr_searchcriterial.match_case THEN
li_SearchPos = Pos(mle_text.Text, is_SearchFor, li_SearchPos )
ELSE
ELSE
li_SearchPos = Pos(UPPER(mle_text.Text),is_SearchFor, li_SearchPos )
END IF
IF li_SearchPos > 0 THEN
mle_text.text = Replace(mle_text.text, li_SearchPos, ii_SearchLen, &
is_ReplaceText )
changed = true
li_SearchPos += ii_ReplaceLen
END IF
LOOP WHILE li_SearchPos <> 0
//如果没有发现匹配的文字则返回,否则将保存该输出文件
IF Changed THEN
wf_SaveExportObject()
END IF
  这 里 我 们 只 是 列 出 了 这 个 软 件 中 部 分 代 码, 其 余 部分 您 可

自 行 补 齐。 事 实 上, 这 个 应 用 小 软 件 的 用 途 是 非 常广 的。 我 们

在 以 前 的 专 题 中 曾 经 谈 到 过 使 用 可 重 用 的 数据 窗 口 的 问 题,
将 数 据 窗 口 定 义 为 由 用 户 对 象dw_main 继 承而 来 的 用 户 对 象, 并

且 提 到 了 要 改 变 已 设 计 好 的 数 据 窗口 所 应 继 承 的 祖 先 对 象。
此 外 您 在 编 程 中 可 能 经 历 过 这样 的 事 情, 在 最 开 始 编 程 曾 经
尝 试 使 用 了 一 些 简 单 地 窗口 继 承, 而 当 您 完 成 了 该 软 件 的 开
发, 而 且 具 有 了 一 定 的开 发 经 验 后, 在 整 理 这 些 代 码 时, 您 会

发 现 有 更 好 的 继 承关 系 来 取 代 现 有 的 层 次, 当 您 设 计 好 新 的
基 类 后, 就 可 以使 用 这 个 软 件 来 替 换 原 有 的 基 类 对 象 了。
  由 于PowerBuilder 没 有 为 我 们 提 供 将 对 象 输 入pbl 库 的 函数, 我

们 只 能 将 其 保 存 成 为 文 件, 然 后 手 工 输 入 对 象 库 中。如 果 您
认 为 这 样 太 麻 烦, 也 可 以 使 用C 语 言 调 用 其ORCA 的API 函 数, 用 程

序 来 完 成 输 入 工 作, 不 过 这 个 内 容 就 超 出 了 本文 的 范 围 了。
--
我想自由自在地飞......
飞过大海...
飞过沙漠...
飞翔在星的夜空......
※ 来源:.逸仙时空 Yat-sen Channel bbs.zsu.edu.cn.[FROM: 202.116.90.29]
----------------------------------------------------------------------------
----
[回到开始][上一层][下一篇]
欢迎访问Cterm主页

--
《列子·汤问》:“夸父不量力,欲追日影,逐之于隅谷之际。渴欲 得饮,赴饮河渭
。河渭不足,将走北饮大泽。未至,道渴而死。”

※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 202.118.229.154]
[百宝箱] [返回首页] [上级目录] [根目录] [返回顶部] [刷新] [返回]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:207.062毫秒