Chapter 183 · XUI 专业控件

TimelineView 时间轴

动画/视频编辑时间轴:图层/帧/Span 区间、帧率、标尺、选区、回调。

183

概念

TimeLineView(注意大写 L)是专业时间轴控件:
• Layer:图层(轨道),可命名/着色/锁定/隐藏
• Frame:帧格子,可设置关键帧类型和 UserData
• Span:时间区间(片段),有起止帧和标签
• Ruler:顶部帧标尺
• Selection:帧/区间选择
注意:函数名为 xuiTimeLineView*(大写 L),desc 为 xui_timeline_view_desc_t。

API 速查

函数说明
int xuiTimeLineViewCreate(pCtx, ppW, pDesc)创建时间轴
int xuiTimeLineViewSetFrameCount(pW, iCount)总帧数
int xuiTimeLineViewSetFrameRate(pW, fRate)帧率
int xuiTimeLineViewSetCurrentFrame(pW, iFrame)当前帧
int xuiTimeLineViewAddLayer(pW, sName, pLayer)添加图层
int xuiTimeLineViewSetFrame(pW, iLayer, iFrame, iType, pUser)设置关键帧
int xuiTimeLineViewAddSpan(pW, iLayer, iStart, iEnd, iType, sLabel, pId)添加 Span
int xuiTimeLineViewSetMetrics(pW, fHeaderW, fFrameW, fRowH, fRulerH)尺寸配置
int xuiTimeLineViewSetColors(pW, pColors)颜色配置

编译本章示例

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

示例:动画时间轴

xui_timeline_view_desc_t desc = { 0 };

xui_widget pTimeline;
xuiTimeLineViewCreate(pCtx, &pTimeline, &desc);

// 24fps,120 帧
xuiTimeLineViewSetFrameRate(pTimeline, 24.0f);
xuiTimeLineViewSetFrameCount(pTimeline, 120);

// 添加图层
int iPosLayer, iAlphaLayer;
xuiTimeLineViewAddLayer(pTimeline, "Position", &iPosLayer);
xuiTimeLineViewAddLayer(pTimeline, "Alpha", &iAlphaLayer);

// 设置关键帧
xuiTimeLineViewSetFrame(pTimeline, iPosLayer, 0, 1, NULL);
xuiTimeLineViewSetFrame(pTimeline, iPosLayer, 60, 1, NULL);

// 添加动画片段
int iSpan;
xuiTimeLineViewAddSpan(pTimeline, iAlphaLayer,
    10, 50, 0, "FadeIn", &iSpan);

// 当前帧
xuiTimeLineViewSetCurrentFrame(pTimeline, 0);

完整代码

将以下代码保存为 ch183_main.c,编译后运行即可看到动画时间轴编辑器:

#include "xge.h"
#include "xui.h"

static xui_context g_pCtx;

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x1E1E1EFF);
    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 = 900; d.iHeight = 400;
    d.sTitle = "ch183 - TimeLineView";
    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, 900, 400);

    // 创建时间轴
    xui_timeline_view_desc_t tdesc = { 0 };
    xui_widget pTL;
    xuiTimeLineViewCreate(g_pCtx, &pTL, &tdesc);

    // 24fps,120 帧
    xuiTimeLineViewSetFrameRate(pTL, 24.0f);
    xuiTimeLineViewSetFrameCount(pTL, 120);

    // 添加图层
    int iPos, iAlpha;
    xuiTimeLineViewAddLayer(pTL, "Position", &iPos);
    xuiTimeLineViewAddLayer(pTL, "Alpha", &iAlpha);

    // 设置关键帧
    xuiTimeLineViewSetFrame(pTL, iPos, 0, 1, NULL);
    xuiTimeLineViewSetFrame(pTL, iPos, 60, 1, NULL);
    xuiTimeLineViewSetFrame(pTL, iPos, 120, 1, NULL);

    // 添加动画片段
    int iSpan;
    xuiTimeLineViewAddSpan(pTL, iAlpha,
        10, 50, 0, "FadeIn", &iSpan);

    xuiTimeLineViewSetCurrentFrame(pTL, 0);

    xui_widget pRoot = xuiGetRootWidget(g_pCtx);
    xuiWidgetAddChild(pRoot, pTL);
    xuiWidgetSetRect(pTL, (xui_rect_t){0, 0, 900, 400});

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

代码讲解

  • TimeLineViewCreate:创建时间轴控件(注意函数名大写 L)。
  • SetFrameRate + SetFrameCount:配置帧率和总帧数,决定标尺刻度。
  • AddLayer:添加动画轨道(图层),返回图层索引。
  • SetFrame:在指定图层/帧设置关键帧标记。
  • AddSpan:添加连续时间区间(动画片段),有起止帧和标签。

要点与陷阱

  • 大写 L:函数名 xuiTimeLineView*(非 xuiTimeLineView*)。
  • Frame vs Span:Frame 是单帧标记,Span 是连续区间。
  • 回调:SetFrameCallbacks/SetSpanCallbacks 监听编辑变化。
  • 自定义渲染:SetRenderers 可覆盖帧/Span/图层/标尺渲染。

进阶练习

  1. 动画播放器:时间轴 + 播放按钮,CurrentFrame 驱动动画。
  2. 多轨道编辑:拖拽 Span 调整动画片段时序。
TimelineView 时间轴效果
图:TimelineView 时间轴渲染效果