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毫秒