pbai 发表于 2026-8-21 07:47:28

PowerBuilder DataWindow 入门:从取数到保存的一条完整链路

PowerBuilder DataWindow 入门:从取数到保存的一条完整链路


阅读说明
① 适用版本:PowerBuilder 9.0 ~ 12.5(PBIDEA 兼容);
② 支持数据库:示例基于 SQL Server(SQLCA 连接),本文 API 适用于任何 PB 支持的数据库;
③ 操作系统与环境要求:Windows 7 及以上,需能连接到目标数据库;
④ 难度系数:★★★☆☆(入门进阶,建议先看过 Day1《DataWindow 三缓冲区》再读本文效果更好);
⑤ 其它阅读说明:示例假设窗口上已放置数据窗口控件 dw_1,且其 DataObject 已指向某个 d_ 开头的 DataWindow 对象。


DataWindow 到底是什么

DataWindow(数据窗口)是 PowerBuilder 最核心的武器:一条 SQL 查出来,界面、录入、校验、更新全包了。理解它抓住三点:


[*]两个输入:数据源(SQL 语句或外部数据)+ 表现风格(Grid 表格 / Tabular 列表 / Freeform 自由格式)。
[*]三层对象:DataWindow 对象(设计时画的,存在 d_ 开头的对象里)→ DataWindow 控件(窗口里放的 dw_1)→ 缓冲区里的行数据。
[*]四类成员:属性(DataObject、Border…)、函数(Retrieve、Update…)、事件(itemchanged、dberror…)、子对象(列、文本、band)。


日常工作就是围绕"取数 → 编辑 → 保存"这条链路转,本文按这个顺序讲透。

第一步:连接数据库(SQLCA)

PB 用事务对象 SQLCA 统一管数据库连接,窗口打开时配一次即可。


// 窗口 open 事件:配置并连接数据库
SQLCA.DBMS   = "MSSQL"            // 数据库类型
SQLCA.ServerName = "127.0.0.1,1433" // 服务器和端口
SQLCA.Database   = "demo"         // 数据库名
SQLCA.UserID   = "sa"             // 用户名
SQLCA.Pass       = "123456"         // 密码
SQLCA.AutoCommit = false            // 手动控制事务

// 连接
long ll_code
ll_code = SQLCA.Connect()
if ll_code <> 0 then
    MessageBox("错误", "连接失败:" + SQLCA.SQLErrText)
    return
end if

MessageBox("提示", "数据库连接成功")


第二步:取数(SetTransObject + Retrieve)

把事务对象交给 dw_1,再执行 Retrieve 拉数据。顺序不能反:先 SetTransObject 再 Retrieve。


// 按钮 cb_retrieve 的 clicked 事件:取数
long ll_rows
dw_1.SetTransObject(SQLCA)          // 让 dw_1 用 SQLCA 这个连接
ll_rows = dw_1.Retrieve()         // 执行检索,返回行数

if ll_rows = -1 then                // -1 表示检索出错
    MessageBox("错误", "检索失败:" + SQLCA.SQLErrText)
    return
elseif ll_rows = 0 then
    MessageBox("提示", "没有查到数据")
else
    MessageBox("提示", "共检索到 " + String(ll_rows) + " 行")
end if


如果 DataWindow 对象定义了检索参数(比如按部门查),Retrieve 直接传参:


string ls_dept
ls_dept = "SALES"
dw_1.Retrieve(ls_dept)            // 参数顺序、类型与定义时一致


第三步:编辑行(新增 / 删除 / 改值)

新增一行


// 按钮 cb_add 的 clicked 事件:末尾加一行并跳到新行
long ll_new
ll_new = dw_1.InsertRow(0)          // 0 表示插到末尾,返回新行号
dw_1.ScrollToRow(ll_new)            // 滚动到新行
dw_1.SetColumn("name")            // 光标定位到 name 列
dw_1.SetFocus()

// 给新行填默认值(可直接写入缓冲区,用户可见)
dw_1.SetItem(ll_new, "create_date", Today())

MessageBox("提示", "已新增第 " + String(ll_new) + " 行,请录入")


删除当前行


// 按钮 cb_del 的 clicked 事件:删除当前行
long ll_cur
ll_cur = dw_1.GetRow()            // 当前行号
if ll_cur <= 0 then
    MessageBox("提示", "没有可删除的行")
    return
end if

if MessageBox("确认", "删除当前行?", Question!, YesNo!) = 1 then
    dw_1.DeleteRow(ll_cur)          // 注意:只是进删除缓冲区,还没真正删库
    MessageBox("提示", "已删除,记得点保存才会生效")
end if


第四步:保存(AcceptText + Update + 事务)

保存是新手最容易出错的地方,三个动作缺一不可:


[*]AcceptText():把正在编辑的单元格内容收进缓冲区——不调用的话,光标所在格的修改会丢;
[*]Update():把缓冲区的新增/修改/删除生成 SQL 发给数据库;
[*]COMMIT / ROLLBACK:按 Update 结果提交或回滚事务。



// 按钮 cb_save 的 clicked 事件:保存全部修改
integer li_ret
li_ret = dw_1.AcceptText()          // 1=成功 0=没输入框 -1=数据非法
if li_ret <> 1 then
    MessageBox("错误", "当前单元格数据不合法,请检查后再保存")
    return
end if

// 更新数据库
integer li_upd
li_upd = dw_1.Update()
if li_upd = 1 then
    commit using SQLCA ;            // 提交事务
    MessageBox("提示", "保存成功")
else
    rollback using SQLCA ;          // 失败回滚,不留半截数据
    MessageBox("错误", "保存失败:" + SQLCA.SQLErrText)
end if



注意:commit using SQLCA ; 末尾的分号是 PowerScript 嵌入式 SQL 的固定写法,不能省。


第五步:常用函数速查


分类函数作用
取数Retrieve()执行检索,返回行数(-1 出错)
行操作InsertRow(n) / DeleteRow(n)增 / 删行(n=0 表示末尾)
行操作RowCount()当前主缓冲区行数
行操作GetRow() / SetRow(n) / ScrollToRow(n)取 / 设 / 滚动到当前行
列操作GetColumn() / SetColumn("列名")取 / 设当前列
列操作GetItemString(n,"列") / GetItemNumber(n,"列")读某行某列的值
列操作SetItem(n, "列", 值)直接写缓冲区某个格
列操作AcceptText()把正在编辑的格子收进缓冲区
数据Update()把改动写回数据库
数据Reset()清空全部行
排序过滤SetSort("列 A") + Sort()排序
排序过滤SetFilter("条件") + Filter()过滤显示(不删数据)
查找Find("条件", 1, RowCount())按条件找行,返回行号



// 综合示例:读值、排序、过滤、查找
// 输入值
long ll_cnt
ll_cnt = dw_1.RowCount()            // 当前行数

// 读当前行 name 列
long ll_row
ll_row = dw_1.GetRow()
string ls_name
ls_name = dw_1.GetItemString(ll_row, "name")

// 按薪资降序排
dw_1.SetSort("salary D")            // A=升序 D=降序
dw_1.Sort()

// 只看薪资大于 5000 的行(数据还在,只是不显示)
dw_1.SetFilter("salary > 5000")
dw_1.Filter()

// 按条件找行:找到返回行号,找不到返回 0
long ll_find
ll_find = dw_1.Find("name = 'Tom'", 1, dw_1.RowCount())

MessageBox("查询示例", "共" + String(ll_cnt) + "行 / 当前行name=" + ls_name + " / 找到Tom在" + String(ll_find) + "行")


第六步:事件入门(校验就写在事件里)

DataWindow 的事件是"活"的入口,最常用两个:


事件触发时机典型用途
itemchanged用户改完一个单元格、值被接受时校验、联动计算
itemerror单元格输入非法(类型不符)时提示用户改错位置
row**hanged当前行切换时联动明细、刷新状态栏
dberror数据库操作出错时统一错误处理


事件脚本的返回值很有讲究:itemchanged 返回 0 表示接受输入,返回 2 表示拒绝并让光标留在原地。


// 这是 dw_1 的 itemchanged 事件脚本(在数据窗口控件上双击事件写)
// data 是用户刚输入的新值(还没写进缓冲区);dwo 是列对象
if dwo.name = "salary" then
    if not IsNumber(string(data)) then
      MessageBox("校验", "薪资必须是数字")
      return 2                  // 2=拒绝输入,光标留在该格
    end if
end if
return 0                            // 0=接受,写入缓冲区


第七步:DataStore——没有界面的 DataWindow

DataStore 是没有可视界面的 DataWindow,用来做后台批量处理、导入导出。用法几乎一样,只是要自己 create / destroy。


// 按钮 cb_batch 的 clicked 事件:后台批量读取处理
datastore lds
lds = create datastore
lds.DataObject = "d_employee"       // 指向同一个 DataWindow 对象
lds.SetTransObject(SQLCA)
long ll_cnt
ll_cnt = lds.Retrieve()

// 逐行读出来处理(循环变量先声明)
integer li_i
string ls_name
for li_i = 1 to ll_cnt
    ls_name = lds.GetItemString(li_i, "name")
    // 这里做你的业务处理,比如拼字符串、写日志
next

// 整表数据导出为文本 / 从文件导入
string ls_all
ls_all = lds.Object.DataWindow.Data   // 全部数据:制表符分隔的文本
lds.ImportFile("C:\data\list.csv")    // 从 CSV 导入

destroy lds

MessageBox("DataStore", "后台处理 " + String(ll_cnt) + " 行,导出文本长度 " + String(Len(ls_all)))


小结:一条链路,四个要点

DataWindow 入门就是记住"连接 → 取数 → 编辑 → 保存"这条链路,以及四个易错点:


[*]先 SetTransObject 再 Retrieve,顺序反了必然报错;
[*]保存前先 AcceptText,否则正在编辑的那个格子会丢修改;
[*]Update 成功要 COMMIT,失败要 ROLLBACK,否则数据会处于"改了又没完全改"的悬空状态;
[*]DeleteRow 只是把行放进删除缓冲区,没点保存前数据库一行都没动——这也是 DataWindow 三缓冲区的妙处(详见 Day1 文章)。


把这四个要点和上面的速查表记住,DataWindow 的日常开发就不会再发怵。
页: [1]
查看完整版本: PowerBuilder DataWindow 入门:从取数到保存的一条完整链路

免责声明:
本站所发布的一切破解补丁、注册机和注册信息及软件的解密分析文章仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负。本站信息来自网络,版权争议与本站无关。您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。如果您喜欢该程序,请支持正版软件,购买注册,得到更好的正版服务。如有侵权请邮件与我们联系处理。

Mail To:Admin@SybaseBbs.com