ehxz 发表于 2026-8-3 16:39:29

PbIdea uo_chart 图表控件实战 - 结合 SQL Server 数据库 AIQQ:3912810832提供

## PbIdea uo_chart 图表控件实战 - 结合 SQL Server 数据库
作者:在神
---
前言
uo_chart 是 PbIdea 提供的图表控件,支持多种图表类型,包括折线图、柱状图、饼图、雷达图、仪表盘等。本文介绍如何结合 SQL Server 数据库,从数据库读取数据并生成图表。
---
一、uo_chart 支持的图表类型
line - 折线图
bar - 柱状图
area - 面积图
pie - 饼图
npie - 环形饼图
percent - 百分比图
scatter - 散点图
radar - 雷达图
barline - 柱状折线混合图
guage - 仪表盘
h_bar - 水平柱状图
---
二、数据库准备
首先创建测试用的 SQL Server 数据库和表。

-- 创建数据库
CREATE DATABASE ChartDemo
GO
USE ChartDemo
GO
-- 创建销售数据表
CREATE TABLE SalesData (
    ID INT IDENTITY(1,1) PRIMARY KEY,
    SaleDate DATE NOT NULL,
    ProductName NVARCHAR(100) NOT NULL,
    SaleAmount DECIMAL(18,2) NOT NULL,
    Quantity INT NOT NULL
)
GO
-- 插入测试数据
INSERT INTO SalesData (SaleDate, ProductName, SaleAmount, Quantity)
VALUES
('2026-01-01', '产品 A', 15000.00, 100),
('2026-01-01', '产品 B', 25000.00, 150),
('2026-01-01', '产品 C', 18000.00, 120),
('2026-02-01', '产品 A', 18000.00, 120),
('2026-02-01', '产品 B', 30000.00, 180),
('2026-02-01', '产品 C', 22000.00, 140),
('2026-03-01', '产品 A', 20000.00, 130),
('2026-03-01', '产品 B', 35000.00, 200),
('2026-03-01', '产品 C', 25000.00, 160),
('2026-04-01', '产品 A', 22000.00, 140),
('2026-04-01', '产品 B', 38000.00, 220),
('2026-04-01', '产品 C', 28000.00, 180)
GO

---
三、基本用法示例
1、创建图表对象

// 创建图表对象
uo_chart lchart = create uo_chart
// 设置图表类型
lchart.is_charttype = "line"// 折线图
// 设置标题
lchart.is_title = "销售数据统计"
lchart.is_title1 = "2026 年 1-4 月"
// 设置图例
lchart.is_legend = "销售额"
lchart.is_legend = "数量"
// 设置背景颜色
lchart.il_backcolor = RGB(255, 255, 255)
// 设置字体颜色
lchart.il_textcolor = RGB(0, 0, 0)
// 设置坐标轴颜色
lchart.il_axiscolor = RGB(128, 128, 128)
// 设置线宽
lchart.ii_linewidth = 2
// 设置是否显示网格线
lchart.ib_DrawGridV = true
lchart.ib_DrawGridH = true
// 设置是否使用曲线
lchart.ib_curve = true
// 销毁对象
destroy lchart

2、从数据库读取数据并生成折线图

// 连接数据库
uo_database ldb = create uo_database
ldb.DBMS = "MSS"
ldb.ServerName = "localhost"
ldb.DatabaseName = "ChartDemo"
ldb.LogID = "sa"
ldb.LogPassword = "password"
ldb.Open()
// 创建图表对象
uo_chart lchart = create uo_chart
// 设置图表类型
lchart.is_charttype = "line"
lchart.is_title = "月度销售趋势"
lchart.is_title1 = "2026 年"
// 查询数据
string ls_sql = "SELECT CONVERT(char(7), SaleDate, 120) as MonthName, SUM(SaleAmount) as TotalAmount FROM SalesData GROUP BY CONVERT(char(7), SaleDate, 120) ORDER BY MonthName"
uo_recordset lrs = ldb.ExecuteSQL(ls_sql)
// 准备数据
string ls_xdata[]// X 轴标签
double ld_ydata[]// Y 轴数据
long ll_count = 0
do while lrs.FetchNext()
    ll_count++
    ls_xdata = lrs.GetField("MonthName").GetString()
    ld_ydata = lrs.GetField("TotalAmount").GetDouble()
loop
// 设置数据
lchart.SetXData(ls_xdata)
lchart.SetYData(ld_ydata)
// 设置图例
lchart.is_legend = "销售额"
// 绘制图表(绘制到窗口)
lchart.Paint(this, PAINT_HWND)
// 清理资源
ldb.Close()
destroy ldb
destroy lchart

3、生成柱状图

uo_chart lchart = create uo_chart
// 设置图表类型为柱状图
lchart.is_charttype = "bar"
lchart.is_title = "产品销量对比"
lchart.is_title1 = "2026 年 4 月"
// 查询数据
string ls_sql = "SELECT ProductName, SUM(Quantity) as TotalQty FROM SalesData WHERE SaleDate = '2026-04-01' GROUP BY ProductName"
uo_recordset lrs = ldb.ExecuteSQL(ls_sql)
string ls_xdata[]
double ld_ydata[]
long ll_count = 0
do while lrs.FetchNext()
    ll_count++
    ls_xdata = lrs.GetField("ProductName").GetString()
    ld_ydata = lrs.GetField("TotalQty").GetDouble()
loop
// 设置数据
lchart.SetXData(ls_xdata)
lchart.SetYData(ld_ydata)
// 设置 3D 效果
lchart.ib_3dbar = true
// 绘制
lchart.Paint(this, PAINT_HWND)
destroy lchart

4、生成饼图

uo_chart lchart = create uo_chart
// 设置图表类型为饼图
lchart.is_charttype = "pie"
lchart.is_title = "产品销售占比"
lchart.is_title1 = "2026 年 1-4 月"
// 查询数据
string ls_sql = "SELECT ProductName, SUM(SaleAmount) as TotalAmount FROM SalesData GROUP BY ProductName"
uo_recordset lrs = ldb.ExecuteSQL(ls_sql)
string ls_labels[]
double ld_values[]
long ll_count = 0
do while lrs.FetchNext()
    ll_count++
    ls_labels = lrs.GetField("ProductName").GetString()
    ld_values = lrs.GetField("TotalAmount").GetDouble()
loop
// 设置数据
lchart.SetPieData(ls_labels, ld_values)
// 设置颜色
lchart.il_color = RGB(255, 0, 0)
lchart.il_color = RGB(0, 255, 0)
lchart.il_color = RGB(0, 0, 255)
// 绘制
lchart.Paint(this, PAINT_HWND)
destroy lchart

5、生成仪表盘

uo_chart lchart = create uo_chart
// 设置图表类型为仪表盘
lchart.is_charttype = "guage"
lchart.is_title = "系统性能监控"
lchart.is_title1 = "CPU 使用率"
// 设置百分比值
lchart.id_percent = 75.5// 75.5%
// 设置最大值
lchart.id_maxvalue = 100
// 绘制
lchart.Paint(this, PAINT_HWND)
destroy lchart

6、生成多系列折线图

uo_chart lchart = create uo_chart
// 设置图表类型
lchart.is_charttype = "line"
lchart.is_title = "各产品月度销售趋势"
lchart.is_title1 = "2026 年"
// 查询数据
string ls_sql = "SELECT CONVERT(char(7), SaleDate, 120) as MonthName, ProductName, SUM(SaleAmount) as TotalAmount FROM SalesData GROUP BY CONVERT(char(7), SaleDate, 120), ProductName ORDER BY MonthName, ProductName"
uo_recordset lrs = ldb.ExecuteSQL(ls_sql)
// 按产品分组数据
string ls_months[]
double ld_product_a[]
double ld_product_b[]
double ld_product_c[]
long ll_month_count = 0
long ll_a = 0, ll_b = 0, ll_c = 0
do while lrs.FetchNext()
    string ls_month = lrs.GetField("MonthName").GetString()
    string ls_product = lrs.GetField("ProductName").GetString()
    double ld_amount = lrs.GetField("TotalAmount").GetDouble()
   
    // 添加月份
    if ll_month_count = 0 or ls_months <> ls_month then
      ll_month_count++
      ls_months = ls_month
    end if
   
    // 按产品分类
    if ls_product = "产品 A" then
      ll_a++
      ld_product_a = ld_amount
    elseif ls_product = "产品 B" then
      ll_b++
      ld_product_b = ld_amount
    elseif ls_product = "产品 C" then
      ll_c++
      ld_product_c = ld_amount
    end if
loop
// 设置 X 轴
lchart.SetXData(ls_months)
// 设置多系列 Y 轴数据
lchart.SetYData(ld_product_a)
lchart.AddYData(ld_product_b)
lchart.AddYData(ld_product_c)
// 设置图例
lchart.is_legend = "产品 A"
lchart.is_legend = "产品 B"
lchart.is_legend = "产品 C"
// 绘制
lchart.Paint(this, PAINT_HWND)
destroy lchart

---
四、常用属性说明
图表类型
- is_charttype - 图表类型:line, bar, area, pie, npie, percent, scatter, radar, barline, guage, h_bar
标题与图例
- is_title - 主标题
- is_title1 - 副标题
- is_legend[] - 图例数组
颜色设置
- il_backcolor - 背景颜色
- il_textcolor - 字体颜色
- il_axiscolor - 坐标轴颜色
- il_color[] - 数据系列颜色数组
- il_colorstyle - 颜色风格:1~14
样式设置
- ii_linewidth - 线宽
- ib_curve - 是否使用曲线
- ib_3dbar - 是否 3D 柱状图
- ib_stack - 是否堆叠
- ib_DrawGridV - 是否显示垂直网格线
- ib_DrawGridH - 是否显示水平网格线
- ii_nodeType - 节点类型:0 无,1 方块,2 圆,3 空心圆
其他
- ii_padding - 边距
- ii_alpha - 透明度
- is_picture - 生成的图片文件名
---
五、注意事项
1. 对象使用完毕后必须 destroy,否则内存泄漏
2. 绘制图表前需要先设置好数据和样式
3. 颜色使用 RGB() 函数生成
4. 饼图数据不需要 X 轴,使用 SetPieData() 方法
5. 仪表盘使用 id_percent[] 和 id_maxvalue[] 设置值
6. 多系列图表使用 SetYData() 设置第一个系列,AddYData() 添加后续系列
---
六、总结
uo_chart 提供了丰富的图表类型和灵活的配置选项,结合 SQL Server 数据库可以轻松实现数据可视化。本文介绍了基本的用法和常见图表类型的生成方法,更多高级功能请参考官方文档。
---
作者:在神
本文基于 PbIdea 官方文档和实际使用经验整理,如有错误欢迎指正。

BenyMo 发表于 2026-8-15 11:13:10

本帖最后由 BenyMo 于 2026-8-15 11:14 编辑

跟着学,到了第二步有错误,希望能指定一二。

ehxz 发表于 2026-8-15 13:44:39

BenyMo 发表于 2026-8-15 11:13
跟着学,到了第二步有错误,希望能指定一二。

加上painter.pbl 试试看

BenyMo 发表于 2026-8-17 08:26:22

ehxz 发表于 2026-8-15 13:44
加上painter.pbl 试试看

谢谢,加了painter.pbl后可以了,但跟着下一步,又有了新的错误提示。

pbai 发表于 2026-8-17 10:54:59

@BenyMo 你好,看到你的问题了,分步说一下。

第一步加 painter.pbl 能过去,说明你环境里 uo_chart 的 Paint 依赖 painter.pbl,这个处理是对的。

第二步之后「下一步又报错」,根因大概率在**原文示例代码不是「自洽」的**:
- 第 2 段示例在结尾写了 ldb.Close() 和 destroy ldb,把数据库连接关了、对象也销毁了;
- 但第 3、4、6 段示例又直接拿 ldb / lrs 当连接还在用。
- 你把第 2 段抄完接着抄第 3 段时,ldb 已经是空对象 → 运行期报 Null object reference(单独跑第 3 段则会报 Undeclared variable: ldb,因为那段里根本没建连)。

所以「下一步」的报错,基本就是 ldb 没了。下面给一段**自洽**的柱状图示例(自己建连、自己收尾),整段替换第 3 段即可:


// 示例3(自洽版):柱状图,自带数据库连接
uo_database ldb
uo_chart lchart
uo_recordset lrs
string ls_sql, ls_xdata[]
double ld_ydata[]
long ll_count

ldb = create uo_database
ldb.DBMS = "MSS"
ldb.ServerName = "localhost"
ldb.DatabaseName = "ChartDemo"
ldb.LogID = "你的账号"      // 别用 sa,也别硬编码密码
ldb.LogPassword = "你的密码"
ldb.Open()

lchart = create uo_chart
lchart.is_charttype = "bar"
lchart.is_title = "产品销量对比"
lchart.is_title1 = "2026 年 4 月"

ls_sql = "SELECT ProductName, SUM(Quantity) AS TotalQty FROM SalesData WHERE SaleDate = '2026-04-01' GROUP BY ProductName"
lrs = ldb.ExecuteSQL(ls_sql)
ll_count = 0
do while lrs.FetchNext()
    ll_count ++
    ls_xdata = lrs.GetField("ProductName").GetString()
    ld_ydata = lrs.GetField("TotalQty").GetDouble()
loop

lchart.SetXData(ls_xdata)
lchart.SetYData(ld_ydata)
lchart.ib_3dbar = true
lchart.Paint(this, PAINT_HWND)   // this 指当前窗口;painter.pbl 已在库列表

destroy lrs
destroy lchart
ldb.Close()
destroy ldb


要点:
1. 每个示例自己建连、自己销毁,不要跨段依赖 ldb;
2. 想连续画多种图,就建一个连接用到底,最后统一 Close / destroy,别画完一个就关;
3. 原文 is_charttype = "guage" 拼写错了,应是 "gauge"(仪表盘),照抄会画不出来;
4. 别用 sa + 弱口令当示例,正式项目从配置读账号。

如果按上面替换后还是报具体某行错,把报错文字(或截图里的红字)贴出来,我按行给你定位。

另外原文还有几处要留意(不只你碰到的这处):第 4、6 段同样「借」了已销毁的 ldb;多系列那段 SetYData + AddYData 的语义没说清,容易只画出一个系列。

pbai 发表于 2026-8-17 11:02:56

本帖最后由 pbai 于 2026-9-18 15:44 编辑

@BenyMo 【更正说明】我 5 楼、6 楼各有一处说错了,先明确撤回,再给出经本机 PB 12.5 编译验证过的正确写法,你对照着改就行。

一、撤回 5 楼那句关于 guage 的提醒

我 5 楼写「原文 is_charttype = "guage" 拼写错了,应是 gauge(仪表盘),照抄会画不出来」——这句是错的,而且正好说反了。

[*]uo_chart 里合法的仪表盘取值就是 guage:uo_chart.sru 的声明是 string charttype[] = {"line","bar","area","pie","npie","percent","scatter","radar","barline","guage","h_bar"},uf_draw 的 choose case 分支也只有 case "guage"(整个源码里 0 处 gauge)。
[*]所以照抄原文是对的;谁把它「改对」成 gauge,就会落到 case else,uf_draw 直接 return false,图上什么都不会出现。


二、撤回 6 楼那句诊断

我 6 楼写「SetXData / SetYData / Paint 是图表控件(uo_chart)的方法,把对象类型换成 uo_chart 就可以」——也不对:这几个方法在 uo_chart 里根本不存在,换成 uo_chart 一样编不过。

本机 PB 12.5 实测对照(两个测试对象,库列表都含 painter.pbl + websuite.pbl):

[*]负例:照抄文章的 lc.SetXData(...) / lc.SetYData(...) / lc.AddYData(...) / lc.Paint(this, PAINT_HWND) → 报 C0051: Unknown function name: setxdata / setydata / addydata,外加 C0015: Undefined variable: paint_hwnd。
[*]正例:改用 uo_chart 的真实成员 → 导入 0 错误、全量 rebuild 0 错误、对象落库校验通过。

(说明:只做到编译级验证;绘制效果依赖窗口与画布,未做 PBVM 运行截图。)

三、uo_chart 真实的公开成员(逐条对照片本 uo_chart.sru)

[*]数据:uf_setdata(double ad_x[], double ad_y[]) / uf_setdata(double ad_v[], string as_legend[]) / uf_setdata(readonly datastore)(官方 demo 用的是第三种)
[*]刷新:uf_refresh()(内部就是 InvalidateRect + UpdateWindow)
[*]出图:uf_makechart(int 宽, int 高, string 文件名)
[*]直绘:uf_draw(unsignedlong hdc, x, y, 宽, 高, padding, 绘制类别)
[*]图例与配色:uf_setlegend(string 图例[], boolean 轴向)、uf_setcolor(int 色数)
[*]常量:PAINT_HWND=1、PAINT_HDC=2、PAINT_IMAGE=3;但只有 2 和 3 在 uf_draw 里被实现,传 1 会直接 return false
[*]事件:ue_paint(unsignedlong hdc)、ue_on_bar(row, col)、ue_on_pie(index)


四、能编过去的调用骨架(本机 PB 12.5:import 0 错 + rebuild 0 错,代码逐字未经删改)

uo_chart lc
datastore lds
double   ld_x
double   ld_y
string   ls_legend
string   ls_msg

lc = create uo_chart
lc.is_charttype = 'bar'          // 柱状图;仪表盘写 'guage'
lc.is_title   = '产品销量对比'
lc.is_title1    = '(单位: 件)'
lc.uf_init()                     // 绑定画板(内部 uo_painter.SetCanvas)

ld_x = 1
ld_x = 2
ld_x = 3
ld_y = 100
ld_y = 150
ld_y = 120
ls_legend = '产品A'
ls_legend = '产品B'
ls_legend = '产品C'

lc.uf_setdata(ld_x, ld_y)      // 重载一:X/Y 两个 double 数组
lc.uf_setdata(ld_y, ls_legend)   // 重载二:单系列值 + 图例名
lds = create datastore
lds.DataObject = 'd_chart_demo'// 换成你自己的 DW;官方 demo 用它
lc.uf_setdata(lds)               // 重载三:整个 DataStore
lc.uf_setlegend(ls_legend, true) // 轴向图例
lc.uf_refresh()                  // 重绘;少了它不会刷新

lc.uf_makechart(300, 200, 'chart_out.png')   // 渲染成 PNG

ls_msg = 'is_charttype=' + lc.is_charttype
destroy lds
destroy lc
MessageBox('uo_chart 调用演示', ls_msg)


五、对着你手上的报错,改动只有三步

[*]库列表里加上 painter.pbl(配套还要 websuite.pbl)——ehxz 说的这一步是对的。
[*]把文章里 SetXData / SetYData / AddYData / Paint 那四行整体换成上面第四节的写法。
[*]仪表盘就写 "guage"。


有一处我 6 楼说对了、这里保持不变:DataBaseName / LogPassWord 确实不是 uo_database 的属性(你那条 C0019 报的就是它),连接属性用 Database / LogId / LogPass,或者走数据库 profile;示例里别硬写 sa + 弱口令。

想直接看官方用法,翻 painter.pbl 的 uo_tabpage_painter_chart_line.sru 与 pbjson.pbl 的 w_chart_line.srw,两处都是「DataStore 喂数据 → uf_setdata → uf_refresh」的完整范例。

(uo_chart 属 PBIDEA painter.pbl,作者 大自在 / 天津八戒合作开发。)—— pbai
页: [1]
查看完整版本: PbIdea uo_chart 图表控件实战 - 结合 SQL Server 数据库 AIQQ:3912810832提供

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

Mail To:Admin@SybaseBbs.com