15菜单、热键、光标
系统菜单
如图,这是系统给出的菜单,也可以通过资源视图-》Menu进行修改。
通过结构体WNDCLASSEX wcex 进行加载:
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_MENUDEMO2);
菜单的互斥
点击某一菜单,其他菜单变成不可选择。
利用EnablemenuItem() 处理,有以下两种方式:
1.EnableMenuItem(hMenu,2,MF_GRAYED|MF_BYPOSITION);
通过菜单的相对位置进行设置,选择后整个菜单栏都会变灰。如上图位置,“描图”为0,“颜色”为1,“帮助为3”。。。。
注意:若第二参数使用相对位置,那么第三个参数必须使用MF_BYPOSITION。MF_GRAYED灰度化,使2位置变灰,不可选择。
2.EnableMenuItem(hMenu,IDM_ABOUT,MF_GRAYED|MF_BYCOMMAND);
通过对应的菜单选项的ID进行设置,此方法可以单独设置某一选择或多个选择,不是整一个菜单栏都不可选择。
注意:若第二参数使用ID,那么第三个参数必须使用MF_ BYCOMMAND。
菜单的勾选
点击某一菜单选项后,其前面出现选中状态。
通过WM_INITMENUPOPUP:响应消息,及函数CheckMenuItem()。
case WM_INITMENUPOPUP:
if(uFlat==IDM_POINT)
CheckMenuItem(hMenu,IDM_POINT,MF_BYCOMMAND|MF_CHECKED);
else
CheckMenuItem(hMenu,IDM_POINT,MF_BYCOMMAND|MF_UNCHECKED);
uFlat为临时变量,判断是否被选中。
CheckMenuItem(hMenu,IDM_POINT,MF_BYCOMMAND|MF_UNCHECKED);
MF_UNCHECKED 不选中。
MF_CHECKED 选中
自定义菜单(右键菜单)
方法与上面的相同,在资源菜单中新建菜单,获取相应的ID。
1.加载菜单
hMyMenu=LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1));
2.设置,并显示本地菜单
case WM_CONTEXTMENU:
point.x=LOWORD(lParam);
point.y=HIWORD(lParam); TrackPopupMenu(GetSubMenu(hMyMenu,0),TPM_LEFTALIGN|TPM_VCENTERALIGN,point.x,point.y,0,hWnd,0);
WM_CONTEXTMENU:相应本地菜单消息。
lParam 携带光标的坐标。
GetSubMenu(hMyMenu,0),获取本地菜单hMyMenu的下一栏。
如图,GetSubMenu将会显示2 3 4 5,不将显示1。
也可以通过GetMenu()来获取系统菜单,再将系统菜单设为本地菜单。
热键,或称快捷键。
如何利用WIN32已有的资源进行热键操作?
步骤:
1.在资源视图中找到Accelerator,出现如下图:
2.设置想要的按键,作为相应按钮。可以以下两个地方设置:
第一:
第二:
解析:ID,需要产生相应的控件ID,可以是系统按钮、自拟控件的ID。修饰符,有Ctrl、Alt、Shift,当我们按下某字母键时,是否需要这三个键来组合,才会响应。(True,需要。False,不需要)Key,按下哪个键去响应控件。Type,推荐使用VIRTKEY。
3.保存,运行程序,就会修改成功。
光标
有时需要修改鼠标的光标,或是在不用的区域显示不同的光标。
步骤:
1.在资源视图->Icon,添加和设定自己光标。
2.加载光标,有两个方法:
1.wcex.hIcon= LoadIcon(hInstance, IDI_ICON1);
利用WNDCLASSEX wcexd的结构体属性,进行直接加载。
2.通过消息响应WM_SETCURSOR加载,调用函数SetCursor()。
hCursor1=LoadCursor(hInst,MAKEINTRESOURCE(IDC_CURSOR1));
hCursor2=LoadCursor(hInst,MAKEINTRESOURCE(IDC_CURSOR2));
case WM_SETCURSOR:
if(LOWORD(lParam)==HTCLIENT)
SetCursor(hCursor1);
else if(LOWORD(lParam)==HTCAPTION)
SetCursor(hCursor2);
break;
lParam:携带了当前光标的坐标。
HTCLIENT:代表窗口的客户区。
HTCAPTION:代表标题栏
区别:第一种方法加载简便,一次性加载,不需要每次响应。第二方法可以多样化,如上所示,可以在客户区使用一种光标,在标题栏使用另外一种光标。
另外,也可以加载动态光标,或其他文件中、桌面的光标。利用函数LoadCursorFromFile()
,参数为光标所在的路径。
图标
修改程序中的大图标(桌面任务栏)和小图标(程序的标题栏最左边)
方式1:通过WNDCLASSEX wcex结构体进行修改
wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SMALL));
wcex.hIconSm = LoadIcon(wcex.hInstance,MAKEINTRESOURCE(IDI_ICON1));
第一个wcex.hIcon为大图标。
第二个wcex.hIconSm 为小图标。
MAKEINTRESOURCE():为预定义,将ID转换成对应的字符串。
方法2:
通过函数进行修改。
hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));
PostMessage(hWnd,WM_SETICON,ICON_BIG,(LPARAM)hIcon);
利用PostMessage()发送设置光标的消息.
第三个参数必须为ICON_BIG,或是ICON_SMALL.
部分源码: LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; HMENU hMenu=GetMenu(hWnd); static HMENU hMyMenu; static HCURSOR hCursor1,hCursor2; static UINT uFlat=0; static POINT point; static HICON hIcon; switch (message) { case WM_CREATE: hCursor1=LoadCursor(hInst,MAKEINTRESOURCE(IDC_CURSOR1)); hCursor2=LoadCursor(hInst,MAKEINTRESOURCE(IDC_CURSOR2)); hMyMenu=LoadMenu(hInst,MAKEINTRESOURCE(IDR_MENU1)); hIcon=LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1)); break; //设置光标。分任务栏和客户区 case WM_SETCURSOR: //判断当前光标位置 if(LOWORD(lParam)==HTCLIENT) SetCursor(hCursor1); else if(LOWORD(lParam)==HTCAPTION) SetCursor(hCursor2); break; case WM_CONTEXTMENU: //获取当前光标位置 point.x=LOWORD(lParam); point.y=HIWORD(lParam); TrackPopupMenu(GetSubMenu(hMyMenu,0),TPM_LEFTALIGN|TPM_VCENTERALIGN,point.x,point.y,0,hWnd,0); case WM_INITMENUPOPUP: if(uFlat==IDM_POINT) CheckMenuItem(hMenu,IDM_POINT,MF_BYCOMMAND|MF_CHECKED); else CheckMenuItem(hMenu,IDM_POINT,MF_BYCOMMAND|MF_UNCHECKED); if(uFlat==IDM_RECT) CheckMenuItem(hMenu,IDM_RECT,MF_BYCOMMAND|MF_CHECKED); else CheckMenuItem(hMenu,IDM_RECT,MF_BYCOMMAND|MF_UNCHECKED); if(uFlat==IDM_TRAG) CheckMenuItem(hMenu,IDM_TRAG,MF_BYCOMMAND|MF_CHECKED); else CheckMenuItem(hMenu,IDM_TRAG,MF_BYCOMMAND|MF_UNCHECKED); if(uFlat==IDM_CIRCLE) CheckMenuItem(hMenu,IDM_CIRCLE,MF_BYCOMMAND|MF_CHECKED); else CheckMenuItem(hMenu,IDM_CIRCLE,MF_BYCOMMAND|MF_UNCHECKED); break; case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); uFlat=wmId; // 分析菜单选择: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About); break; case IDM_POINT: //MessageBox(hWnd,"dsd","ds",MB_OK); EnableMenuItem(hMenu,1,MF_GRAYED|MF_BYPOSITION); EnableMenuItem(hMenu,2,MF_GRAYED|MF_BYPOSITION); uFlat=IDM_POINT; DrawMenuBar(hWnd); break; case IDM_RECT: EnableMenuItem(hMenu,IDM_GREEN,MF_GRAYED|MF_BYCOMMAND); EnableMenuItem(hMenu,IDM_ABOUT,MF_GRAYED|MF_BYCOMMAND); uFlat=IDM_RECT; DrawMenuBar(hWnd); break; case IDM_TRAG: EnableMenuItem(hMenu,1,MF_GRAYED|MF_BYPOSITION); EnableMenuItem(hMenu,2,MF_ENABLED|MF_BYPOSITION); DrawMenuBar(hWnd); uFlat=IDM_TRAG; break; case IDM_CIRCLE: EnableMenuItem(hMenu,1,MF_ENABLED|MF_BYPOSITION); EnableMenuItem(hMenu,2,MF_ENABLED|MF_BYPOSITION); uFlat=IDM_CIRCLE; DrawMenuBar(hWnd); break; case IDM_ELLPSE: break; case IDM_SQUIRE: break; case IDM_RED: PostMessage(NULL,WM_SETICON,ICON_BIG,(LPARAM)hIcon); break; case WM_SETICON: MessageBox(NULL,"d","dd",MB_OK); break; case IDM_BLUE: break; case IDM_YELLOW: break; case IDM_GREEN: break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }