在 VC 中, 菜单设计是要保存在资源源文件(*.rc)中, 不管是 VC 还是 Delphi 用什么临时储存方式, 但最终都会被编译成相同的资源文件(*.res).
在 Delphi 中如果想要更灵活地使用菜单, 也回避不了使用资源文件.
下面是和上例对应的资源文件.
2、建立资源文件: File -> New -> Other... -> Text , 写入下面资源文件代码, 和工程保存在相同文件夹, 保存为 *.rc, 我这里使用的是: TestRes.rc;
5、另外, 菜单资源的写法还是挺复杂的、功能也很强大; 后面的例子再说.
function WndProc(wnd: HWND; msg: UINT; wParam: Integer; lParam: Integer): Integer; stdcall;
end.
我们可以把上例中的资源文件修改成这样:
MyMenu1 MENUEX
BEGIN
POPUP "&File" ,65535
BEGIN
MENUITEM "&New" ,101
MENUITEM "&Open" ,102
MENUITEM "&Save" ,103
MENUITEM SEPARATOR
MENUITEM "E&xit" ,104
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,201
MENUITEM "&Copy" ,202
MENUITEM "&Paste" ,203
END
POPUP "&Help" ,65535
BEGIN
MENUITEM "&About" ,301
END
END
解释一下:
1. 以前是使用 MENU 标识菜单资源的; 用 MENUEX 会有更多功能.
2、就像 Delphi 一样, 它们使用 BEGIN 与 END 划分语句块, 也可以用 C/C++ 语言的方式: { ... }; 还有它的注释也是 C 语言格式的.
3、MyMenu1 MENUEX 中的 MyMenu1 是自定义的该菜单的标识.
4、MyMenu1 MENUEX 后面可以有关于载入和释放的控制符: PRELOAD、MOVEABLE PURE、DISCARDABLE(这个我没找到权威资料, 有谁知道, 万望告诉我; DISCARDABLE 用的最多, 可能是该资源没被使用可以忽略的意思).
5、POPUP 表示这是一个弹出菜单项, 也就是: 它有下级菜单; 大家习惯用 65535 做标识.
6、MENUITEM 表示一个菜单项, MENUITEM SEPARATOR 表示一个菜单分隔符.
7、MENUITEM 的第一个参数是要显示的文本, & 用来指定加速键.
8、MENUITEM 的第二个参数(参数用 , 号隔开)是该菜单项的标识, 是一个整数值(1-65535); 当用户点击菜单时, 会送出 WM_COMMAND 消息, 消息的 wParam 参数就是这个标识, 从而让我们知道点击的是哪一个菜单项; 这个标识有点像句柄, 一般在操作这个菜单项时也需要这个标识.
现在要解决一个问题: 这些 MENUITEM 的标识 101、102、103 等等不好记忆, 如果定义成有字面意义的常量就好了.
在 Delphi 中使用 const 定义常量, 但资源文件是系统级的, 需要用 C/C++ 的方法来定义常量. 这样我们可以修改如下:
#define IDM_New 101
#define IDM_Open 102
#define IDM_Save 103
#define IDM_Exit 104
#define IDM_Cut 201
#define IDM_Copy 202
#define IDM_Paste 203
#define IDM_About 301
MYMENU1 MENUEX
BEGIN
POPUP "&File" ,65535
BEGIN
MENUITEM "&New" ,IDM_New
MENUITEM "&Open" ,IDM_Open
MENUITEM "&Save" ,IDM_Save
MENUITEM SEPARATOR
MENUITEM "E&xit" ,IDM_Exit
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,IDM_Cut
MENUITEM "&Copy" ,IDM_Copy
MENUITEM "&Paste" ,IDM_Paste
END
POPUP "&Help" ,65535
BEGIN
MENUITEM "&About" ,IDM_About
END
END
继续研究: 每一个菜单项后面可以有很多参数来指定不同的功能和显示效果.
譬如: MFT_STRING(是字符串)、MFS_CHECKED(选择)、MFS_GRAYED(禁用)、MFT_RIGHTJUSTIFY(显示在右边)等等, 示例如下:
#define IDM_New 101
#define IDM_Open 102
#define IDM_Save 103
#define IDM_Exit 104
#define IDM_Cut 201
#define IDM_Copy 202
#define IDM_Paste 203
#define IDM_About 301
MYMENU1 MENUEX
BEGIN
POPUP "&File" ,65535
BEGIN
MENUITEM "&New" ,IDM_New ,MFT_STRING, MFS_CHECKED
MENUITEM "&Open" ,IDM_Open ,MFT_STRING, MFS_GRAYED
MENUITEM "&Save" ,IDM_Save
MENUITEM SEPARATOR
MENUITEM "E&xit" ,IDM_Exit
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,IDM_Cut
MENUITEM "&Copy" ,IDM_Copy
MENUITEM "&Paste" ,IDM_Paste
END
POPUP "&Help" ,65535 ,MFT_RIGHTJUSTIFY
BEGIN
MENUITEM "&About" ,IDM_About
END
END
调用后的效果图:
又如: MFT_MENUBREAK(分列)、MFT_MENUBARBREAK(分列并带分割线), 示例如下:
#define IDM_New 101
#define IDM_Open 102
#define IDM_Save 103
#define IDM_Exit 104
#define IDM_Cut 201
#define IDM_Copy 202
#define IDM_Paste 203
#define IDM_About 301
MYMENU1 MENUEX
BEGIN
POPUP "&File" ,65535
BEGIN
MENUITEM "&New" ,IDM_New
MENUITEM "&Open" ,IDM_Open ,MFT_MENUBREAK
MENUITEM "&Save" ,IDM_Save
MENUITEM SEPARATOR
MENUITEM "E&xit" ,IDM_Exit
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,IDM_Cut
MENUITEM "&Copy" ,IDM_Copy ,MFT_MENUBARBREAK
MENUITEM "&Paste" ,IDM_Paste
END
POPUP "&Help" ,65535 ,MFT_RIGHTJUSTIFY
BEGIN
MENUITEM "&About" ,IDM_About
END
END
调用后的效果图:
再如: MFT_RIGHTORDER(右对齐)示例如下:
#define IDM_New 101
#define IDM_Open 102
#define IDM_Save 103
#define IDM_Exit 104
#define IDM_Cut 201
#define IDM_Copy 202
#define IDM_Paste 203
#define IDM_About 301
MYMENU1 MENUEX
BEGIN
POPUP "&File" ,65535
BEGIN
MENUITEM "&New" ,IDM_New ,MFT_RIGHTORDER ,MFS_CHECKED
MENUITEM "&Open" ,IDM_Open
MENUITEM "&Save" ,IDM_Save
MENUITEM SEPARATOR
MENUITEM "E&xit" ,IDM_Exit
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,IDM_Cut
MENUITEM "&Copy" ,IDM_Copy
MENUITEM "&Paste" ,IDM_Paste
END
POPUP "&Help" ,65535
BEGIN
MENUITEM "&About" ,IDM_About
END
END
调用后的效果图:
还是 MFT_RIGHTORDER(右对齐) 的例子:
#define IDM_New 101
#define IDM_Open 102
#define IDM_Save 103
#define IDM_Exit 104
#define IDM_Cut 201
#define IDM_Copy 202
#define IDM_Paste 203
#define IDM_About 301
MYMENU1 MENUEX
BEGIN
POPUP "&File" ,65535 ,MFT_RIGHTORDER
BEGIN
MENUITEM "&New" ,IDM_New
MENUITEM "&Open" ,IDM_Open
MENUITEM "&Save" ,IDM_Save
MENUITEM SEPARATOR
MENUITEM "E&xit" ,IDM_Exit
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,IDM_Cut
MENUITEM "&Copy" ,IDM_Copy
MENUITEM "&Paste" ,IDM_Paste
END
POPUP "&Help" ,65535
BEGIN
MENUITEM "&About" ,IDM_About
END
END
第三部分:
前面我们分别使用过 MENU 和 MENUEX 来指定菜单资源, 我发现用 MENU 不必注意大小写; 但 MENUEX 在使用参数时需要注意大小写! 另外, 指定相同的功能时, 它们使用的参数和格式也有很大的区别. 我想还是多了解 MENUEX 吧, 因为它的参数同时也是 Win32API 菜单函数们 需要的!
MENUEX 有四个参数, 分别是: 菜单文本, 菜单标识(整数), 菜单格式(常数: MFT_*), 菜单样式(常数: MFS_*).
后两个参数都有系统预定义的常量, 列表如下:
MFT_STRING = 0; {菜单项是字符串}
MFT_BITMAP = 4; {菜单项用一个图片来代替(暂没测试)}
MFT_MENUBARBREAK = $20; {换列并有分列线}
MFT_MENUBREAK = $40; {换列}
MFT_OWNERDRAW = $100; {指定为物主菜单; 通过 WM_DRAWITEM 消息的申请可以绘制更复杂的菜单}
MFT_RADIOCHECK = $200; {圆点代替 √ 来表示选择
MFT_SEPARATOR = $800; {指定为分割线, 会忽略前面指定的菜单文本}
MFT_RIGHTORDER = $2000; {右对齐}
MFT_RIGHTJUSTIFY = $4000; {显示在右边(帮助位置)}
MFS_GRAYED = 3; {禁止使用, 灰度显示}
MFS_DISABLED = MFS_GRAYED; {同上}
MFS_CHECKED = 8; {选择}
MFS_HILITE = $80; {反色凸现}
MFS_ENABLED = 0; {不禁止, 这是默认的, 一般用于程序中对禁止的反操作}
MFS_UNCHECKED = 0; {不选择}
MFS_UNHILITE = 0; {不反色}
MFS_DEFAULT = $1000; {指定为缺省, 应该类似与缺省按钮(还没试过), 会加粗显示菜单文本}
以上同类参数可以通过 "或" 运算来同时指定功能, 当然这里不能使用 Delphi 的 "or", 是用 C/C++ 的 "|" 运算符. 再举个例子:
#define IDM_New 101
#define IDM_Open 102
#define IDM_Save 103
#define IDM_Exit 104
#define IDM_Cut 201
#define IDM_Copy 202
#define IDM_Paste 203
#define IDM_About 301
MYMENU1 MENUEX
BEGIN
POPUP "&File" ,65535
BEGIN
MENUITEM "&New" ,IDM_New ,MFT_STRING | MFT_RIGHTORDER ,MFS_DEFAULT | MFS_CHECKED | MFS_GRAYED
MENUITEM "&Open" ,IDM_Open ,MFT_STRING, MFS_HILITE
MENUITEM "&Save" ,IDM_Save
MENUITEM SEPARATOR
MENUITEM "E&xit" ,IDM_Exit
END
POPUP "&Edit" ,65535
BEGIN
MENUITEM "Cu&t" ,IDM_Cut
MENUITEM "&Copy" ,IDM_Copy
MENUITEM "&Paste" ,IDM_Paste
END
POPUP "&Help" ,65535
BEGIN
MENUITEM "&About" ,IDM_About
END
END