eduwin 菜单 API
eduwin 支持三种菜单:主菜单(窗口菜单栏)、系统菜单(标题栏图标菜单)、上下文菜单(右键弹出)。
主菜单
HMENU create_main_menu(HWND win);
HMENU add_main_menu(HMENU main, const WCHAR *text);
int add_menu_item(HMENU popup, const WCHAR *text);
void add_menu_separator(HMENU popup);
HMENU add_sub_menu(HMENU parent, const WCHAR *text);
void on_menu_click(int id, void (*callback)(void *), void *data);
create_main_menu 创建菜单栏并附加到窗口,返回菜单栏句柄。add_main_menu 在菜单栏添加一个顶级弹出菜单(如"文件"),返回该弹出菜单句柄。
add_menu_item 向弹出菜单添加可点击的菜单项,返回自动分配的 ID。add_menu_separator 添加分隔线。add_sub_menu 添加子菜单,返回子菜单句柄。on_menu_click 注册点击回调。
菜单项文本中可以用 (&F) 指定助记符(Alt+F 快捷访问),用 \t 分隔快捷键提示文字(仅显示,快捷键注册见 set_menu_shortcut)。
HMENU main = create_main_menu(win);
HMENU file = add_main_menu(main, L"文件(&F)");
int id_new = add_menu_item(file, L"新建\tCtrl+N");
int id_open = add_menu_item(file, L"打开\tCtrl+O");
add_menu_separator(file);
int id_exit = add_menu_item(file, L"退出");
on_menu_click(id_new, on_new, NULL);
on_menu_click(id_open, on_open, NULL);
on_menu_click(id_exit, on_exit, NULL);
// 带子菜单的"视图"菜单
HMENU view = add_main_menu(main, L"视图(&V)");
int id_status = add_menu_item(view, L"状态栏");
set_menu_checked(id_status, 1);
HMENU sort_sub = add_sub_menu(view, L"排序方式");
int id_sort_name = add_menu_item(sort_sub, L"按名称");
on_menu_click(id_sort_name, on_sort_name, NULL);
系统菜单
int create_sys_menu(HWND win, const WCHAR *text);
void add_sys_separator(HWND win);
向系统菜单(标题栏图标右键菜单)添加自定义项。create_sys_menu 添加一个菜单项并返回自动分配的 ID,add_sys_separator 添加分隔线。回调通过 on_menu_click 注册。
add_sys_separator(win);
int id_sys = create_sys_menu(win, L"关于 (&A)");
on_menu_click(id_sys, on_sys_about, NULL);
上下文菜单
HMENU create_context_menu(void);
void show_context_menu(HMENU menu, HWND relative, int x, int y);
create_context_menu 创建一个空的上下文菜单,add_menu_item / add_menu_separator 添加菜单项。
show_context_menu 在屏幕坐标 (x, y) 处弹出菜单。relative 用于确定菜单弹出后的归属。
HMENU ctx = create_context_menu();
int id_info = add_menu_item(ctx, L"查看详情");
add_menu_separator(ctx);
int id_delete = add_menu_item(ctx, L"删除");
on_menu_click(id_info, on_ctx_info, NULL);
on_menu_click(id_delete, on_ctx_delete, NULL);
上下文菜单的坐标处理
show_context_menu 要求 屏幕坐标,不同场景下获取坐标的方式不同:
普通窗口(WM_CONTEXTMENU):
右键消息自带的坐标已经是屏幕坐标,可直接使用。
// 子类化窗口过程截获 WM_CONTEXTMENU
if (msg == WM_CONTEXTMENU) {
POINT pt = {LOWORD(lp), HIWORD(lp)};
show_context_menu(ctx_menu, (HWND)wp, pt.x, pt.y);
}
画布控件(canvas_on_mouse 回调):
画布鼠标回调中的 x, y 是画布客户区坐标,必须用 ClientToScreen 转换为屏幕坐标:
void on_mouse_down(int btn, int x, int y)
{
if (btn != 1) return; // 只处理右键
POINT pt = {x, y};
ClientToScreen(canvas, &pt);
show_context_menu(ctx_menu, canvas, pt.x, pt.y);
}
不能直接用
GetCursorPos替代,因为右键消息不一定来自鼠标(也可能是键盘 Shift+F10 或触控)。
菜单状态控制
void set_menu_checked(int id, int checked);
void set_menu_enabled(int id, int enabled);
set_menu_checked 设置菜单项勾选状态(前面打勾 ✓)。set_menu_enabled 设置菜单项启用/禁用(灰色不可点击)。
set_menu_checked(id_status, 1); // 勾选
set_menu_enabled(id_paste, 0); // 禁用
快捷键
void set_menu_shortcut(int id, BYTE vkey, int ctrl, int shift);
为菜单项注册真正的键盘快捷键(加速键)。vkey 是虚拟键码(如 'N'、'Z'、VK_F5),ctrl 和 shift 表示是否需要按下 Ctrl / Shift 键。
set_menu_shortcut(id_new, 'N', 1, 0); // Ctrl+N
set_menu_shortcut(id_undo, 'Z', 1, 0); // Ctrl+Z
快捷键提示文字需要在
add_menu_item的文本中用\t指定(如L"新建\tCtrl+N"),set_menu_shortcut只负责实际的键盘响应,不修改菜单文字。