Database 版 (精华区)
发信人: wodeji (西西), 信区: Database
标 题: [转载] owerBuilder开 发 系 列 谈(25、26)
发信站: 紫 丁 香 (Tue Sep 29 17:52:53 1998), 站内信件
【 以下文字转载自 Programming 讨论区 】
【 原文由 two 所发表 】
一 个 代 码 维 护 的 应 用 程 序( 上、 下)
在 使 用PowerBuilder 编 程 的 过 程 中, 您 一 定 遇 到 过 一 个 全 局 变 量 或 设 计 的
对 象 需 要 更 换 名 称 的 情 况, 这 个 变 量 可 能 会 在 您 所 编 写 的 多 个PowerScript 中
引 用, 为 了 实 现 更 名, 您 可 能 要 打 开 所 有 的 对 象, 对 其 中 所 有 进 行 过 编 码
的 事 件 进 行 搜 索。 显 然, 这 是 一 个 非 常 费 时 费 力 的 工 作, 而 且 一 旦 搜 寻 有
所 遗 漏, 这 点 差 错 就 可 能 成 为 您 编 写 的 应 用 中 的 错 误 潜 伏 下 来, 在 测 试 或
直 到 用 户 使 用 时 才 被 发 现。
事 实 上PowerBuilder 系 统 本 身 提 供 了 一 系 列 对 其 本 身 对 象 库pbl 进 行 操 纵 的
函 数, 如LibraryDirectory() 等。 这 些 函 数 可 以 用 于 您 在 编 程 时 对 自 身 代 码 的 维
护, 还 可 以 自 动 创 建 用 于 打 印 报 表 的 数 据 窗 口 等。
这 里 我 们 介 绍 给 您 一 个 小 型 的 应 用 软 件, 用 于 自 动 检 索PowerBuilder 的pbl
库, 搜 索 和 替 换 您 指 定 的 对 象 或 代 码。 通 过 这 个 软 件, 您 将 进 一 步 了
解PowerBuilder 对 用 户 所 设 计 的 对 象 的 管 理 模 式。
我 们 首 先 设 计 一 个 用 于 浏 览 的 不 可 视 用 户 自 定 义 对 象 名 叫u_objbrowser。
这 个 对 象 的 作 用 是 在PowerBuilder 的 对 象 库 中 搜 索 和 浏 览 对 象。 浏 览 的 过 程 是
先 查 询 当 前 应 用 包 含 的 所 有PowerBuilder 对 象 库, 搜 索 这 些 库 中 指 定 的 对 象 类
型, 将 命 中 的 结 果 返 回。 在 这 个 对 象 中, 我 们 重 点 要 用 到 的 就
是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_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 库, 这 样 的 信 息 并 不 是 作 为application 对 象 的 一
个 属 性 存 储 在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 库 中 的 对 象
这 个 函 数 有 三 个 参 量: 一 个 由 库 名 组 成 的 字 串, 一 个LibDirType 对 象 类
型, 一 个 布 尔 型 的 标 志 参 数。 布 尔 参 数 用 以 指 示 是 否 只 返 回 对 象 名 称。
其 中LibDirType 是 一 个 枚 举 数 据 类 型, 包 括 了 下 列 的 几 个 值DirAll!,
DirApplication!, DirDataWindow!, DirFunction!, DirMenu!, DirStructure!, DirUserObject!
和DirWindow! 这 个 函 数 的 返 回 值 是 所 有 与 您 指 定 的 对 象 类 型 相 匹 配 的 存 储 在
这 些 库 中 的 对 象 名。 事 实 上 使 用LibraryDirectory() 函 数 还 将 包 含 这 些 对 象 的 注
释 和 最 后 修 改 的 时 间 等 信 息, 而 在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_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_pos1)
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_SearchCriteria, 将 用
户 输 入 的 信 息 填 写 入 这 个 结 构 中。 这 个 结 构 包 括:
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() 函 数 可 以 显 示 正 在 进
行 的 进 度, 本 文 也 正 是 将 这 个 窗 口 进 行 改 进 后 得 到 的, 不 过 这 个 窗 口
在PowerBuilder5.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
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 函 数, 用 程 序 来 完 成 输 入 工 作, 不 过 这 个 内 容
就 超 出 了 本 文 的 范 围 了。
--
※ 来源:.紫 丁 香 bbs.hit.edu.cn.[FROM: 202.97.236.132]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: whs.hit.edu.cn]
--
※ 转载:.紫 丁 香 bbs.hit.edu.cn.[FROM: cadcam.hit.edu.c]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:207.560毫秒