[{"data":1,"prerenderedAt":646},["ShallowReactive",2],{"doc-\u002Fdocs\u002Fapi\u002Feduwin-menu-api":3},{"id":4,"title":5,"body":6,"description":639,"extension":640,"meta":641,"navigation":141,"path":642,"seo":643,"stem":644,"__hash__":645},"content\u002Fdocs\u002Fapi\u002Feduwin-menu-api.md","eduwin 菜单 API",{"type":7,"value":8,"toc":630},"minimark",[9,13,30,33,36,84,94,112,127,244,246,248,263,277,297,299,301,316,328,342,377,381,390,399,402,432,441,456,499,509,511,514,529,539,554,556,559,568,594,609,626],[10,11,5],"h1",{"id":12},"eduwin-菜单-api",[14,15,16,17,21,22,25,26,29],"p",{},"eduwin 支持三种菜单：",[18,19,20],"strong",{},"主菜单","（窗口菜单栏）、",[18,23,24],{},"系统菜单","（标题栏图标菜单）、",[18,27,28],{},"上下文菜单","（右键弹出）。",[31,32],"hr",{},[34,35,20],"h2",{"id":20},[37,38,43],"pre",{"className":39,"code":40,"language":41,"meta":42,"style":42},"language-c shiki shiki-themes github-light github-dark","HMENU create_main_menu(HWND win);\nHMENU add_main_menu(HMENU main, const WCHAR *text);\nint add_menu_item(HMENU popup, const WCHAR *text);\nvoid add_menu_separator(HMENU popup);\nHMENU add_sub_menu(HMENU parent, const WCHAR *text);\nvoid on_menu_click(int id, void (*callback)(void *), void *data);\n","c","",[44,45,46,54,60,66,72,78],"code",{"__ignoreMap":42},[47,48,51],"span",{"class":49,"line":50},"line",1,[47,52,53],{},"HMENU create_main_menu(HWND win);\n",[47,55,57],{"class":49,"line":56},2,[47,58,59],{},"HMENU add_main_menu(HMENU main, const WCHAR *text);\n",[47,61,63],{"class":49,"line":62},3,[47,64,65],{},"int add_menu_item(HMENU popup, const WCHAR *text);\n",[47,67,69],{"class":49,"line":68},4,[47,70,71],{},"void add_menu_separator(HMENU popup);\n",[47,73,75],{"class":49,"line":74},5,[47,76,77],{},"HMENU add_sub_menu(HMENU parent, const WCHAR *text);\n",[47,79,81],{"class":49,"line":80},6,[47,82,83],{},"void on_menu_click(int id, void (*callback)(void *), void *data);\n",[14,85,86,89,90,93],{},[44,87,88],{},"create_main_menu"," 创建菜单栏并附加到窗口，返回菜单栏句柄。",[44,91,92],{},"add_main_menu"," 在菜单栏添加一个顶级弹出菜单（如\"文件\"），返回该弹出菜单句柄。",[14,95,96,99,100,103,104,107,108,111],{},[44,97,98],{},"add_menu_item"," 向弹出菜单添加可点击的菜单项，返回自动分配的 ID。",[44,101,102],{},"add_menu_separator"," 添加分隔线。",[44,105,106],{},"add_sub_menu"," 添加子菜单，返回子菜单句柄。",[44,109,110],{},"on_menu_click"," 注册点击回调。",[14,113,114,115,118,119,122,123,126],{},"菜单项文本中可以用 ",[44,116,117],{},"(&F)"," 指定助记符（Alt+F 快捷访问），用 ",[44,120,121],{},"\\t"," 分隔快捷键提示文字（仅显示，快捷键注册见 ",[44,124,125],{},"set_menu_shortcut","）。",[37,128,130],{"className":39,"code":129,"language":41,"meta":42,"style":42},"HMENU main = create_main_menu(win);\n\nHMENU file = add_main_menu(main, L\"文件(&F)\");\nint id_new  = add_menu_item(file, L\"新建\\tCtrl+N\");\nint id_open = add_menu_item(file, L\"打开\\tCtrl+O\");\nadd_menu_separator(file);\nint id_exit = add_menu_item(file, L\"退出\");\n\non_menu_click(id_new,  on_new,  NULL);\non_menu_click(id_open, on_open, NULL);\non_menu_click(id_exit, on_exit, NULL);\n\n\u002F\u002F 带子菜单的\"视图\"菜单\nHMENU view = add_main_menu(main, L\"视图(&V)\");\nint id_status = add_menu_item(view, L\"状态栏\");\nset_menu_checked(id_status, 1);\n\nHMENU sort_sub = add_sub_menu(view, L\"排序方式\");\nint id_sort_name = add_menu_item(sort_sub, L\"按名称\");\non_menu_click(id_sort_name, on_sort_name, NULL);\n",[44,131,132,137,143,148,153,158,163,169,174,180,186,192,197,203,209,215,221,226,232,238],{"__ignoreMap":42},[47,133,134],{"class":49,"line":50},[47,135,136],{},"HMENU main = create_main_menu(win);\n",[47,138,139],{"class":49,"line":56},[47,140,142],{"emptyLinePlaceholder":141},true,"\n",[47,144,145],{"class":49,"line":62},[47,146,147],{},"HMENU file = add_main_menu(main, L\"文件(&F)\");\n",[47,149,150],{"class":49,"line":68},[47,151,152],{},"int id_new  = add_menu_item(file, L\"新建\\tCtrl+N\");\n",[47,154,155],{"class":49,"line":74},[47,156,157],{},"int id_open = add_menu_item(file, L\"打开\\tCtrl+O\");\n",[47,159,160],{"class":49,"line":80},[47,161,162],{},"add_menu_separator(file);\n",[47,164,166],{"class":49,"line":165},7,[47,167,168],{},"int id_exit = add_menu_item(file, L\"退出\");\n",[47,170,172],{"class":49,"line":171},8,[47,173,142],{"emptyLinePlaceholder":141},[47,175,177],{"class":49,"line":176},9,[47,178,179],{},"on_menu_click(id_new,  on_new,  NULL);\n",[47,181,183],{"class":49,"line":182},10,[47,184,185],{},"on_menu_click(id_open, on_open, NULL);\n",[47,187,189],{"class":49,"line":188},11,[47,190,191],{},"on_menu_click(id_exit, on_exit, NULL);\n",[47,193,195],{"class":49,"line":194},12,[47,196,142],{"emptyLinePlaceholder":141},[47,198,200],{"class":49,"line":199},13,[47,201,202],{},"\u002F\u002F 带子菜单的\"视图\"菜单\n",[47,204,206],{"class":49,"line":205},14,[47,207,208],{},"HMENU view = add_main_menu(main, L\"视图(&V)\");\n",[47,210,212],{"class":49,"line":211},15,[47,213,214],{},"int id_status = add_menu_item(view, L\"状态栏\");\n",[47,216,218],{"class":49,"line":217},16,[47,219,220],{},"set_menu_checked(id_status, 1);\n",[47,222,224],{"class":49,"line":223},17,[47,225,142],{"emptyLinePlaceholder":141},[47,227,229],{"class":49,"line":228},18,[47,230,231],{},"HMENU sort_sub = add_sub_menu(view, L\"排序方式\");\n",[47,233,235],{"class":49,"line":234},19,[47,236,237],{},"int id_sort_name = add_menu_item(sort_sub, L\"按名称\");\n",[47,239,241],{"class":49,"line":240},20,[47,242,243],{},"on_menu_click(id_sort_name, on_sort_name, NULL);\n",[31,245],{},[34,247,24],{"id":24},[37,249,251],{"className":39,"code":250,"language":41,"meta":42,"style":42},"int create_sys_menu(HWND win, const WCHAR *text);\nvoid add_sys_separator(HWND win);\n",[44,252,253,258],{"__ignoreMap":42},[47,254,255],{"class":49,"line":50},[47,256,257],{},"int create_sys_menu(HWND win, const WCHAR *text);\n",[47,259,260],{"class":49,"line":56},[47,261,262],{},"void add_sys_separator(HWND win);\n",[14,264,265,266,269,270,273,274,276],{},"向系统菜单（标题栏图标右键菜单）添加自定义项。",[44,267,268],{},"create_sys_menu"," 添加一个菜单项并返回自动分配的 ID，",[44,271,272],{},"add_sys_separator"," 添加分隔线。回调通过 ",[44,275,110],{}," 注册。",[37,278,280],{"className":39,"code":279,"language":41,"meta":42,"style":42},"add_sys_separator(win);\nint id_sys = create_sys_menu(win, L\"关于 (&A)\");\non_menu_click(id_sys, on_sys_about, NULL);\n",[44,281,282,287,292],{"__ignoreMap":42},[47,283,284],{"class":49,"line":50},[47,285,286],{},"add_sys_separator(win);\n",[47,288,289],{"class":49,"line":56},[47,290,291],{},"int id_sys = create_sys_menu(win, L\"关于 (&A)\");\n",[47,293,294],{"class":49,"line":62},[47,295,296],{},"on_menu_click(id_sys, on_sys_about, NULL);\n",[31,298],{},[34,300,28],{"id":28},[37,302,304],{"className":39,"code":303,"language":41,"meta":42,"style":42},"HMENU create_context_menu(void);\nvoid show_context_menu(HMENU menu, HWND relative, int x, int y);\n",[44,305,306,311],{"__ignoreMap":42},[47,307,308],{"class":49,"line":50},[47,309,310],{},"HMENU create_context_menu(void);\n",[47,312,313],{"class":49,"line":56},[47,314,315],{},"void show_context_menu(HMENU menu, HWND relative, int x, int y);\n",[14,317,318,321,322,324,325,327],{},[44,319,320],{},"create_context_menu"," 创建一个空的上下文菜单，",[44,323,98],{}," \u002F ",[44,326,102],{}," 添加菜单项。",[14,329,330,333,334,337,338,341],{},[44,331,332],{},"show_context_menu"," 在屏幕坐标 ",[44,335,336],{},"(x, y)"," 处弹出菜单。",[44,339,340],{},"relative"," 用于确定菜单弹出后的归属。",[37,343,345],{"className":39,"code":344,"language":41,"meta":42,"style":42},"HMENU ctx = create_context_menu();\nint id_info   = add_menu_item(ctx, L\"查看详情\");\nadd_menu_separator(ctx);\nint id_delete = add_menu_item(ctx, L\"删除\");\non_menu_click(id_info,   on_ctx_info,   NULL);\non_menu_click(id_delete, on_ctx_delete, NULL);\n",[44,346,347,352,357,362,367,372],{"__ignoreMap":42},[47,348,349],{"class":49,"line":50},[47,350,351],{},"HMENU ctx = create_context_menu();\n",[47,353,354],{"class":49,"line":56},[47,355,356],{},"int id_info   = add_menu_item(ctx, L\"查看详情\");\n",[47,358,359],{"class":49,"line":62},[47,360,361],{},"add_menu_separator(ctx);\n",[47,363,364],{"class":49,"line":68},[47,365,366],{},"int id_delete = add_menu_item(ctx, L\"删除\");\n",[47,368,369],{"class":49,"line":74},[47,370,371],{},"on_menu_click(id_info,   on_ctx_info,   NULL);\n",[47,373,374],{"class":49,"line":80},[47,375,376],{},"on_menu_click(id_delete, on_ctx_delete, NULL);\n",[378,379,380],"h3",{"id":380},"上下文菜单的坐标处理",[14,382,383,385,386,389],{},[44,384,332],{}," 要求 ",[18,387,388],{},"屏幕坐标","，不同场景下获取坐标的方式不同：",[14,391,392],{},[18,393,394,395,398],{},"普通窗口（",[44,396,397],{},"WM_CONTEXTMENU","）：",[14,400,401],{},"右键消息自带的坐标已经是屏幕坐标，可直接使用。",[37,403,405],{"className":39,"code":404,"language":41,"meta":42,"style":42},"\u002F\u002F 子类化窗口过程截获 WM_CONTEXTMENU\nif (msg == WM_CONTEXTMENU) {\n    POINT pt = {LOWORD(lp), HIWORD(lp)};\n    show_context_menu(ctx_menu, (HWND)wp, pt.x, pt.y);\n}\n",[44,406,407,412,417,422,427],{"__ignoreMap":42},[47,408,409],{"class":49,"line":50},[47,410,411],{},"\u002F\u002F 子类化窗口过程截获 WM_CONTEXTMENU\n",[47,413,414],{"class":49,"line":56},[47,415,416],{},"if (msg == WM_CONTEXTMENU) {\n",[47,418,419],{"class":49,"line":62},[47,420,421],{},"    POINT pt = {LOWORD(lp), HIWORD(lp)};\n",[47,423,424],{"class":49,"line":68},[47,425,426],{},"    show_context_menu(ctx_menu, (HWND)wp, pt.x, pt.y);\n",[47,428,429],{"class":49,"line":74},[47,430,431],{},"}\n",[14,433,434],{},[18,435,436,437,440],{},"画布控件（",[44,438,439],{},"canvas_on_mouse"," 回调）：",[14,442,443,444,447,448,451,452,455],{},"画布鼠标回调中的 ",[44,445,446],{},"x, y"," 是",[18,449,450],{},"画布客户区坐标","，必须用 ",[44,453,454],{},"ClientToScreen"," 转换为屏幕坐标：",[37,457,459],{"className":39,"code":458,"language":41,"meta":42,"style":42},"void on_mouse_down(int btn, int x, int y)\n{\n    if (btn != 1) return; \u002F\u002F 只处理右键\n\n    POINT pt = {x, y};\n    ClientToScreen(canvas, &pt);\n    show_context_menu(ctx_menu, canvas, pt.x, pt.y);\n}\n",[44,460,461,466,471,476,480,485,490,495],{"__ignoreMap":42},[47,462,463],{"class":49,"line":50},[47,464,465],{},"void on_mouse_down(int btn, int x, int y)\n",[47,467,468],{"class":49,"line":56},[47,469,470],{},"{\n",[47,472,473],{"class":49,"line":62},[47,474,475],{},"    if (btn != 1) return; \u002F\u002F 只处理右键\n",[47,477,478],{"class":49,"line":68},[47,479,142],{"emptyLinePlaceholder":141},[47,481,482],{"class":49,"line":74},[47,483,484],{},"    POINT pt = {x, y};\n",[47,486,487],{"class":49,"line":80},[47,488,489],{},"    ClientToScreen(canvas, &pt);\n",[47,491,492],{"class":49,"line":165},[47,493,494],{},"    show_context_menu(ctx_menu, canvas, pt.x, pt.y);\n",[47,496,497],{"class":49,"line":171},[47,498,431],{},[500,501,502],"blockquote",{},[14,503,504,505,508],{},"不能直接用 ",[44,506,507],{},"GetCursorPos"," 替代，因为右键消息不一定来自鼠标（也可能是键盘 Shift+F10 或触控）。",[31,510],{},[34,512,513],{"id":513},"菜单状态控制",[37,515,517],{"className":39,"code":516,"language":41,"meta":42,"style":42},"void set_menu_checked(int id, int checked);\nvoid set_menu_enabled(int id, int enabled);\n",[44,518,519,524],{"__ignoreMap":42},[47,520,521],{"class":49,"line":50},[47,522,523],{},"void set_menu_checked(int id, int checked);\n",[47,525,526],{"class":49,"line":56},[47,527,528],{},"void set_menu_enabled(int id, int enabled);\n",[14,530,531,534,535,538],{},[44,532,533],{},"set_menu_checked"," 设置菜单项勾选状态（前面打勾 ✓）。",[44,536,537],{},"set_menu_enabled"," 设置菜单项启用\u002F禁用（灰色不可点击）。",[37,540,542],{"className":39,"code":541,"language":41,"meta":42,"style":42},"set_menu_checked(id_status, 1);   \u002F\u002F 勾选\nset_menu_enabled(id_paste, 0);    \u002F\u002F 禁用\n",[44,543,544,549],{"__ignoreMap":42},[47,545,546],{"class":49,"line":50},[47,547,548],{},"set_menu_checked(id_status, 1);   \u002F\u002F 勾选\n",[47,550,551],{"class":49,"line":56},[47,552,553],{},"set_menu_enabled(id_paste, 0);    \u002F\u002F 禁用\n",[31,555],{},[34,557,558],{"id":558},"快捷键",[37,560,562],{"className":39,"code":561,"language":41,"meta":42,"style":42},"void set_menu_shortcut(int id, BYTE vkey, int ctrl, int shift);\n",[44,563,564],{"__ignoreMap":42},[47,565,566],{"class":49,"line":50},[47,567,561],{},[14,569,570,571,574,575,578,579,578,582,585,586,589,590,593],{},"为菜单项注册真正的键盘快捷键（加速键）。",[44,572,573],{},"vkey"," 是虚拟键码（如 ",[44,576,577],{},"'N'","、",[44,580,581],{},"'Z'",[44,583,584],{},"VK_F5","），",[44,587,588],{},"ctrl"," 和 ",[44,591,592],{},"shift"," 表示是否需要按下 Ctrl \u002F Shift 键。",[37,595,597],{"className":39,"code":596,"language":41,"meta":42,"style":42},"set_menu_shortcut(id_new,  'N', 1, 0);    \u002F\u002F Ctrl+N\nset_menu_shortcut(id_undo, 'Z', 1, 0);   \u002F\u002F Ctrl+Z\n",[44,598,599,604],{"__ignoreMap":42},[47,600,601],{"class":49,"line":50},[47,602,603],{},"set_menu_shortcut(id_new,  'N', 1, 0);    \u002F\u002F Ctrl+N\n",[47,605,606],{"class":49,"line":56},[47,607,608],{},"set_menu_shortcut(id_undo, 'Z', 1, 0);   \u002F\u002F Ctrl+Z\n",[500,610,611],{},[14,612,613,614,616,617,619,620,585,623,625],{},"快捷键提示文字需要在 ",[44,615,98],{}," 的文本中用 ",[44,618,121],{}," 指定（如 ",[44,621,622],{},"L\"新建\\tCtrl+N\"",[44,624,125],{}," 只负责实际的键盘响应，不修改菜单文字。",[627,628,629],"style",{},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":42,"searchDepth":56,"depth":56,"links":631},[632,633,634,637,638],{"id":20,"depth":56,"text":20},{"id":24,"depth":56,"text":24},{"id":28,"depth":56,"text":28,"children":635},[636],{"id":380,"depth":62,"text":380},{"id":513,"depth":56,"text":513},{"id":558,"depth":56,"text":558},"eduwin 支持三种菜单：主菜单（窗口菜单栏）、系统菜单（标题栏图标菜单）、上下文菜单（右键弹出）。","md",{},"\u002Fdocs\u002Fapi\u002Feduwin-menu-api",{"title":5,"description":639},"docs\u002Fapi\u002Feduwin-menu-api","kK6p183lC-eWI7CJfs_tXJh9CgzrONYIfXY1S7Tnkb4",1782488679848]