XUI 事件分发管线:DispatchEvent、PendingEvents、CommandDispatch、事件冒泡与拦截。
XUI 输入事件分发管线:
• DispatchEvent:将原始输入事件注入 XUI 上下文
• DispatchPendingEvents:处理队列中的待处理事件
• CommandDispatch:命令分发(菜单/快捷键/按钮统一入口)
• 冒泡:事件从目标控件向父级冒泡
• DISPATCH_STOP:拦截事件,阻止继续传播
| 函数 | 说明 |
|---|---|
int xuiDispatchEvent(xui_context pCtx, const xui_event_t* pEvent) | 分发事件 |
int xuiDispatchPendingEvents(xui_context pCtx) | 处理待处理事件 |
int xuiCommandDispatch(pCtx, pTarget, iCmd, sCmd, pData) | 命令分发 |
gcc -O2 -I. -o ch191.exe ch191_main.c src\xui_*.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch191.exe
// 在 XGE 帧循环中桥接输入
void OnFrame(void) {
// 鼠标事件
if (xgeMouseDown(XGE_MOUSE_LEFT)) {
xui_event_t ev = { 0 };
ev.iType = XUI_EVENT_POINTER_DOWN;
ev.iButton = XGE_MOUSE_LEFT;
float mx, my;
xgeMouseGet(&mx, &my);
ev.fX = mx; ev.fY = my;
xuiDispatchEvent(pCtx, &ev);
}
// 处理所有待处理事件
xuiDispatchPendingEvents(pCtx);
}
// 命令分发(菜单项点击)
xuiCommandDispatch(pCtx, pTargetWidget,
CMD_SAVE, "file.save", NULL);将以下代码保存为 ch191_main.c,编译后运行即可看到输入事件分发与命令系统效果:
#include "xge.h"
#include "xui.h"
#include <stdio.h>
static xui_context g_pCtx;
static xui_widget g_pLog;
static int g_iCount = 0;
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;
}
static void onBtnClick(xui_widget pW, void* pUser) {
(void)pW; (void)pUser;
char buf[128];
sprintf(buf, "Click #%d dispatched", ++g_iCount);
xuiLabelSetText(g_pLog, buf);
}
int main(void) {
xge_desc_t d = {0};
d.iWidth = 640; d.iHeight = 480;
d.sTitle = "ch191 - Input Dispatch";
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_widget pBtn;
xuiButtonCreate(g_pCtx, &pBtn, NULL);
xuiWidgetAddChild(pRoot, pBtn);
xuiLabelSetText(pBtn, "Click Me");
xuiWidgetSetRect(pBtn, (xui_rect_t){240, 160, 160, 48});
xuiWidgetSetRect(pBtn, (xui_rect_t){0, 0, 160, 48});
xuiWidgetSetEventCallback(pBtn, onBtnClick, NULL);
g_pLog = xuiLabelCreate(g_pCtx, &g_pLog, NULL);
xuiWidgetAddChild(pRoot, g_pLog);
xuiLabelSetText(g_pLog, "Waiting for events...");
xuiWidgetSetRect(g_pLog, (xui_rect_t){200, 260, 240, 32});
xuiWidgetSetRect(g_pLog, (xui_rect_t){0, 0, 240, 32});
xgeRun(onFrame, NULL);
xuiDestroy(g_pCtx);
xgeUnit();
return 0;
}