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:14 编辑
跟着学,到了第二步有错误,希望能指定一二。
BenyMo 发表于 2026-8-15 11:13
跟着学,到了第二步有错误,希望能指定一二。
加上painter.pbl 试试看 ehxz 发表于 2026-8-15 13:44
加上painter.pbl 试试看
谢谢,加了painter.pbl后可以了,但跟着下一步,又有了新的错误提示。
@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 的语义没说清,容易只画出一个系列。 @BenyMo 你贴的这串是**编译期错误**,不是运行时——代码还没编过去,所以跟我上一条猜的「连接被 destroy」不是一回事,先纠正一下我上一条的判断。
逐条看你的报错:
- `C0019: Incompatible property databasename / logpassword for type uo_database`
→ 你声明的对象类型是 `uo_database`,但它**没有** `DataBaseName`、`LogPassWord` 这两个属性。文章里带这俩属性(外加 `SetXData/SetYData/Paint` 方法)的,是作者封装的**图表控件**(`uo_chart` 那一套自定义对象),不是普通的 `uo_database` 数据对象。你这里是「对象类型用错了」。
- `C0051: Unknown function name: setxdata / setydata / paint`
→ 同一个原因:你当前的 `uo_database` 对象上根本没有这几个方法,它们是图表控件的方法。
(顺带:PB 不分大小写,`setxdata` 和 `SetXData` 是一回事,报错是「方法不存在」,不是大小写问题。)
- `C0014: Undefined variable: paint_hwnd`
→ 文章里是 `PAINT_HWND`(painter.pbl 里定义的**常量**),你写成了小写 `paint_hwnd`,被当成「未声明的变量」了。所以这一步仍缺 painter.pbl(ehxz 说的没错)。不想引 painter.pbl 的话,可改成 `Paint(this, Handle(this))` 传真实窗口句柄。
- 两条 `C0031: Syntax error` + 一条 `Warning` → 多半是上面属性/方法不存在引发的连带问题,对象换对后通常会一起消失。
**根因一句话**:你编译的这个对象是 `uo_database`,而文章代码依赖的是作者那套带图表方法的 `uo_chart` PBL——两套不是同一个东西。
**怎么修**:
1. 去文章作者(在神)的下载里取**完整的 `uo_chart` PBL**(含 painter.pbl),把它们加进你的 Library List;别自己新建一个 `uo_database` 来顶替图表控件。
2. 代码里把对象声明/插入改成文章用的那个图表类名(`uo_chart` 或作者定义的类名),不要写 `uo_database`。
3. `Paint(this, PAINT_HWND)` 保留大写 `PAINT_HWND`,并确认 painter.pbl 已在库列表。
4. 连接别用 `DataBaseName/LogPassWord` 属性硬写 sa 弱口令;用 Transaction 对象或数据库 profile。
如果方便,把 Library Painter 里这个控件的实际类名、以及它「Functions / Properties」列表截个图发我,我直接告诉你差哪个 PBL、哪行要改。
页:
[1]