聊天/日志消息列表:节点模型、流式追加、折叠、事件回调。
MessageList 是消息/聊天列表控件:
• Node:消息节点(ID/发送者/文本/头像/时间戳)
• 流式追加:AppendNodeText 逐字追加(AI 打字效果)
• 折叠:长消息可折叠/展开
• 事件:点击/链接/按钮交互回调
适用:聊天界面、AI 对话、日志查看器、通知中心。
| 函数 | 说明 |
|---|---|
int xuiMessageListCreate(pCtx, ppW, pDesc) | 创建消息列表 |
int xuiMessageListSetNodes(pW, pNodes, iCount) | 批量设置节点 |
int xuiMessageListAddNode(pW, pNode) | 追加节点 |
int xuiMessageListUpdateNodeText(pW, sId, sText) | 更新文本 |
int xuiMessageListAppendNodeText(pW, sId, sText) | 追加文本 |
int xuiMessageListSetNodeCollapsed(pW, sId, bCollapsed) | 折叠/展开 |
int xuiMessageListClear(pW) | 清空 |
int xuiMessageListSetEvent(pW, onEvent, pUser) | 事件回调 |
gcc -O2 -I. -o ch185.exe ch185_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch185.exe
xui_message_list_desc_t desc = { 0 };
xui_widget pMsgList;
xuiMessageListCreate(pCtx, &pMsgList, &desc);
// 添加用户消息
xui_message_node_t msg = { 0 };
msg.sId = "msg_001";
msg.sSender = "User";
msg.sText = "Hello, XGE!";
msg.bSelf = 1;
xuiMessageListAddNode(pMsgList, &msg);
// AI 回复(流式追加)
msg.sId = "msg_002";
msg.sSender = "Assistant";
msg.sText = "";
msg.bSelf = 0;
xuiMessageListAddNode(pMsgList, &msg);
// 模拟打字效果
xuiMessageListAppendNodeText(pMsgList, "msg_002", "Hi! ");
xuiMessageListAppendNodeText(pMsgList, "msg_002", "How can ");
xuiMessageListAppendNodeText(pMsgList, "msg_002", "I help?");
// 事件回调
xuiMessageListSetEvent(pMsgList, OnMsgEvent, NULL);将以下代码保存为 ch185_main.c,编译后运行即可看到聊天消息列表效果:
#include "xge.h"
#include "xui.h"
static xui_context g_pCtx;
static xui_widget g_pMsgList;
static int g_iTick = 0;
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);
// 模拟流式输出
g_iTick++;
if (g_iTick == 60)
xuiMessageListAppendNodeText(g_pMsgList, "msg_002", "Hi! ");
if (g_iTick == 90)
xuiMessageListAppendNodeText(g_pMsgList, "msg_002", "How can ");
if (g_iTick == 120)
xuiMessageListAppendNodeText(g_pMsgList, "msg_002", "I help you?");
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 = 600; d.iHeight = 700;
d.sTitle = "ch185 - MessageList";
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, 600, 700);
xui_message_list_desc_t mdesc = { 0 };
xuiMessageListCreate(g_pCtx, &g_pMsgList, &mdesc);
// 用户消息
xui_message_node_t msg = { 0 };
msg.sId = "msg_001";
msg.sSender = "User";
msg.sText = "Hello, XGE!";
msg.bSelf = 1;
xuiMessageListAddNode(g_pMsgList, &msg);
// AI 回复(流式)
msg.sId = "msg_002";
msg.sSender = "Assistant";
msg.sText = "";
msg.bSelf = 0;
xuiMessageListAddNode(g_pMsgList, &msg);
xui_widget pRoot = xuiGetRootWidget(g_pCtx);
xuiWidgetAddChild(pRoot, g_pMsgList);
xuiWidgetSetRect(g_pMsgList, (xui_rect_t){0, 0, 600, 700});
xgeRun(onFrame, NULL);
xuiDestroy(g_pCtx);
xgeUnit();
return 0;
}