Chapter 149 · XUI 容器与导航

TableGrid 数据网格

TableGrid 在 TableView 基础上增加单元格编辑能力:内联编辑器、验证、提交/取消、自定义编辑器。

149

概念

TableGrid = TableView + 编辑能力:
• EditMode:单击编辑 / 双击编辑 / 按键进入
• 内联编辑器:文本输入、下拉选择、数值步进等
• Validate:提交前验证(范围、格式)
• Commit/Reject:确认或取消编辑
• Editor 回调:为特定列创建自定义编辑控件

API 速查

函数说明
int xuiTableGridCreate(xui_context pCtx, xui_widget* ppW, const xui_table_grid_desc_t* pDesc)创建数据网格
xui_widget xuiTableGridGetTableView(xui_widget pW)获取内部 TableView
int xuiTableGridSetColumns(xui_widget pW, const xui_table_view_column_t* arr, int iCount)定义列
int xuiTableGridSetAdapter(xui_widget pW, onCount, onCell, onSet, void* pUser)数据适配器
int xuiTableGridSetEditMode(xui_widget pW, int iMode)编辑模式
int xuiTableGridBeginEdit(xui_widget pW, int iRow, int iCol)开始编辑
int xuiTableGridEndEdit(xui_widget pW, int bCommit)结束编辑
int xuiTableGridSetValidate(xui_widget pW, onValidate, void* pUser)验证回调
int xuiTableGridSetEditor(xui_widget pW, onEditor, void* pUser)自定义编辑器
int xuiTableGridIsEditing(xui_widget pW)是否编辑中

编译本章示例

gcc -O2 -I. -o ch149.exe ch149_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch149.exe

示例:可编辑配置表

xui_table_grid_desc_t desc = { 0 };

xui_widget pGrid;
xuiTableGridCreate(pCtx, &pGrid, &desc);
xuiWidgetSetRect(pGrid, (xui_rect_t){0, 0, 500.0f, 350.0f});

// 列定义
xui_table_view_column_t cols[2] = {
    { "参数名", 200.0f, 0, 0 },
    { "值",     250.0f, 0, 0 },
};
xuiTableGridSetColumns(pGrid, cols, 2);

// 双击进入编辑
xuiTableGridSetEditMode(pGrid, 1);

// 数据适配器(含 onSet 写回)
xuiTableGridSetAdapter(pGrid, OnCount, OnCell, OnSet, pAppData);
xuiTableGridSetValidate(pGrid, OnValidate, NULL);
xuiTableGridSetChange(pGrid, OnChange, NULL);

xuiWidgetAddChild(pParent, pGrid);

完整代码

将以下代码保存为 ch149_main.c,编译后运行即可看到可编辑网格效果:

#include "xge.h"
#include "xui.h"
#include <stdio.h>
#include <string.h>

static xui_context g_pCtx;
static char g_data[4][2][32] = {
    { "分辨率", "1920x1080" },
    { "音量",   "80" },
    { "语言",   "中文" },
    { "主题",   "暗色" },
};

static int onCount(void* p) { (void)p; return 4; }
static const char* onCell(int r, int c, void* p) {
    (void)p; return g_data[r][c];
}
static void onSet(int r, int c, const char* s, void* p) {
    (void)p; strncpy(g_data[r][c], s, 31);
}

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);
    float mx, my;
    xgeMouseGet(&mx, &my);
    xuiInputPointerMove(g_pCtx, mx, my);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, 0);
    else
        xuiInputPointerUp(g_pCtx, 0);
    xuiUpdate(g_pCtx, xgeGetDelta());
    xuiLayout(g_pCtx);
    xuiRender(g_pCtx, NULL, NULL, 0);
    return XGE_OK;
}

int main(void) {
    xge_desc_t d = { 0 };
    d.iWidth = 800; d.iHeight = 600;
    d.sTitle = "ch149 - TableGrid";
    d.iFlags = XGE_INIT_VSYNC;
    xgeInit(&d);

    xuiCreate(&g_pCtx);
    extern const xui_proxy_t tXgeProxy;
    xui_proxy_t tXgeProxy = xuiProxyXge();
xuiSetProxy(g_pCtx, &tXgeProxy);
    xuiSetViewportSize(g_pCtx, 800, 600);

    xui_widget pRoot;
    xuiWidgetCreate(g_pCtx, &pRoot);
xuiWidgetSetLayoutType(pRoot, XUI_LAYOUT_COLUMN);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 800, 600});
    xuiWidgetSetPadding(pRoot, 40, 40, 40, 40);
    xuiSetRootWidget(g_pCtx, pRoot);

    /* 创建数据网格 */
    xui_table_grid_desc_t gd = { 0 };
    xui_widget pGrid;
    xuiTableGridCreate(g_pCtx, &pGrid, &gd);
    xuiWidgetSetRect(pGrid, (xui_rect_t){0, 0, 500, 300});
    xuiWidgetAddChild(pRoot, pGrid);

    xui_table_view_column_t cols[2] = {
        { "参数", 200.0f, 0, 0 },
        { "值",   250.0f, 0, 0 },
    };
    xuiTableGridSetColumns(pGrid, cols, 2);
    xuiTableGridSetEditMode(pGrid, 1);
    xuiTableGridSetAdapter(pGrid, onCount, onCell, onSet, NULL);

    xgeRun(onFrame, NULL);
    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • Adapter 三回调:onCount 返回行数,onCell 读取单元格,onSet 写回编辑结果。
  • EditMode=1:双击单元格进入编辑状态。
  • 数据源:用全局数组存储配置,编辑后直接写回。
  • GetTableView:可获取内部 TableView 调用排序/选中等 API。

要点与陷阱

  • GetTableView:可获取内部 TableView 调用排序/选中等只读 API。
  • onSet 回调:Adapter 的第三个回调负责将编辑结果写回数据源。
  • Validate:返回非零拒绝提交,编辑器保持打开状态。
  • Editor 回调:为下拉列创建 ComboBox,为数值列创建 NumericInput。
  • CommitCount/RejectCount:统计提交/拒绝次数用于脏检测。

进阶练习

  1. Excel 风格网格:Tab 键切换编辑单元格,Enter 提交并下移。
  2. 条件格式:CellRenderer 中根据值范围显示不同背景色。
TableGrid 数据网格效果
图:TableGrid 数据网格渲染效果