软件维护常见问题--更换全局变量名称或对象名称

来源:互联网 发布:linux more指令 编辑:程序博客网 时间:2024/06/05 15:03

 


      在 使 用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
     
最 后 一 个 函 数 是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 函 数,用 程 序 来 完 成 输 入 工 作, 不 过 这 个 内 容 就 超 出 了 本 文的 范 围 了。

原创粉丝点击