📄 10. 菜单及其它资源.txt
字号:
当窗口被清除时,与窗口相关的所有菜单都将被清除。与窗口不相关的菜单在程序结束前通过呼叫DestroyMenu主动清除。
菜单和消息
当使用者选择一个菜单项时,Windows通常向窗口消息处理程序发送几个不同的消息。在大多数情况下, 您的程序可以忽略大部分消息,只需把它们传递给DefWindowProc即可。WM_INITMENU就是这一类的消息,它具有下列参数:
wParam: 主菜单句柄
lParam: 0
wParam值是您的主菜单句柄,即使使用者选择的是系统菜单中的项目。Windows程序通常忽略WM_INITMENU消息。尽管在选中该项之前的消息已经给程序提供了修改菜单的机会,但是我们觉得此刻改变顶层菜单是会扰乱使用者的。
程序也会接收到WM_MENUSELECT消息。随着使用者在菜单项中移动光标或者鼠标,程序会收到许多WM_MENUSELECT消息。这对实作那些包含对菜单项的文字描述的状态列是很有帮助的。WM_MENUSELECT的参数如下所示:
LOWORD (wParam):被选中项目:菜单ID或者弹出式菜单句柄
HIWORD (wParam):选择旗标
lParam: 包含被选中项目的菜单句柄
WM_MENUSELECT是一个菜单追踪消息,wParam的值告诉您目前选择的是菜单中的哪一项(加高亮度显示的那个),wParam的高字组中的「选择旗标」可以是下列这些旗标的组合:MF_GRAYED、MF_DISABLED、MF_CHECKED、MF_BITMAP、MF_POPUP、MF_HELP、MF_SYSMENU和MF_MOUSESELECT。如果您需要根据对菜单项的选择来改变窗口显示区域的内容,那么您可以使用WM_MENUSELECT消息。许多程序把该消息发送给DefWindowProc。
当Windows准备显示一个弹出式菜单时,它给窗口消息处理程序发送一个WM_INITMENUPOPUP消息,参数如下:
wParam: 弹出式菜单句柄
LOWORD (lParam):弹出式菜单索引
HIWORD (lParam): 系统菜单为1,其它为0
如果您需要在显示弹出式菜单之前启用或者禁用菜单项,那么这个消息就很重要。例如,假定程序使用弹出式菜单上的 Paste命令从剪贴簿复制文字,当您收到弹出式菜单中的WM_INITMENUPOPUP消息时,应确定剪贴簿内是否有文字存在。如果没有,那么应该使 Paste菜单项无效化。我们将在本章后面修改的POPPAD程序中看到这样的例子。
最重要的菜单消息是WM_COMMAND,它表示使用者已经从菜单中选中了一个被启用的菜单项。第八章中的WM_COMMAND消息也可以由子窗口控件产生。如果您碰巧为菜单和子窗口控件使用同一ID码,那么您可以通过lParam的值来区别它们,菜单项的lParam其值为0,请参见表10-1。
表10-1
菜单
控件
LOWORD (wParam):
菜单ID
控件ID
HIWORD (wParam):
0
通知码
lParam:
0
子窗口句柄
WM_SYSCOMMAND消息类似于WM_COMMAND消息,只是WM_SYSCOMMAND表示使用者从系统菜单中选择一个启用的菜单项:
wParam: 菜单ID
lParam: 0
然而,如果WM_SYSCOMMAND消息是由按鼠标按键产生的,LOWORD(lParam)和HIWORD(lParam)将包含鼠标光标位置的x和y屏幕坐标。
对于WM_SYSCOMMAND,菜单ID指示系统菜单中的哪一项被选中。对于预先定义的系统菜单项,较低的那四个位应该和0xFFF0进行AND运算来屏蔽掉,结果值应该为下列之一: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的低字组将是您定义的菜单ID。为了避免与预先定义的菜单ID相冲突,应用程序应该使用小于0xF000的值,这对于将一般的WM_SYSCOMMAND消息发送给DefWindowProc是很重要的。如果您不这样做,那么您实际上就是禁用了正常的系统菜单命令。
我们将讨论的最后一个消息是WM_MENUCHAR。实际上,它根本不是菜单消息。在下列两种情况之一发生时,Windows会把这个消息发送到窗口消息处理程序:如果使用者按下Alt和一个与菜单项不匹配的字符时,或者在显示弹出式菜单而使用者按下一个与弹出式菜单里的项目不匹配的字符键时。随WM_MENUCHAR消息一起发送的参数如下所示:
LOWORD (wParam): 字符代码(ASCII或Unicode)
HIWORD (wParam): 选择码
lParam: 菜单句柄
选择码是:
0 不显示弹出式菜单
MF_POPUP 显示弹出式菜单
MF_SYSMENU 显示系统弹出式菜单
Windows程序通常把该消息传递给DefWindowProc,它一般给Windows传回0,这会使Windows发出哔声。在 第十四章GRAFMENU程序中会看到WM_MENUCHAR消息的使用。
范例程序
让我们来看一个简单的例子。程序10-4所示的MENUDEMO程序,在主菜单中有五个选择项-File、Edit、Background、Timer和Help,每一项都与一个弹出式菜单相连。MENUDEMO只完成了最简单、最通用的菜单处理操作,包括拦截WM_COMMAND消息和检查wParam的低字组。
程序10-4 MENUDEMO
MENUDEMO.C
/*---------------------------------------------------------------------
MENUDEMO.C -- Menu Demonstration
(c) Charles Petzold, 1998
-----------------------------------------------------------------------*/
#include <windows.h>
#include "resource.h"
#define ID_TIMER 1
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
TCHAR szAppName[] = TEXT ("MenuDemo") ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = szAppName ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox ( NULL, TEXT ("This program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow ( szAppName, TEXT ("Menu Demonstration"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc ( HWND hwnd, UINT message, WPARAM wParam,LPARAM lParam)
{
static int idColor [5] = { WHITE_BRUSH, LTGRAY_BRUSH, GRAY_BRUSH,
DKGRAY_BRUSH, BLACK_BRUSH } ;
static int iSelection = IDM_BKGND_WHITE ;
HMENU hMenu ;
switch (message)
{
case WM_COMMAND:
hMenu = GetMenu (hwnd) ;
switch (LOWORD (wParam))
{
case IDM_FILE_NEW:
case IDM_FILE_OPEN:
case IDM_FILE_SAVE:
case IDM_FILE_SAVE_AS:
MessageBeep (0) ;
return 0 ;
case IDM_APP_EXIT:
SendMessage (hwnd, WM_CLOSE, 0, 0) ;
return 0 ;
case IDM_EDIT_UNDO:
case IDM_EDIT_CUT:
case IDM_EDIT_COPY:
case IDM_EDIT_PASTE:
case IDM_EDIT_CLEAR:
MessageBeep (0) ;
return 0 ;
case IDM_BKGND_WHITE: // Note: Logic below
case IDM_BKGND_LTGRAY: // assumes that IDM_WHITE
case IDM_BKGND_GRAY: // through IDM_BLACK are
case IDM_BKGND_DKGRAY: // consecutive numbers in
case IDM_BKGND_BLACK: // the order shown here.
CheckMenuItem (hMenu, iSelection, MF_UNCHECKED) ;
iSelection = LOWORD (wParam) ;
CheckMenuItem (hMenu, iSelection, MF_CHECKED) ;
SetClassLong (hwnd, GCL_HBRBACKGROUND, (
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -