如有需要请参考“Windows程序设计”一书的第十章的第二节(本文未完 待续)
10.2 菜单
一些菜单概念:主菜单、顶层菜单、下拉式菜单、弹出式菜单、子菜单、系统菜单、菜单项;启用、禁用、灰化、激活、不激活菜单。
可以把顶层菜单和每一个弹出式菜单看作是独立的菜单。顶层菜单有一个句柄,而顶层菜单中的每一个弹出式菜单也有它自己的句柄。系统菜单(也是一个弹出式菜单)也有一个句柄。
每一个菜单项有三个特性:(1)菜单项中显示的内容。(2)菜单项的ID;如果是弹出式菜单,那么就是弹出式菜单的句柄。(3)菜单项的属性:包括是否被禁用、灰化或被选中。
在程序中添加菜单有两种方法:(1)在资源描述文件(.rc)中添加菜单,然后在窗口类结构的lpszMenuName字段中、在CreateWindow函数中或者在窗口过程(WndProc)的WM_CREATE消息中引用该菜单。(2)在运行过程中全部用代码来添加菜单,而不使用资源描述文件,不过这种方法相对来说比较麻烦。
你所指定的菜单项的ID值是Windows发送给窗口过程中菜单消息中的数值。在菜单中ID值应该是唯一的。按照习惯,我们一般使用以“IDM(ID for a Menu)”开头的标识符,例如使用“IDM_FILE_OPEN”来表示“文件”菜单中的“打开”这个菜单项。
在上面提过,当使用资源描述文件来添加菜单的时候,在代码中引用菜单有三种方法:(1)第一种是在窗口类结构中引用,例如:wndClass.lpszMenuName = szMenuName,其中的szMenuName是资源描述文件中的菜单名称。(2)第二种方法是通过LoadMenu函数来将菜单资源加载到内存中,LoadMenu函数会返回一个菜单句柄hMenu,然后你在CreateWindow函数中指定这个句柄。(3)如果你没有在窗口类结构和CreateWindow函数中指定菜单,那么你可以在窗口过程(WndProc)的WM_CREATE消息中指定,具体方法为:SetMenu(hWnd, hMenu),其中hMenu是LoadMenu函数返回的菜单句柄。
至于在运行过程中全部用代码来添加菜单的具体实现方法,请参考后面的“实例”。
当窗口被清除的时候,同窗口相关的所有菜单都会被自动清除。同窗口不相关的菜单(也就是没有被指定给任何窗口的)在程序结束前要通过调用DestroyMenu函数来显式地清除掉。
当用户选择菜单项时,Windows会向应用程序的窗口过程发送几个不同的消息。在很多情况下,我们的应用程序可以忽略大部分消息,只须将它们传递给DefWindowProc函数就行了。
一般应用程序需要处理的几个菜单消息有:
(1)WM_INITMENU菜单消息。这个消息在初始化主菜单时产生,如果程序员想拥有像Office 2003那样的菜单,就可以处理这个消息并重画主菜单。这个消息具有下列参数:
wParam:主菜单句柄
lParam:0
其中wParam的值是主菜单的句柄,即使用户选择的是系统菜单中的项。
(2)WM_MENUSELECT菜单消息。当用户在菜单项中拖动鼠标的时候,你的应用程序的窗口过程会收到很多WM_MENUSELECT菜单消息,这时我们可以在状态栏中显示对该菜单项的文本描述。这个消息具有下列参数:
LOWORD(wParam):菜单项的ID或弹出式菜单的句柄。
HIWORD(wParam):选择标志。
lParam:包含该菜单项的菜单句柄。
这个消息是一个菜单跟踪消息。其中wParam的低位字的值告诉你当前选择的是那一个菜单项(该菜单项会被加亮);wParam的高位字的值是“选择标志”,它可以是下列标志的组合:MF_GRAYED、MF_DISABLED、MF_CHECKED、MF_BITMAP、MF_POPUP、MF_HELP、MF_SYSMENU和MF_MOUSESELECT。如果你要实现Office 2003那样的菜单,你需要在这个消息产生时作一些处理,例如重画这个菜单项。
(3)WM_INITMENUPOPUP菜单消息。当Windows准备显示一个弹出式菜单时,它就会给应用程序的窗口过程发送这个消息。如果需要在显示弹出式菜单之前启用或禁用某些菜单项,我们就需要处理这个消息了。这个消息具有下列参数:
wParam:弹出式菜单句柄。
LOWORD(lParam):弹出式菜单索引。
HIWORD(lParam):系统菜单为1,其他为0。
如果你要实现Office 2003那样的菜单,你也需要在这个消息产生时作一些处理,例如重画弹出式菜单,使它具有Office 2003那样的菜单外观。
(4)WM_COMMAND菜单消息。这个菜单消息是最重要的,它表示用户已经选中(单击)了一个被启用的菜单项。对于没有被启用的菜单项,Windows是不会给窗口过程发送该消息的。WM_COMMAND消息也可以由子窗口控制产生,但它们是有区别的,具体如下:
LOWORD(wParam):如果是菜单,则为菜单ID;如果是子窗口控制,则为控制ID。
HIWORD(wParam):如果是菜单,则为0;如果是子窗口控制,则为通知码。
lParam:如果是菜单,则为0;如果是子窗口控制,则为子窗口的句柄。
(5)WM_SYSCOMMAND菜单消息。它在用户从系统菜单中选中(单击)某一菜单项时产生。这个消息具有下列参数:
wParam:菜单ID。
lParam:0。
如果WM_SYSCOMMAND消息是由于按鼠标键而产生的,那么LOWORD(lParam)和HIWORD(lParam)将包含鼠标指针所在位置的屏幕坐标X和Y。菜单ID指示系统菜单中的哪一项被选中(单击)了。对于系统菜单中原有的菜单项的ID,应该通过和0xFFF0进行“与”操作来屏蔽掉低4位,这样得出来的结果值应该为下列之一:SC_SIZE、SC_MOVE、SC_MINIMIZE、SC_MAXIMIZE、SC_NEXTWINDOW、SC_PREVWINDOW、SC_CLOSE、SC_VSCROLL、SC_HSCROLL、SC_ARRANGE、SC_RESTORE和SC_TASKLIST,这些值表示选中了具体那一个系统菜单项。此外,wParam的值还可以是SC_MOUSEMENU或SC_KEYMENU。
如果您在系统菜单中添加了自定义的菜单项,那么wParam的低位字(LOWORD(wParam))就是你自定义的系统菜单项的ID。为了避免与系统菜单中原有的菜单项的ID相冲突,应用程序应该使用小于0xF000的值作为自定义的系统菜单项的ID。
(6)WM_MENUCHAR菜单消息。如果用户按下Alt键和一个与菜单项中加了下划线的字符不匹配的字符键时,或者当显示弹出式菜单而用户按下一个与弹出式菜单里头的菜单项中加了下划线的字符不匹配的字符键时,那么Windows就会把这个消息发送到你的应用程序中的窗口过程。这个消息具有下列参数:
LOWORD(wParam):字符代码(ASCII或Unicode)。
HIWORD(wParam):选择码。
lParam:菜单句柄。
其中选择码可以是下列值:
0 不显示弹出式菜单。
MF_POPUP 显示弹出式菜单。
MF_SYSMENU 显示系统弹出式菜单。
应用程序一般不需要处理这个消息,而应把它传递给DefWindowProc函数来处理。
(本文未完 待续)