马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?站点注册
×
PowerBuilder DataWindow 运行时动态改属性:Modify 与 Describe
做业务系统时经常遇到这类需求:某个字段在 A 角色下只读、B 角色下可编辑;金额超过阈值的单元格要标红;某几列在导出模式下要临时隐藏。为每种情况各画一个 DataWindow 显然不现实。PowerBuilder 的办法是在运行时改属性——用 Modify() 写、用 Describe() 读。本文只讲清楚一件事:怎么用 Modify / Describe 在运行时安全地改列宽、颜色和可见性。
一、属性表达式:一切的基础
DataWindow 里的每个东西(列、文本、计算域、band)都有一串可读写的属性,寻址格式统一是 对象名.属性[.子属性]。常见几类:
| 写法 | 含义 | | emp_name.Width | 列 emp_name 的宽度(单位 PBU) | | emp_name.Visible | 是否可见,'0' 隐藏、'1' 显示 | | emp_name.Protect | 是否保护(只读),'1' 只读 | | emp_salary.Background.Color | 背景色(长整型数值的字符串) | | #3.Name | 第 3 列的列名(#n 按列序号寻址) | | DataWindow.Column.Count | 一共有多少列 | | DataWindow.Header.Color | 表头 band 的背景色 | | DataWindow.Detail.Height | 明细 band 的高度 |
记住两点就不会写错:属性名不区分大小写;赋的值要用单引号包起来,因为整条语法本身是一个字符串。
二、Modify:把属性写进去
Modify() 接收一条属性语法字符串,返回空串表示成功,返回非空就是出错信息。
- string ls_syntax, ls_err
- // 把 emp_name 列宽改成 600 PBU
- ls_syntax = "emp_name.Width = '600'"
- ls_err = dw_1.Modify(ls_syntax)
- if ls_err <> "" then
- MessageBox("改属性失败", ls_err)
- end if
复制代码
一定要接返回值。这是 Modify 和点号写法(dw_1.Object.emp_name.Width = 600)最大的区别:点号写法出错会触发 DataWindow 的 Error 事件甚至弹运行时错误,而 Modify 只是把错误当字符串还给你,逻辑上更好控制。
一次改多个属性,用换行符 ~n 拼起来即可,比连续调用几次更快:
- string ls_syntax, ls_err
- ls_syntax = "emp_name.Width = '600'~n" + &
- "emp_name.Protect = '1'~n" + &
- "emp_salary.Visible = '0'"
- ls_err = dw_1.Modify(ls_syntax)
复制代码
三、改颜色:值是数字,别忘了 RGB
颜色属性存的是长整型数值,用 RGB() 算出来再转成字符串拼进语法:
- long ll_red
- string ls_syntax, ls_err
- ll_red = RGB(255, 0, 0)
- ls_syntax = "emp_salary.Background.Color = '" + string(ll_red) + "'"
- ls_err = dw_1.Modify(ls_syntax)
- // 表头整条 band 换底色
- ls_syntax = "DataWindow.Header.Color = '" + string(RGB(230, 240, 250)) + "'"
- ls_err = dw_1.Modify(ls_syntax)
复制代码
更有意思的是条件表达式:属性值不一定是常量,可以是一段 DataWindow 表达式,格式为 '默认值~t表达式',中间用制表符 ~t 隔开。下面这句让工资超过 5000 的行自动标红,且随数据变化实时生效,不用逐行循环:
- string ls_syntax, ls_err
- ls_syntax = "emp_salary.Background.Color = " + &
- "'0~tif(emp_salary > 5000, RGB(255, 0, 0), RGB(255, 255, 255))'"
- ls_err = dw_1.Modify(ls_syntax)
复制代码
这是运行时动态改属性最值得掌握的一招:把「逐行判断」交给 DataWindow 引擎,代码量和刷新性能都远好过自己遍历。
四、Describe:先读再改,才不会瞎改
Describe() 反过来读属性,返回字符串。两个特殊返回值必须认识:
- "?":属性不存在,或对这个对象不适用(列名写错时最常见)。
- "!":取到的值不一致(一次问了多个对象时会这样)。
- string ls_width, ls_type, ls_coltype
- ls_width = dw_1.Describe("emp_name.Width") // 例如 "600"
- ls_type = dw_1.Describe("emp_name.Type") // "column"
- ls_coltype = dw_1.Describe("emp_name.ColType") // 例如 "char(40)"
- if ls_width = "?" then
- MessageBox("提示", "没有这个对象或属性,检查列名拼写")
- end if
复制代码
配合 DataWindow.Column.Count 和 #n.Name,可以写出完全不依赖具体列名的通用代码。注意循环变量要先声明再用,PowerBuilder 的 for 不支持在语句里内联声明:
- long ll_cols, i
- string ls_name, ls_syntax, ls_err
- ll_cols = long(dw_1.Describe("DataWindow.Column.Count"))
- for i = 1 to ll_cols
- ls_name = dw_1.Describe("#" + string(i) + ".Name")
- // 把所有列统一改成只读
- ls_syntax = ls_name + ".Protect = '1'"
- ls_err = dw_1.Modify(ls_syntax)
- next
复制代码
想知道一个 DataWindow 上到底有哪些对象(含文本、计算域、线条),问 DataWindow.Objects,返回的是用制表符分隔的一长串名字:
- string ls_objs
- ls_objs = dw_1.Describe("DataWindow.Objects")
- // 形如 "emp_id~temp_name~tt_title~tc_total"
复制代码
五、一个可运行的完整例子:按角色切换只读
把下面代码放在窗口的 open 事件或权限初始化函数里,就能用一份 DataWindow 应付两种角色。改属性前后加 SetRedraw,避免逐条刷新造成的闪烁:
- // 参数:ab_readonly = true 表示当前角色只读
- boolean lb_readonly
- long ll_cols, i
- string ls_name, ls_syntax, ls_err, ls_protect, ls_bkcolor
- lb_readonly = true
- if lb_readonly then
- ls_protect = "1"
- ls_bkcolor = string(RGB(240, 240, 240))
- else
- ls_protect = "0"
- ls_bkcolor = string(RGB(255, 255, 255))
- end if
- dw_1.SetRedraw(false)
- ll_cols = long(dw_1.Describe("DataWindow.Column.Count"))
- for i = 1 to ll_cols
- ls_name = dw_1.Describe("#" + string(i) + ".Name")
- if ls_name <> "?" then
- ls_syntax = ls_name + ".Protect = '" + ls_protect + "'~n" + &
- ls_name + ".Background.Color = '" + ls_bkcolor + "'"
- ls_err = dw_1.Modify(ls_syntax)
- if ls_err <> "" then
- // 某些对象没有 Background 属性时会报错,记录后继续
- ls_err = ""
- end if
- end if
- next
- // 只读模式顺手隐藏操作列
- if lb_readonly then
- ls_err = dw_1.Modify("b_delete.Visible = '0'")
- end if
- dw_1.SetRedraw(true)
复制代码
六、几个容易踩的坑
- 改动只在内存里:Modify 的效果只作用于当前运行的这个实例,程序关掉就没了,不会写回 PBL 里的 DataWindow 对象。要永久生效请在 DataWindow 画板里改。
- 列名和对象名不是一回事:emp_name 是列,标签文字往往叫 emp_name_t。改标题颜色要改文本对象,不是改列。
- 单引号必须成对:"emp_name.Width = 600" 少了单引号会返回错误信息。养成 ' + string(值) + ' 的拼法。
- ~t 是分隔符不是装饰:条件表达式的 '默认值~t表达式' 里那个制表符不能省,省了整条语法就无效。
- 批量改前先 SetRedraw(false):几十列逐条 Modify 会明显闪屏,包起来能快好几倍。
- 返回值要判断:Describe 拿到 "?" 就说明寻址写错了,别把它当成正常值继续参与计算。
七、小结
运行时改属性其实就两个动作:Describe() 问清楚现状,Modify() 写下去并检查返回值。宽度、可见性、只读、颜色这些全都能改;遇到「按条件变色」这类需求,优先用 '默认值~t表达式' 交给 DataWindow 引擎判断,而不是自己逐行循环。把这两个函数用熟,一个 DataWindow 就能适配多角色、多场景,省下的是一堆几乎重复的数据窗口对象。 |