Chapter 156 · XUI 弹出层与反馈

MenuBar 菜单栏

MenuBar 水平顶级菜单栏,每个顶级项关联一个下拉 Menu,支持助记键、键盘导航。

156

概念

MenuBar 是应用程序顶部的菜单栏:
• 顶级项:文件 / 编辑 / 视图 / 帮助 等
• 关联 Menu:每个顶级项绑定一个 Menu 控件作为下拉
• 助记键:Alt+F 打开"文件"菜单
• 悬停切换:菜单打开状态下悬停其他顶级项自动切换

API 速查

函数说明
int xuiMenuBarCreate(xui_context pCtx, xui_widget* ppW, const xui_menubar_desc_t* pDesc)创建菜单栏
int xuiMenuBarAddItem(xui_widget pW, const char* sText, xui_widget pMenu, int iValue)添加顶级项
int xuiMenuBarSetItemMenu(xui_widget pW, int iIndex, xui_widget pMenu)绑定下拉菜单
int xuiMenuBarSetItemEnabled(xui_widget pW, int iIndex, int bEnabled)启用/禁用
int xuiMenuBarSetItemMnemonic(xui_widget pW, int iIndex, int iMnemonic)助记键
int xuiMenuBarOpenItem(xui_widget pW, int iIndex)打开指定菜单
int xuiMenuBarClose(xui_widget pW)关闭
int xuiMenuBarSetSelect(xui_widget pW, xui_menu_select_proc onSelect, void* pUser)选中回调
int xuiMenuBarSetColors(xui_widget pW, const xui_menubar_colors_t* pColors)颜色

编译本章示例

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

示例:应用菜单栏

xui_menubar_desc_t desc = { 0 };

xui_widget pMenuBar;
xuiMenuBarCreate(pCtx, &pMenuBar, &desc);

// 创建各下拉菜单
xui_widget pFileMenu, pEditMenu;
xuiMenuCreate(pCtx, &pFileMenu, &menuDesc);
xuiMenuCreate(pCtx, &pEditMenu, &menuDesc);

// 添加顶级项
xuiMenuBarAddItem(pMenuBar, "文件", pFileMenu, 0);
xuiMenuBarAddItem(pMenuBar, "编辑", pEditMenu, 1);

// 助记键
xuiMenuBarSetItemMnemonic(pMenuBar, 0, 'F');
xuiMenuBarSetItemMnemonic(pMenuBar, 1, 'E');

xuiMenuBarSetSelect(pMenuBar, OnMenuSelect, NULL);
xuiWidgetAddChild(pTopDock, pMenuBar);

完整代码

将以下代码保存为 ch156_main.c,编译后运行即可看到菜单栏效果:

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

static xui_context g_pCtx;

static void onSel(xui_widget pW, int iVal, void* p) {
    (void)pW; (void)p;
    printf("菜单选择: %d\n", iVal);
}

static int onFrame(void* pUser) {
    (void)pUser;
    xgeClear(0x081114FF);
    float mx, my;
    xgeMouseGet(&mx, &my);
    xuiInputPointerMove(g_pCtx, mx, my);
    if (xgeMouseDown(XGE_MOUSE_LEFT))
        xuiInputPointerDown(g_pCtx, 0);
    else
        xuiInputPointerUp(g_pCtx, 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 = 800; d.iHeight = 600;
    d.sTitle = "ch156 - MenuBar";
    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_widget pRoot;
    xuiWidgetCreate(g_pCtx, &pRoot);
xuiWidgetSetLayoutType(pRoot, XUI_LAYOUT_COLUMN);
    xuiWidgetSetRect(pRoot, (xui_rect_t){0, 0, 800, 600});
    xuiSetRootWidget(g_pCtx, pRoot);

    /* 创建菜单栏 */
    xui_menubar_desc_t mbd = { 0 };
    xui_widget pBar;
    xuiMenuBarCreate(g_pCtx, &pBar, &mbd);
    xuiMenuBarSetSelect(pBar, onSel, NULL);
    xuiWidgetAddChild(pRoot, pBar);

    /* 创建下拉菜单 */
    xui_menu_desc_t md = { 0 };
    xui_widget pFile, pEdit;
    xuiMenuCreate(g_pCtx, &pFile, &md);
    xuiMenuCreate(g_pCtx, &pEdit, &md);

    xui_menu_item_t fi[] = {
        { "新建", "Ctrl+N", 1, 0 },
        { "打开", "Ctrl+O", 2, 0 },
        { "退出", "",       3, 0 },
    };
    xuiMenuSetItems(pFile, fi, 3);

    xui_menu_item_t ei[] = {
        { "撤销", "Ctrl+Z", 10, 0 },
        { "重做", "Ctrl+Y", 11, 0 },
    };
    xuiMenuSetItems(pEdit, ei, 2);

    xuiMenuBarAddItem(pBar, "文件", pFile, 0);
    xuiMenuBarAddItem(pBar, "编辑", pEdit, 1);

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

代码讲解

  • MenuBar + Menu:菜单栏包含顶级项,每项关联一个下拉 Menu。
  • AddItem:添加顶级菜单项,绑定对应的下拉菜单控件。
  • 共享 Select:MenuBar 的回调统一处理所有子菜单项。
  • 悬停切换:菜单打开状态下悬停其他顶级项自动切换。

要点与陷阱

  • 共享 Select:MenuBar 的 Select 回调统一处理所有子菜单项。
  • Mnemonic:配合 Alt 键使用,字符匹配时打开对应菜单。
  • OpenIndex:当前打开的顶级项索引,-1 表示未打开。
  • 布局:MenuBar 通常放在 Dock 顶部区域。

进阶练习

  1. 完整 IDE 菜单栏:文件/编辑/视图/构建/工具/帮助。
  2. 最近文件子菜单:动态更新"文件→最近打开"列表。
MenuBar 菜单栏效果
图:MenuBar 菜单栏渲染效果