El proceso de creación de un menú en la aplicación de Windows es el siguiente:
1. Crea recursos de menú
2. Recurso del menú de carga de la aplicación
3. La aplicación responde a los mensajes de eventos del menú.
Primero distinga algunos conceptos:
<1> "Menú principal" y "Menú principal" tienen el mismo significado.
<2> Los elementos del menú principal se denominan "menú emergente" o "submenú".
<3> El elemento del menú emergente puede ser otro menú emergente.
<4> El estado del menú: habilitado, deshabilitado. Invalidación, la diferencia entre la invalidación y los dos anteriores es el texto de la pantalla gris.
1. Crea recursos de menú
Al crear recursos de menú, puede usar dos métodos: uno es usar el editor IDE para crear el menú; el otro es editar el archivo .rc manualmente. El primer método se usa en muchos libros de texto MFC. Estoy aquí Principalmente presenta métodos manuales para editar los recursos del menú, que ayudarán a todos a comprender los recursos de la programación IDE.
Si crea un recurso de menú en la secuencia de comandos de recurso * .rc, debe crear un archivo * .H correspondiente, que se utiliza para resolver el problema de referencia de símbolo del identificador de recurso.
Pero hay un accidente, el nombre del menú debe ser un símbolo y la cadena de nombre no se puede utilizar. La siguiente es la sintaxis básica de la descripción de MEMU que se encuentra comúnmente en archivos * .rc:
MENU_NAME MENU DISCARDABLE
{
POPUP “name”
{
MENUITEM “name”, MENU_ID
}
}
MENU_NAME puede ser una cadena de nombre o un símbolo. La palabra clave DISCARDABLE está un poco desactualizada pero aún es necesaria. Las definiciones del menú de primer nivel en el menú comienzan todas con la palabra clave POPUP. Los elementos del menú están definidos por MENUITEM, como para MENU_ID es definido en el archivo * .h. El siguiente ejemplo:
// .RC资源文件中
MainMenu MENU DISCARDABLE
{
POPUP "File"
{
MENUITEM"Open", MENU_FILE_ID_OPEN
MENUITEM"Close", MENU_FILE_ID_CLOSE
MENUITEM"Save", MENU_FILE_ID_SAVE
MENUITEM"Exit", MENU_FILE_ID_EXIT
} // end popup
POPUP "Help"
{
MENUITEM"About", MENU_HELP_ABOUT
} // end popup
} // end top level menu
// .H文件中
// defines for the top level menu FILE
#define MENU_FILE_ID_OPEN 1000
#define MENU_FILE_ID_CLOSE 1001
#define MENU_FILE_ID_SAVE 1002
#define MENU_FILE_ID_EXIT 1003
// defines for the top level menu HELP
#define MENU_HELP_ABOUT 2000
在这里没有定义”MainMenu”, 这样可以通过字符串而不是ID来访问该菜单. 如果我向如下方式定义了该项的ID
#define MainMenu 100
Debe utilizar MAKEINTRESOURCE (MainMenu) o MAKEINTRESOURCE (100) para acceder a este recurso de menú.
Si desea configurar una tecla de acceso rápido o una tecla de acceso directo, puede usar el guión (&) para lograr esta función. Por ejemplo:
MENUITEM “E&xit”, MENU_FILE_ID_EXIT
Haga x una tecla de acceso rápido y
POPUP “&File”
Hacer de F una tecla de método abreviado utilizada por Alt + F
2. Cargar menú
En la definición de la clase de Windows, el código que define el menú es:
WNDCLASSEX wnd;
wnd.lpszMenuName = NULL; //默认情况下
Simplemente asígnelo al nombre del menú:
wnd.lpszMenuName = “MainMenu”;
o
wnd.lpszMenuName = MAKEINTRESOURCE(MainMenu);
De esta manera, todas las ventanas creadas tendrán el mismo menú. Para resolver este problema, puede asignar un menú a una ventana pasando el identificador del menú durante el proceso de creación del menú. Cargue el recurso del menú a través de LoadMenu (), si tiene éxito, se devolverá un identificador HMENU.
LoadMenu()原型:
HMENU LoadMenu(HINSTANCE hInstance, // handle of applicationinstance
LPCTSTRlpMenuName); // menu name string or menu-resource identifier
Cargue el menú "ManiMenu" en el parámetro del identificador del menú a través de la función estándar CreateWindow ():
// create the window
hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, “Sound”,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 400, 400, NULL,
LoadMenu(hinstance, “MainMenu”), hinstance, NULL);
La última forma de asociar el menú a la ventana es llamar a la función SetMenu ():
BOOL SetMenu( HWND hwnd, // handle of window to attach to
HMENUhMenu); // handle of menu
SetMenu () asocia directamente el menú a una ventana, este nuevo menú tendrá prioridad sobre cualquier menú asociado previamente. Por ejemplo:
// …
wnd.lpszMenuName = NULL;
// …
hwnd = CreateWindowEx(NULL, WINDOW_CLASS_NAME, “Sound”,
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 400, 400, NULL,
NULL, // handle to menu ,note it’s null.
hinstance, NULL);
//…
// load the menu resource
HMENU hMenu = LoadMenu(hinstance, “MainMenu”);
// attach the menu to the window
SetMenu(hwnd, hMemu);
Mensajes en respuesta a eventos del menú
El mensaje que pasa cuando suelta el mouse después de seleccionar un elemento del menú. Esto se refiere a un proceso de selección. El proceso de selección pasa un mensaje WM_COMMAND a la función WinProc de la ventana asociada con el menú. El ID del elemento de menú especificado y varios otros Los datos se almacena en el wparam y lparam del mensaje, como se muestra a continuación:
msg --- WM_COMMAND
LOWORD (lparam) ---- El identificador de la ventana que envió el mensaje
wparam --- ID del elemento de menú seleccionado
Posibles errores en la compilación:
DemoMenu.obj: error LNK2001: símbolo externo no resuelto__imp__PlaySoundA @ 12
Agregue winmm.lib al proyecto, proceso: Proyecto -> Configuración -> Conexión -> Agregar winmm.lib en las opciones del proyecto.
Acerca de la función de menú
La operación del menú no es más que agregar, eliminar, modificar y verificar cuatro operaciones desde la dirección general.
4.1 HMENUCreateMenu (VOID);
4.2 BOOL AppendMenu (HMENU hMenu, // manejar al menú
UINT uFlags, // opciones de elementos de menú
UINT_PTR uIDNewItem, // identificador, menú o submenú
LPCTSTR lpNewItem // contenido del elemento de menú);
4.3 BOOLInsertMenu (HMENU hMenu, // manejar al menú
UINT uPosition, // elemento al que precede el nuevo elemento
UINT uFlags, // opciones
UINT_PTR uIDNewItem, // identificador, menú o submenú
LPCTSTR lpNewItem // contenido del elemento de menú);
4.4 BOOLInsertMenuItem (HMENU hMenu, // manejar al menú
UINT vital // identificador o posición
BOOL fByPosition, // significado de uItem
LPCMENUITEMINFO lpmii // información del elemento del menú);
Menú contextual
El menú del botón derecho no es diferente del menú normal. Justo cuando aparece. Necesito usar esta función
BOOLTrackPopupMenu( HMENU hMenu, // handle to shortcut menu
UINT uFlags, // options
int x, // horizontal position
int y, // vertical position
int nReserved, // reserved, must be zero
HWND hWnd, // handle to owner window
CONST RECT *prcRect // ignored);
El parámetro uFlags especifica la alineación del menú en el menú, haga clic con el botón izquierdo y haga clic con el botón derecho para seleccionar el elemento del menú
TPM_CENTERALIGN。TMP_LEFTALIGN。TMP_RIGHTALIGN
TPM_BOTTOMALIGN, TPM_TOPALIGN, TPM_VCENTERALIGN
TPM_LEFTBUTTPON, TPM_RIGHTBUTTON
TPM_NONOTIFY, TPM_RETURNCMD
Menu del sistema
Obtener el identificador del menú del sistema
HMENU GetSystemMenu (
HWNDhWnd, // manejar a la ventana
BOOL bRevert // opción de reinicio);
Cuando bRevert = FALSE. Dijo. Copie el menú del sistema y devuelva el controlador del menú de copia, este menú se puede cambiar. Cuando bRevert = TRUE, configure el menú del sistema en el estado original predeterminado. Y el valor de retorno de la función es NULL.
Acelerador
La tecla de aceleración también es un tipo de recurso, puede usar la tecla de método abreviado para abrir el elemento de comando rápidamente. Las teclas de aceleración se pueden agregar en los propios recursos o se pueden escribir directamente en el programa.
while(GetMessage(&msg,NULL,0,0))
{
if (!TranslateAccelerator(hWnd,hAccel,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
Aquí la función TranslateAccelerator traduce algunos mensajes de pulsación de teclas en mensajes WM_COMMAND o WM_SYSCOMMAND.
Ejemplo de demostración de código
La siguiente demostración es una demostración de menú que se basa completamente en el código y no se basa en la creación de recursos, incluida la barra de menú.
El menú contextual, el menú del sistema y las teclas de aceleración pueden cambiar y eliminar dinámicamente el menú. Únete a la operación.
#define OEMRESOURCE
# include<Windows.h>
#define IDM_FILE_OPEN 100
#define IDM_FILE_NEW 101
#define IDM_FILE_PIC 102
#define IDM_FILE_EXIT 103
#define IDM_MENU_ADD 104
#define IDM_MENU_REM 105
#define IDM_MENU_DEL 106
#define IDM_MENU_MOD 107
#define IDM_ABOUT 108
#define IDM_VERSION 109
#define IDM_MENU_NEW 110
#define IDM_POP_ONE 200
#define IDM_POP_TWO 201
#define IDM_SYS_ONE 300
#define IDM_SYS_TWO 301
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam);
HMENU createOwnMenu(HWND hwnd);
HMENU createPopMenu(HWND hwnd);
HACCEL createAccelerator(HWND hwnd);
TCHAR* szAppName = TEXT("MenuClass");
TCHAR* szWndName = TEXT("ChangeMenu");
HACCEL hAccel = NULL;
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPreInstance,LPSTR lpCmdLine,int iCmdShow)
{
WNDCLASS wndCls;
HWND hWnd;
MSG msg;
wndCls.cbClsExtra = 0;
wndCls.cbWndExtra = 0;
wndCls.lpfnWndProc = WndProc;
wndCls.style = CS_HREDRAW | CS_VREDRAW;
wndCls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndCls.hCursor = LoadCursor(NULL,IDC_ARROW);
wndCls.hIcon = LoadIcon(NULL,IDI_APPLICATION);
wndCls.hInstance = hInstance;
wndCls.lpszClassName = szAppName;
wndCls.lpszMenuName = NULL;
if(!RegisterClass(&wndCls))
{
MessageBox(NULL,TEXT("Register window failed"),TEXT("Error"),MB_OK);
}
hWnd = CreateWindow(szAppName,szWndName,WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
UpdateWindow(hWnd);
ShowWindow(hWnd,SW_NORMAL);
while(GetMessage(&msg,NULL,0,0))
{
if(!TranslateAccelerator(hWnd,hAccel,&msg))
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
{
static int nAdd = 1;
HMENU hMenu,hSonMenu,hTmpMenu;
HMENU hTrack,hSon;
HMENU hSysMenu;
POINT pt;
switch(msg)
{
case WM_CREATE:
hMenu = createOwnMenu(hwnd);
SetMenu(hwnd,hMenu);
hSysMenu = GetSystemMenu(hwnd,FALSE);
AppendMenu(hSysMenu,MF_SEPARATOR,0,NULL);
AppendMenu(hSysMenu,MF_STRING,IDM_SYS_ONE,TEXT("SysOne"));
AppendMenu(hSysMenu,MF_STRING,IDM_SYS_TWO,TEXT("SysTwo"));
hAccel = createAccelerator(hwnd);
break;
case WM_SYSCOMMAND:
switch(LOWORD(wParam))
{
case IDM_SYS_ONE:
MessageBox(NULL,TEXT("This is added system menu item1"),NULL,MB_OK);
break;
case IDM_SYS_TWO:
MessageBox(NULL,TEXT("This is added system menu item2"),NULL,MB_OK);
break;
}
break;
case WM_COMMAND:
hMenu = GetMenu(hwnd);
switch(LOWORD(wParam))
{
case IDM_FILE_OPEN:
MessageBox(NULL,TEXT("File Open selected"),TEXT("Test check"),MB_OK);
break;
case IDM_MENU_ADD:
hTmpMenu = GetSubMenu(hMenu,2);
AppendMenu(hTmpMenu,MF_STRING,IDM_MENU_NEW+nAdd,TEXT("New Item"));
nAdd++;
DrawMenuBar(hwnd);
break;
case IDM_MENU_REM:
hTmpMenu = GetSubMenu(hMenu,2);
if( nAdd >1 )
{
nAdd--;
RemoveMenu(hTmpMenu,IDM_MENU_NEW+nAdd,MF_BYCOMMAND);
}
// 当菜单项时弹出菜单的时候,只切断弹出菜单跟所属菜单的联系,但不销毁对象
/*GetSubMenu(hTmpMenu,2);
RemoveMenu(hTmpMenu,2,MF_BYPOSITION);*/
DrawMenuBar(hwnd);
break;
case IDM_MENU_MOD:
hTmpMenu = GetSubMenu(hMenu,2);
ModifyMenu(hTmpMenu,0,MF_BYPOSITION,IDM_ABOUT,TEXT("Modified Item"));
DrawMenuBar(hwnd);
break;
case IDM_MENU_DEL:
hTmpMenu = GetSubMenu(hMenu,2);
DeleteMenu(hTmpMenu,2,MF_BYPOSITION);
DrawMenuBar(hwnd);
break;
}
break;
case WM_RBUTTONDOWN:
hTrack = createPopMenu(hwnd);
hSon = GetSubMenu(hTrack,0);
pt.x = LOWORD(lParam);
pt.y = HIWORD(lParam);
ClientToScreen(hwnd,&pt);
TrackPopupMenu(hSon,TPM_LEFTBUTTON| TPM_RIGHTALIGN,pt.x,pt.y,0,hwnd,NULL);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return DefWindowProc(hwnd,msg,wParam,lParam);
}
HMENU createOwnMenu(HWND hwnd)
{
HMENU hMenu = CreateMenu();
HMENU hPopMenu = CreateMenu();
//MF_BYPOSIOTION,MF_BYCOMMAND is not useful here in AppendMenu
AppendMenu(hPopMenu,MF_STRING|MF_CHECKED|MF_GRAYED,IDM_FILE_OPEN,TEXT("&Open"));
InsertMenu(hPopMenu,0,MF_BYPOSITION|MF_STRING|MF_DISABLED,IDM_FILE_NEW,TEXT("&New"));
HINSTANCE hInstance = (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE);
HBITMAP hBmp = (HBITMAP)LoadImage(hInstance,TEXT("bitmap1.bmp"),IMAGE_BITMAP,0,0,LR_LOADFROMFILE);
AppendMenu(hPopMenu,MF_BITMAP,IDM_FILE_PIC,(LPCWSTR)hBmp);
AppendMenu(hPopMenu,MF_SEPARATOR,NULL,NULL);
AppendMenu(hPopMenu,MF_STRING,IDM_FILE_EXIT,TEXT("&Exit"));
SetMenuItemBitmaps(hPopMenu,IDM_FILE_PIC,MF_BYCOMMAND,hBmp,hBmp);
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPopMenu,TEXT("File"));
hPopMenu = CreateMenu();
AppendMenu(hPopMenu,MF_STRING,IDM_MENU_ADD,TEXT("&Add"));
AppendMenu(hPopMenu,MF_STRING,IDM_MENU_REM,TEXT("&Remove"));
AppendMenu(hPopMenu,MF_STRING,IDM_MENU_MOD,TEXT("&Modify"));
AppendMenu(hPopMenu,MF_STRING,IDM_MENU_DEL,TEXT("&Delete"));
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPopMenu,TEXT("Menu"));
hPopMenu = CreateMenu();
AppendMenu(hPopMenu,MF_STRING,IDM_ABOUT,TEXT("About"));
AppendMenu(hPopMenu,MF_STRING,IDM_VERSION,TEXT("Version"));
HMENU hSonMenu = CreateMenu();
AppendMenu(hSonMenu,MF_STRING,IDM_MENU_NEW,TEXT("Son"));
AppendMenu(hPopMenu,MF_POPUP,(UINT_PTR)hSonMenu,TEXT("Son Menu"));
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPopMenu,TEXT("Change"));
return hMenu;
}
HMENU createPopMenu(HWND hwnd)
{
HMENU hMenu = CreateMenu();
HMENU hPop = CreateMenu();
AppendMenu(hPop,MF_STRING,IDM_POP_ONE,TEXT("One"));
AppendMenu(hPop,MF_STRING,IDM_POP_TWO,TEXT("Twod"));
AppendMenu(hMenu,MF_POPUP,(UINT_PTR)hPop,TEXT("Pop"));
return hMenu;
}
HACCEL createAccelerator(HWND hwnd)
{
ACCEL acce[2];
acce[0].fVirt = FCONTROL | FNOINVERT | FVIRTKEY;
acce[0].key = 'A';
acce[0].cmd = IDM_MENU_ADD;
acce[1].fVirt = FCONTROL | FNOINVERT | FVIRTKEY;
acce[1].key = 'R';
acce[1].cmd = IDM_MENU_REM;
HACCEL hAccel = CreateAcceleratorTable(acce,2);
return hAccel;
}
El aprendizaje es, en última instancia, un proceso de aprendizaje y práctica y aplicación de lo aprendido. Por lo tanto, el autor ha creado una plataforma para que todos se comuniquen y aprendan. Durante el proceso de aprendizaje, puede encontrar varios problemas. Puede hacer preguntas en la plataforma. Hay expertos profesionales para responderle. Todos tienen años de programación. Experiencial , lo más importante es que poco a poco irás superando el miedo a las dificultades, ya no te preocupes por no poder entender o aprender, hay un mejor ambiente de aprendizaje y paquetes de regalo de aprendizaje gratuitos.