马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?站点注册
×
PBIDEA:用 uo_chart 画出柱状图与饼图
阅读说明
1. 适用版本:PB 9 及以上(本文按 PB 12.5 + PBIDEA 1.x 验证;涉及 painter.pbl 与 websuite.pbl 两个库)
2. 支持数据库:无需数据库(示例全部使用内存 DataStore,不连接任何 DBMS)
3. 操作系统与环境要求:Windows 7+,已安装 PBIDEA 运行库(PbIdea.dll 等);应用库需包含 painter.pbl、websuite.pbl
4. 难度系数:★★☆☆☆
5. 其它阅读说明:前置知识为 DataStore 基本操作(InsertRow/SetItem);建议先看 Day 7《PBIDEA:uo_database 连接池与多库事务复用》了解 PBIDEA 库的引入方式
一、uo_chart 是什么
PBIDEA 的 painter.pbl 里放着一个自绘图表控件 uo_chart。它不依赖任何第三方 ActiveX/OCX,本质是一个 UserObject,通过 ue_paint 事件用 GDI 把图表直接画在窗口上,底层由 websuite.pbl 的 uo_painter(封装 PbIdea.dll)提供画板能力。
它内置 11 种图表类型,通过属性 is_charttype 切换:
| is_charttype | 图表 | is_charttype | 图表 | | line | 折线图 | npie | 南丁格尔玫瑰图 | | bar | 柱状图 | percent | 百分比环形图 | | area | 面积图 | scatter | 散点图 | | pie | 饼图(可环形) | radar | 雷达图 | | barline | 柱线混合 | guage | 仪表盘 | | h_bar | 横向柱状图 | | |
控件创建(constructor)时自动执行 uf_init():创建内部画板 uo_painter p、注册画布事件、并在程序目录建 chart 文件夹,不需要你手动初始化。
二、喂数据:uf_setdata(DataStore)
uo_chart 只有一个主要的数据入口——把 DataStore 传给它:调用 uo_chart_1.uf_setdata(ids) 返回 boolean,数据为空(RowCount < 1 或列数 < 1)时返回 false。
数据约定很关键,务必按这个结构准备 DataStore:
- 第 1 列:每行的分组名(柱状图横轴上的组名、图例名);
- 第 2 列起:数值系列。系列名取数据窗口里该列的列头文本,命名规则是"列名 + 下划线 t",例如列名 c1,列头文本控件就叫 c1_t(painter.pbl 自带的 d_chart_demo 就是这么命名的:c1_t 文本为"周一"、"c2_t"为"周二"……);
- 数据为空(RowCount < 1 或列数 < 1)时返回 false。
柱状图多行多列 = 多组 × 多系列(自动堆叠);饼图一行多列 = 每个数值列一个扇区,扇区名取各列列头文本。
三、示例 1:窗口内画柱状图
前置:① 应用库列表已加入 painter.pbl、websuite.pbl;② 窗口 w_chart_demo 上放一个 UserObject 控件,命名为 uo_chart_1,对象类型选 uo_chart;③ 使用 painter.pbl 自带的数据窗口 d_chart_demo(列:legend + c1~c7,列头周一~周日)。
步骤:1) 打开窗口;2) 在按钮 cb_bar 的 clicked 事件贴入下方代码;3) 运行并点击按钮,即可看到两组 × 七个工作日的堆叠柱状图。 - // ===== 示例输入:两周销售数据(第 1 列=分组名,第 2~8 列=周一~周日)=====
- datastore ids
- ids = create datastore
- ids.DataObject = 'd_chart_demo' // painter.pbl 自带示例数据窗口
- // 第一组:本店
- ids.InsertRow(0)
- ids.SetItem(1, 'legend', '本店')
- ids.SetItem(1, 'c1', 12) // 周一
- ids.SetItem(1, 'c2', 18) // 周二
- ids.SetItem(1, 'c3', 15) // 周三
- ids.SetItem(1, 'c4', 22) // 周四
- ids.SetItem(1, 'c5', 19) // 周五
- ids.SetItem(1, 'c6', 26) // 周六
- ids.SetItem(1, 'c7', 14) // 周日
- // 第二组:分店
- ids.InsertRow(0)
- ids.SetItem(2, 'legend', '分店')
- ids.SetItem(2, 'c1', 9)
- ids.SetItem(2, 'c2', 14)
- ids.SetItem(2, 'c3', 12)
- ids.SetItem(2, 'c4', 17)
- ids.SetItem(2, 'c5', 16)
- ids.SetItem(2, 'c6', 20)
- ids.SetItem(2, 'c7', 11)
- // ===== 配置图表外观 =====
- uo_chart_1.is_charttype = 'bar' // 柱状图
- uo_chart_1.is_title = '一周销售额对比' // 主标题
- uo_chart_1.is_title1 = '(单位:千元)' // 副标题
- uo_chart_1.ib_show_dzz = false // 关闭右下角水印
- uo_chart_1.il_colorstyle = 3 // 色板 3(雅致),可选 1~14
- // ===== 喂数据 + 重绘 =====
- uo_chart_1.uf_setdata(ids)
- uo_chart_1.uf_refresh() // 立即重绘到窗口
- destroy ids
- MessageBox('完成', '柱状图已绘制:2 组 × 7 个工作日')
复制代码
四、示例 2:饼图(一行多列)
饼图的数据结构和柱状图不同:一行数据,第 2 列起每个数值列对应一个扇区,扇区名取各列列头文本。这里仍借用 d_chart_demo 演示(扇区名会显示为"周一~周四",想显示产品名,把数据窗口对应列的标题文本改成产品名即可)。
前置:同示例 1。步骤:在按钮 cb_pie 的 clicked 事件贴入下方代码,运行后点击按钮。 - // ===== 示例输入:四个产品的销量占比(一行,第 1 列占位,第 2~5 列为四个扇区值)=====
- datastore ids
- ids = create datastore
- ids.DataObject = 'd_chart_demo'
- ids.InsertRow(0)
- ids.SetItem(1, 'legend', '产品') // 占位,饼图用不到
- ids.SetItem(1, 'c1', 45) // 扇区 1(列头"周一")
- ids.SetItem(1, 'c2', 25) // 扇区 2
- ids.SetItem(1, 'c3', 18) // 扇区 3
- ids.SetItem(1, 'c4', 12) // 扇区 4
- // c5~c7 留空即 0,不参与
- // ===== 配置 =====
- uo_chart_1.is_charttype = 'pie' // 饼图
- uo_chart_1.is_title = '产品销量占比'
- uo_chart_1.ib_link = false // false=实心饼;true=环形图
- uo_chart_1.ib_show_dzz = false
- // ===== 喂数据 + 重绘 =====
- uo_chart_1.uf_setdata(ids)
- uo_chart_1.uf_refresh()
- destroy ids
- MessageBox('完成', '饼图已绘制:4 个扇区')
复制代码
五、示例 3:不依赖界面直接导出 PNG(报表出图)
做报表时经常要把图存成图片文件塞进导出文档里。uf_makechart() 可以脱离屏幕绘制:在内存画布上画完直接 SaveMemoryImage 存成文件,扩展名决定格式(png/jpg/bmp 均可)。调用前必须先 uf_setdata 喂过数据。
前置:同示例 1(窗口上需有 uo_chart_1 控件,因为对象实例化后才能创建内部画板)。步骤:在按钮 cb_export 的 clicked 事件贴入代码;先点"画柱状图"喂数据,再点本按钮。 - integer li_rc
- // ===== 示例输入:导出尺寸与文件路径 =====
- integer li_w
- integer li_h
- string ls_file
- li_w = 900
- li_h = 520
- ls_file = 'chart/sales_bar.png' // 相对程序运行目录;chart 目录由 uf_init 自动创建
- li_rc = uo_chart_1.uf_makechart(li_w, li_h, ls_file)
- if li_rc = 0 and FileExists(ls_file) then
- MessageBox('导出成功', '图片已保存:' + ls_file)
- else
- MessageBox('导出失败', '返回码:' + string(li_rc))
- end if
复制代码
六、可选:点击图表取数据
控件内置两个点击事件,可用来做"点击柱/扇区弹出明细"的交互:
| 事件 | 参数 | 含义 | | ue_on_bar | ai_row, ai_column | 点击柱子:第几组、第几列 | | ue_on_pie | ai_index | 点击扇区:第几个扇区 |
前置:窗口上已有 uo_chart_1。步骤:在 uo_chart_1 的事件列表里找到 ue_on_bar,双击进入并写入下方代码。 - // uo_chart_1 的 ue_on_bar 事件:点击柱子时触发
- MessageBox('点击了柱子', '第 ' + string(ai_row) + ' 组,第 ' + string(ai_column) + ' 列')
复制代码
七、常见坑
- 系列名取不到:数据窗口的列头文本控件必须命名为"列名_t"(如 c1 配 c1_t),否则取列头失败会回退成列名显示;
- 饼图画不出多个扇区:饼图要用"一行多列",扇区数 = 数值列数;用了多行数据会被最后一行覆盖;
- 图是空的:uf_setdata 返回 false 说明 DataStore 无数据或列数不足,先检查 RowCount 和列数;
- 改完数据不刷新:喂数据后必须调 uf_refresh() 才会重绘;
- scatter / percent / guage 特殊:散点图用数组版 uf_setdata(ad_x[], ad_y[]);percent/guage 可用 uf_setdata(ad_v[], as_legend[]),其余类型都走 DataStore 版;
- 水印与配色:ib_show_dzz 关闭水印;il_colorstyle 1~14 切换色板;柱状图 ib_stack=false 可取消堆叠、ib_3dbar=true 可开 3D。
小结
uo_chart 的核心用法只有三步:准备 DataStore(注意列头命名)→ uf_setdata 喂数据 → uf_refresh 重绘;需要图片文件时再用 uf_makechart 导出。理解了"第 1 列分组名、第 2 列起数值系列"这个约定,柱状图、饼图、折线图、雷达图等 11 种图基本都能照葫芦画瓢。下一篇继续讲 PBIDEA 的办公组件:用 uo_xlsx 读写 Excel。 |