STTTable 是由表头、表体和滚动容器组成的复合控件,可显示 TTable/TTableView/T_RCP,并内置采样、事件、报警、操作日志、查询和配方处理。
推荐使用强类型 Column:
vector<STTTable::Column> cols = {
{"STIME", "时间", 150, 0},
{"TEMP", "温度", 100, 1},
{"PRESS", "压力", 100, 2}
};
STTTable* table = new STTTable(getRuntime(), this, "sampleTable");
table->setMainArg(10, 40, 450, 210, cols, 10, false, 1);
Column 字段:key 必须与数据源列名一致,label 是表头,width 是像素宽度,fac 是数值小数位。
字符串形式等价写法:
table->setMainArg(10, 40, 450, 210,
"STIME,时间,150;TEMP,温度,100,1;PRESS,压力,100,2",
10, false, 1);
每列格式严格为 key,label,width[,fac],列间用 ; 分隔。任一列少于 3 项时函数直接返回,且没有错误返回值。不要在标签中直接放逗号或分号。
tabletype:0 实时采样、1 历史采样、2 事件、3 报警、4 配方、5 操作日志、6 数据查询、15 未指定。它会影响时间、事件类别和级别的格式化。
注意:vector 重载头文件中的 rowcnt 说明有歧义;实现直接把它设为表体数据行数,不含表头。
table->setHeadCellStyle(0x2f5597, 0x203864, 1,
1, 0xffffff, 6, 6, 4, 4,
0xffffff, 16, "", 0);
table->setDataCellStyle(0xffffff, 0xf6f8fb, 1,
1, 0xd0d0d0, 5, 5, 4, 4,
0x202020, 15, "", 0);
table->setSelCellStyle(0xdcecff, 0xb8d8ff, 1,
1, 0x4f81bd, 5, 5, 4, 4,
0x000000, 15, "", 0);
三个方法参数顺序一致:背景起止色、渐变方向、边框宽/色、上下左右 padding、字体色/大小/名称/字形。实现中三种样式共享单元格 padding,最后一次调用的 padding 会覆盖前面设置。
setColorMode(0) 使用渐变,setColorMode(1) 使用隔行配色。样式修改会触发表头/表体重绘。
table->setRowCnt(20)
->setColWidth(1, 120)
->setCellValue(0, 0, "第一条")
->addCellCtrl(0, 0, 1);
table->setHeaderText(1, "当前温度", 2);
string title = table->getHeaderText(1);
setRowCnt(cnt):设置表体行数。setColWidth(col, width):同时修改表头和表体。setCellValue(row, col, text):row 是表体索引,0 表示第一条数据。addCellCtrl(row, col, ctrl):这里的 row 是整个表索引,0 是表头,1 才是第一条数据;默认 ctrl=1 表示向右合并相同内容。setHeaderText:frac >= 0 时同时更新该列小数位。getHeaderText:索引非法时按实现返回空串。这两个 row 语义不同,最容易出现偏一错误。
TTable* data = table->getData();
if (data) {
// 使用 TTable 接口填充,再触发其值变化通知
}
Ivariable source = vm->get("Runtime.ResultTable");
if (source) table->bindData(source);
table->disBindData(); // 解绑并切回控件自带 TTable
bindData 仅接受类型为 T_TABLE、T_TABLEVIEW 或 T_RCP 才能正常显示。绑定 TTableView 时会把 page size 设置为当前表体行数。getData() 仅在当前绑定是上述表类型时返回指针。
shared_ptr 重载只调用 .get(),不会保留共享所有权。bindData(nullptr) 不会解绑旧对象,必须调用 disBindData()。onDataChanged 是内部刷新入口,不应手动调用。
table->setSelected(2); // 第 3 条数据,不触发点击事件
int row = table->getSelectedRow();
int col = table->getSelectedCol();
table->setCellAlign(-1, 0, 2); // 所有行第 0 列居中
int align = table->getCellAlign(0, 0);
table->setCellDoubleClickDisable(-1, -1, true);
bool disabled = table->getCellDoubleClickDisable(0, 0);
table->enableDrag();
table->setClickable(true);
table->setEnable(true);
setCellAlign 的 row/col < 0 表示全部,对齐值 1/2/3 为左/中/右。setCellDoubleClickDisable 同样支持负数通配。查询接口应传实际单元格索引,不要依赖负数。
enableDrag 开启拖拽;setClickable 控制点击,setEnable 控制整体使能。setSelected 不检查业务数据是否存在,调用者应限制在 0..getRecordCnt()-1。
table->setPageSize(20);
table->navFirst();
table->navNext();
table->navBack();
table->navLast();
int page = table->getPageIndex();
int pages = table->getPageCnt();
int pageSize = table->getPageSize();
int records = table->getRecordCnt();
分页只对 TTableView/历史数据等分页源有效;实时采样内存 TTable 和配方表不使用这些导航。无兼容数据源时查询通常返回 0,导航不产生效果。
可把分页状态写入变量:
table->bindPageSize(vm->get("UI.PageSize"));
table->bindRecordCnt(vm->get("UI.RecordCount"));
table->bindPageIndex(vm->get("UI.PageIndex"));
table->bindPageCnt(vm->get("UI.PageCount"));
这些变量由表格更新,必须可写且持续有效。
历史采样:
table->setDataSource("1", "20261020", true);
table->setDateMode(2); // 日期+时间
setDataSource(sampleid, yyyymmdd, isDesc):采样 ID 为空时解除来源;日期为空表示今天实时数据。isDesc=true 倒序。
事件/报警:
table->setDataSourceOfEvent("20261001", "20261020",
true, 0, 99, 1 | 2 | 4 | 8, true);
bool warning = table->isWarningTable();
类别范围常用 0..99,级别是位掩码。实现只对 20000101..29990101 做简单日期范围判断,不验证真实日历日期。
日期控制:
table->bindHistoryDate(vm->get("UI.StartDate"));
table->bindHistoryDate2(vm->get("UI.EndDate"));
table->setHistoryDate(20261001, 20261020);
table->setDateMode(0); // 0时间,1日期,2日期+时间
bindHistoryDate2 主要对事件范围有效。更改日期会重新绑定数据并更新分页变量,可能涉及数据库 I/O,不要高频修改。
onHistoryDateChanged、onHistoryDate2Changed 和 onLanguageChanged 虽出现在类声明中,但属于框架信号处理函数;业务代码不应直接调用。invalidateThis、invalidateTableHead、invalidatePanelBody、invalidateTableBody 是私有布局刷新函数,应通过公开样式/数据接口触发。
table->addCustomColor(true, false, 2, 1, 0xffdddd); // 表体背景
table->addCustomColor(true, true, 2, 1, 0xaa0000); // 表体文字
table->invalidate();
uint32_t color = 0;
if (table->getCustomColor(true, false, 2, 1, color)) {
// color 有效
}
table->removeCustomColor(true, false, 2, 1);
table->clearCustomColor(true, true);
isbody=false/true 表示表头/表体,isfg=false/true 表示背景/文字。增删后必须显式 invalidate()。内部 key 用 (row << 16) | col,行列应限制在 16 位范围内。
if (table->rcpBind("ProductRecipe")) {
table->editRCPCell(0, 1);
table->rcpAdd();
table->rcpInsert();
table->rcpCopy();
table->moveUp();
table->moveDown();
table->rcpSave();
}
editRCPCell(r,c):编辑表体单元格;第 0 列/键为 LID 的列不可编辑,未绑定变量的列也无效。rcpAdd、rcpInsert、rcpCopy、rcpDel:新增、插入、复制、删除。rcpSave:保存当前配方。moveUp / moveDown:交换选中行。rcpBind(name):等价于配方管理器绑定。导入导出:
bool ok1 = table->rcpExportAs("backup/ProductRecipe.csv");
bool ok2 = table->rcpImport("backup/ProductRecipe.csv");
模拟器路径相对 ./data/,真机路径相对 U 盘根目录;子目录必须预先存在。导入会改变当前配方数据,应先确认文件来源并做好备份。
bool ok = table->exportCSV2UDisk();
导出内容由 tabletype 和绑定源决定:实时采样导出内存,历史采样导出绑定日期,事件/报警/日志/查询导出相应结果,配方使用 rcp_xx.csv。该接口内部自行选择 U 盘/模拟器目录和文件名,返回值只表示本次流程结果。
导出可能包含数据库查询和存储写入,不要在短周期定时器中重复调用;U 盘拔出、空间不足、只读文件系统都可能失败。
void Frm01::initHistoryTable() {
vector<STTTable::Column> cols = {
{"STIME", "采样时间", 180, 0},
{"TEMP", "温度", 120, 1},
{"PRESS", "压力", 120, 2}
};
history = new STTTable(getRuntime(), this, "history");
history->setMainArg(20, 50, 440, 190, cols, 12, false, 1);
history->setDateMode(2);
history->setDataSource("1", "20261020", true);
}
key 必须与数据源完全一致。setDataSource 当前实现会直接访问已有 bindVar,不要在对象未完整构造或绑定已失效时调用。setDataSource("") 先解除旧 TTableView 后返回,不会自动恢复自带表;需要普通表时调用 disBindData()。T_RCP 刷新会把显示行数改为实际配方行数,先前的 setRowCnt 可能被覆盖。getData()、分页变量、表格指针都由框架管理,不要 delete,也不要在控件销毁后保存。