在PowerBuilder里手写Excel导出------OLE控制Excel的完整方案
PB没有
Workbook.Save(),没有Sheet.setCellValue()。要做Excel导出,只能通过OLE自动化去操控Windows上的Excel程序。这篇文章记录了一套完整的PB Excel导出工具------从DataWindow取数据、创建Sheet、写单元格、控制字体和边框、合并单元格、自动调整列宽。
文章目录
一、PB导出Excel的三种路子
PowerBuilder没有原生的Excel操作库,能选的路有三条:
| 方案 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| OLE自动化 | 操控Excel COM对象 | 功能最全------字体、边框、合并单元格都能控 | 依赖Excel安装,性能差 |
| 写CSV | FileWrite() 写逗号分隔文件 |
最快,零依赖 | 没有格式,列宽不能控,逗号冲突 |
| 第三方库 | 引入外部的OLE DB或OCX | 功能中等 | 部署麻烦,PB版本兼容性差 |
实际项目里三种都用过。OLE自动化是主方案------政府项目里每台电脑都装了Office,Excel肯定有,依赖不是问题。CSV做快速导出,不需要格式的场景用。
二、OLE自动化------操控Excel进程
powerbuilder
// nv_excel - Excel导出核心类
OLEObject iole_excel // Excel应用程序对象
OLEObject iole_workbook // 工作簿
OLEObject iole_sheet // 当前工作表
int ii_row // 当前写入行号
// 创建Excel实例
public function of_create returns boolean
iole_excel = create OLEObject
try
iole_excel.ConnectToNewObject("Excel.Application")
iole_excel.Visible = false // 后台运行,不弹Excel窗口
iole_excel.DisplayAlerts = false // 不弹保存提示
return true
catch (Exception e)
messagebox("错误", "无法启动Excel,请确认Office已安装")
return false
end try
end function
// 新建工作簿
public subroutine of_newworkbook()
iole_workbook = iole_excel.Workbooks.Add()
iole_sheet = iole_workbook.Worksheets(1)
end subroutine
// 设定导出范围
public subroutine of_setrange(string as_range)
ii_row = 1
end subroutine
// 填充一行数据
public subroutine of_writerow(any aa_data[])
int i
for i = 1 to upperbound(aa_data)
iole_sheet.cells(ii_row, i).value = string(aa_data[i])
next
ii_row++
end subroutine
// 保存并关闭
public function of_saveas(string as_path) returns boolean
try
iole_workbook.SaveAs(as_path, -4143) // xlWorkbookNormal
iole_workbook.Close()
iole_excel.Quit()
destroy iole_sheet
destroy iole_workbook
destroy iole_excel
return true
catch (Exception e)
return false
end try
end function
核心是用 OLEObject.ConnectToNewObject("Excel.Application") 启动Excel进程。从此刻起,对这个OLE对象的任何方法调用都等价于在VBA里写代码。cells(ii_row, i).value 就是在Excel中往第N行第M列写数据------完全和VBA的语法一致。
三、从DataWindow导出------表头+数据+格式
powerbuilder
// of_exportdw------把DataWindow的数据导出到Excel
public subroutine of_exportdw(DataWindow adw, boolean ab_withheader)
string ls_colname
int li_colcount, li_rowcount, i, j
any la_data[]
// 1. 获取DataWindow行列数
li_colcount = integer(adw.Describe("DataWindow.Column.Count"))
li_rowcount = adw.RowCount()
// 2. 写表头(列名)
if ab_withheader then
for i = 1 to li_colcount
ls_colname = adw.Describe("#" + string(i) + ".Name")
la_data[i] = ls_colname
next
of_writerow(la_data)
end if
// 3. 逐行写数据
for j = 1 to li_rowcount
for i = 1 to li_colcount
ls_colname = adw.Describe("#" + string(i) + ".Name")
la_data[i] = adw.GetItemString(j, ls_colname, "", false)
next
of_writerow(la_data)
next
end subroutine
Describe("#" + string(i) + ".Name") 获取第i列的列名作为表头,GetItemString() 取每一格的数据。循环DataWindow的每一行每一列,通过OLE逐格写入Excel。
四、控制格式------字体、颜色、边框、合并
powerbuilder
// 设置表头格式
public subroutine of_formatheader(integer ai_colcount)
OLEObject lrange
lrange = iole_sheet.Range(
iole_sheet.Cells(1, 1),
iole_sheet.Cells(1, ai_colcount))
// 字体:宋体 12号 加粗
lrange.Font.Name = "宋体"
lrange.Font.Size = 12
lrange.Font.Bold = true
// 背景色:浅灰
lrange.Interior.Color = RGB(220, 220, 220)
// 所有边框
lrange.Borders.LineStyle = 1 // xlContinuous
// 水平居中
lrange.HorizontalAlignment = -4108 // xlCenter
end subroutine
// 设置数据区域边框
public subroutine of_formatdataarea(integer ai_startrow, integer ai_endrow, integer ai_colcount)
OLEObject lrange
lrange = iole_sheet.Range(
iole_sheet.Cells(ai_startrow, 1),
iole_sheet.Cells(ai_endrow, ai_colcount))
lrange.Borders.LineStyle = 1
end subroutine
// 合并指定区域
public subroutine of_mergecells(integer ai_startrow, integer ai_startcol,
integer ai_endrow, integer ai_endcol)
iole_sheet.Range(
iole_sheet.Cells(ai_startrow, ai_startcol),
iole_sheet.Cells(ai_endrow, ai_endcol)).Merge()
end subroutine
// 自动调整列宽
public subroutine of_autofitcolumns(integer ai_colcount)
int i
for i = 1 to ai_colcount
iole_sheet.Columns(i).AutoFit()
next
end subroutine
// 设置某列为文本格式(防止身份证号变成科学计数法)
public subroutine of_settextformat(integer ai_col)
iole_sheet.Columns(ai_col).NumberFormat = "@"
end subroutine
完全模拟Excel VBA的API------Font.Name、Borders.LineStyle、Interior.Color、AutoFit()。PB没有这些方法,但通过OLE全都能调,因为这本质上就是VBA代码,只不过执行者是PB里的OLE对象。
第三行那个 NumberFormat = "@" 是钉在PB导出功能上最痛的一刀------身份证号、业务编码、电话号码导出到Excel后自动变成科学计数法,末尾全变成0。加了 NumberFormat = "@" 强制文本格式,才能保住所号码的原样。
五、完整导出流程------从DataWindow到xls文件
powerbuilder
// cb_export clicked 事件
Integer li_rc, li_cc
li_rc = dw_1.RowCount()
li_cc = integer(dw_1.Describe("DataWindow.Column.Count"))
if li_rc = 0 then
messagebox("提示", "没有数据可导出")
return
end if
nv_excel lex
lex = create nv_excel
if not lex.of_create() then
destroy lex
return
end if
lex.of_newworkbook()
// 写表头 + 数据
lex.of_exportdw(dw_1, true)
// 设置格式
lex.of_formatheader(li_cc) // 表头加粗灰底
lex.of_formatdataarea(2, li_rc + 1, li_cc) // 数据区域加边框
lex.of_settextformat(4) // 第4列(身份证)设文本格式
lex.of_autofitcolumns(li_cc) // 自动列宽
// 保存
string ls_path
ls_path = "D:\导出\人员信息_" + string(today(), "yyyymmdd") + ".xls"
if lex.of_saveas(ls_path) then
messagebox("完成", "文件已保存到: ~r~n" + ls_path)
else
messagebox("失败", "保存文件出错")
end if
destroy lex
从点击按钮到生成带格式的xls文件------全程PB代码,借助OLE操控Excel。速度不如CSV,但生成的表格直接可以当报表用:表头带颜色加粗、数据有边框、列宽合适、身份证号不会被截断。
六、亮点总结
✅ OLE自动化------零第三方依赖,利用Windows自带Excel
✅ 格式完整------字体、颜色、边框、合并单元格、列宽全控
✅ 防科学计数法------NumberFormat = "@" 一行解决身份证号被截断
✅ DataWindow直接导出------Describe+GetItemString 不写一行SQL
✅ 表头+数据+格式三合一------导出即报表,不需要二次加工
✅ OLE API即VBA------有VBA基础秒上手
七、适用场景
- PB老系统需要带格式的Excel导出(表头加粗、边框、合并单元格)
- 政府项目------每台电脑都有Office,OLE方案零额外部署
- DataWindow数据批量导出,不需要走数据库重新查询
八、扩展方向
- 多Sheet导出------根据不同查询条件生成多个Sheet页
- 性能优化------大批量数据改用CSV导出+后期格式化的混合方案
- 模板导出------先读一个格式已排好的xls作为模板,只填充数据不改样式
九、结语
PB没有Excel库,但Windows电脑都装了Excel。OLE自动化这条路就是利用了"操作系统自带Office"这一事实------与其引入第三方库增加部署负担,不如直接用OLE控制Excel做导出。
最大的坑不是API不会用(OLE的API就是VBA),而是列格式 ------身份证号导出变科学计数法、日期格式跟着Excel区域设置走、数字前面的0被自动去掉。每踩一个坑就是一行 NumberFormat = "@" 或一行手动格式化的代码。最后的工具类里,格式代码比导出逻辑多一倍。