自定义绘制画布:即时模式绘图 API、Surface 绘制、Mesh 三角形、滚动/缩放。
Canvas 是 XUI 中的自定义绘制控件:
• 即时模式:每帧调用 Draw* 函数绘制图元
• 图元:Point/Line/Triangle/Rect/Circle/Surface/Mesh
• 画布尺寸:独立于控件大小,支持滚动/偏移
• Surface:纹理贴图绘制(Quad/自定义顶点)
适用:自定义图表、游戏地图、绘图工具、可视化编辑器。
| 函数 | 说明 |
|---|---|
int xuiCanvasCreate(pCtx, ppW, pDesc) | 创建画布 |
int xuiCanvasSetCanvasSize(pW, fW, fH) | 画布尺寸 |
int xuiCanvasClear(pW, iColor) | 清屏 |
int xuiCanvasDrawLine(pW, fX0, fY0, fX1, fY1, fW, iColor) | 线段 |
int xuiCanvasDrawRectFill(pW, tRect, iColor) | 填充矩形 |
int xuiCanvasDrawCircleFill(pW, fX, fY, fR, iColor) | 填充圆 |
int xuiCanvasDrawSurface(pW, pSurf, tSrc, tDst, iColor, iFlags) | 纹理 |
int xuiCanvasDrawMeshTriangles(pW, pVerts, iVC, pIdx, iIC, iFlags) | Mesh |
int xuiCanvasSetOffset(pW, fX, fY) | 滚动偏移 |
int xuiCanvasEnsureRectVisible(pW, tRect) | 滚动到可见 |
gcc -O2 -I. -o ch190.exe ch190_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch190.exe
xui_canvas_desc_t desc = { 0 };
xui_widget pCanvas;
xuiCanvasCreate(pCtx, &pCanvas, &desc);
// 画布 2000×2000(可滚动)
xuiCanvasSetCanvasSize(pCanvas, 2000.0f, 2000.0f);
// 每帧绘制(在 Render 回调中)
xuiCanvasClear(pCanvas, 0x1A1A2EFF);
// 网格线
for (int i = 0; i <= 2000; i += 50) {
xuiCanvasDrawLine(pCanvas, i, 0, i, 2000, 1.0f, 0x33335540);
xuiCanvasDrawLine(pCanvas, 0, i, 2000, i, 1.0f, 0x33335540);
}
// 绘制精灵
xui_rect_t tSrc = { 0, 0, 64, 64 };
xui_rect_t tDst = { 100, 100, 64, 64 };
xuiCanvasDrawSurface(pCanvas, pSprite, tSrc, tDst, 0xFFFFFFFF, 0);
// 高亮圆
xuiCanvasDrawCircleFill(pCanvas, 400.0f, 300.0f, 20.0f, 0xFF6B5E80);将以下代码保存为 ch190_main.c,编译后运行即可看到 Canvas 自定义绘图效果:
#include "xge.h"
#include "xui.h"
static xui_context g_pCtx;
static xui_widget g_pCanvas;
static int onFrame(void* pUser) {
(void)pUser;
xgeClear(0x1A1A2EFF);
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);
// 每帧重绘画布
xuiCanvasClear(g_pCanvas, 0x1A1A2EFF);
// 网格线
for (int i = 0; i <= 800; i += 40) {
xuiCanvasDrawLine(g_pCanvas, (float)i, 0, (float)i, 600, 1.0f, 0x33335540);
xuiCanvasDrawLine(g_pCanvas, 0, (float)i, 800, (float)i, 1.0f, 0x33335540);
}
// 填充圆
xuiCanvasDrawCircleFill(g_pCanvas, 200.0f, 150.0f, 40.0f, 0xFF6B5E80);
// 填充矩形
xui_rect_t rc = { 300, 200, 120, 80 };
xuiCanvasDrawRectFill(g_pCanvas, rc, 0x4FD8C260);
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 = "ch190 - Canvas";
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_canvas_desc_t cdesc = { 0 };
xuiCanvasCreate(g_pCtx, &g_pCanvas, &cdesc);
xuiCanvasSetCanvasSize(g_pCanvas, 800.0f, 600.0f);
xui_widget pRoot = xuiGetRootWidget(g_pCtx);
xuiWidgetAddChild(pRoot, g_pCanvas);
xuiWidgetSetRect(g_pCanvas, (xui_rect_t){0, 0, 800, 600});
xgeRun(onFrame, NULL);
xuiDestroy(g_pCtx);
xgeUnit();
return 0;
}