Chapter 193 · XUI 高级机制

资源管理

XUI 资源系统:Surface/Font/Style 注册、引用计数、依赖追踪、按名查找。

193

概念

XUI 资源系统管理 Surface、Font、Style 等共享资源:
• Resource:统一资源句柄,支持按名注册/查找
• 引用计数:AddRef/Release 控制生命周期
• 依赖:资源间可声明依赖关系,释放时级联处理
• 按名查找:ResourceFind 通过字符串名获取已注册资源
避免重复加载,多处共享同一纹理/字体/样式。

API 速查

函数说明
int xuiResourceSet(pCtx, ppRes, pDesc)注册/更新资源
xui_resource xuiResourceFind(pCtx, sName)按名查找
int xuiResourceRemove(pRes)移除资源
int xuiResourceAddRef(pRes)增加引用
int xuiResourceRelease(pRes)释放引用
int xuiResourceAddDependency(pRes, pDep)添加依赖

编译本章示例

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

示例:注册与共享纹理资源

// 注册纹理资源
xui_resource_desc_t tResDesc = { 0 };
tResDesc.sName = "icon.save";
tResDesc.iType = XUI_RESOURCE_SURFACE;
tResDesc.pSurface = pSaveIcon;

xui_resource pRes;
xuiResourceSet(pCtx, &pRes, &tResDesc);

// 其他控件按名查找复用
xui_resource pFound = xuiResourceFind(pCtx, "icon.save");
if (pFound) {
    xuiResourceAddRef(pFound);
    // 使用资源...
    xuiResourceRelease(pFound);
}

// 声明依赖:按钮依赖图标
xuiResourceAddDependency(pBtnResource, pRes);

// 不再需要时移除
xuiResourceRemove(pRes);

完整代码

将以下代码保存为 ch193_main.c,编译后运行即可看到资源注册、查找与引用计数管理效果:

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

static xui_context g_pCtx;
static xui_widget g_pStatus;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x1a1a2e);
    xui_vec2_t pos;
    xgeMouseGet(&pos.x, &pos.y);
    xuiInputPointerMove(g_pCtx, pos.x, pos.y);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, pos.x, pos.y, 0);
    else
        xuiInputPointerUp(g_pCtx, pos.x, pos.y, 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 = 640; d.iHeight = 480;
    d.sTitle = "ch193 - Resource Manager";
    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, 640, 480);

    xui_widget pRoot;
xuiPanelCreate(g_pCtx, &pRoot, NULL);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 640, 480});

    /* 注册资源 */
    xui_resource_desc_t tDesc = {0};
    tDesc.sName = "icon.app";
    tDesc.iType = XUI_RESOURCE_SURFACE;
    xui_resource pRes;
    xuiResourceSet(g_pCtx, &pRes, &tDesc);

    /* 查找并引用 */
    xui_resource pFound = xuiResourceFind(g_pCtx, "icon.app");
    char buf[128];
    if (pFound) {
        xuiResourceAddRef(pFound);
        sprintf(buf, "Resource 'icon.app' found & ref'd");
        xuiResourceRelease(pFound);
    } else {
        sprintf(buf, "Resource not found");
    }

    g_pStatus = xuiLabelCreate(g_pCtx, &g_pStatus, NULL);
xuiWidgetAddChild(pRoot, g_pStatus);
    xuiLabelSetText(g_pStatus, buf);
    xuiWidgetSetRect(g_pStatus, (xui_rect_t){160, 200, 320, 32});
    xuiWidgetSetRect(g_pStatus, (xui_rect_t){0, 0, 320, 32});

    xgeRun(onFrame, NULL);

    /* 清理:移除资源 */
    xuiResourceRemove(pRes);

    xuiDestroy(g_pCtx);
    xgeUnit();
    return 0;
}

代码讲解

  • 资源注册:xuiResourceSet 以名称注册资源,同名覆盖实现热更新。
  • 查找复用:xuiResourceFind 按名查找,多处控件可共享同一资源。
  • 引用计数:AddRef/Release 成对使用,计数归零时资源自动释放。
  • 生命周期:程序退出前调用 xuiResourceRemove 显式移除注册资源。

要点与陷阱

  • 命名规范:建议 "category.name" 格式(如 "icon.save"、"font.main")。
  • 引用计数:Find 后 AddRef,用完 Release,避免悬空或泄漏。
  • 依赖:释放父资源时自动释放依赖资源,防止循环依赖。
  • 热更新:ResourceSet 同名资源会覆盖旧资源,实现运行时换肤。

进阶练习

  1. 换肤系统:注册两套 Surface 资源,运行时切换名称前缀。
  2. 资源统计:遍历所有已注册资源,输出内存占用报告。
资源管理效果
图:资源管理渲染效果