10、菜单和其他资源

1、资源

编译程序时,所有资源都会被保存到exe文件或者dll文件中,所以加载资源的API函数第一传参都是程序实例句柄hInstance。在进程启动时,资源并不会被加载到内存中,只有在需要使用时才调用函数,显式把资源加载到内存中。

每个资源都拥有一个标识符,标识符可以是数字,也可以是字符串。加载资源的函数需要的标识符传参都是字符串类型,可以使用MAKEINTRESOURCE宏把数字标识符转换为字符串类型。

2、图标

图标最开始是在注册窗口类时使用,如果窗口带有标题栏,那么注册窗口类时指定的图标会被显示在窗口左上角。此外,也可以在程序运行过程中,使用SetClassLong来动态改变窗口图标。或者使用DrawIcon在其它位置绘制图标。windows预定义了一些图标,它们标识符带有IDI_前缀,当然我们也可以自定义图标。

在自定义图标时,同一个图标资源文件中可以包含多种尺寸的图标,但LoadIcon加载图标的尺寸由SM_CXICONSM_CYICON决定,它根据实际需要的尺寸从图标文件中选择最合适的尺寸图标,在需要情况下可能对图标进行缩放。如果需要加载其他尺寸的图标,可以使用LoadImage

3、鼠标指针

使用LoadCursor加载鼠标指针资源,可以在注册窗口类中指定窗口类的鼠标指针,也可以在程序运行过程中使用SetClassLong修改窗口类鼠标指针,或者使用SetCursor修改窗口当前窗口的鼠标指针。

当鼠标指针在一个窗口内移动,并且鼠标指针没有被其他窗口捕获时,windows会向该窗口发送WM_SETCURSOR消息。在DefWindowProc的处理中,它先把该消息发送给父窗口处理。如果返回TRUE,则表示父窗口设置了鼠标指针,当前窗口不用再处理;否则,当前窗口继续处理WM_SETCURSOR消息设置鼠标指针,并且在鼠标指针位于非客户区时设置成箭头,位于客户区时设置成注册窗口类指定的鼠标指针。

所以,需要动态修改鼠标指针时,应该在WM_SETCURSOR中设置。

4、字符串资源

使用LoadString来加载字符串资源

5、自定义资源

windows提供了自定义资源,其数据格式由用户定义。使用LoadResourceFindResource获取资源句柄,使用LockResource把资源加载到内存,返回一个内存块句柄(内存指针),使用完后需要释放资源FreeResource

6、菜单
  • 菜单项
    菜单中每一栏被称作一个菜单项,windows定义了一些带MF_前缀的标志位来描述菜单项的属性。

    #define MF_INSERT           0x00000000L
    #define MF_CHANGE           0x00000080L
    #define MF_APPEND           0x00000100L
    #define MF_DELETE           0x00000200L
    #define MF_REMOVE           0x00001000L
    
    #define MF_BYCOMMAND        0x00000000L
    #define MF_BYPOSITION       0x00000400L
    
    #define MF_SEPARATOR        0x00000800L
    
    #define MF_ENABLED          0x00000000L
    #define MF_GRAYED           0x00000001L
    #define MF_DISABLED         0x00000002L
    
    #define MF_UNCHECKED        0x00000000L
    #define MF_CHECKED          0x00000008L
    #define MF_USECHECKBITMAPS  0x00000200L
    
    #define MF_STRING           0x00000000L
    #define MF_BITMAP           0x00000004L
    #define MF_OWNERDRAW        0x00000100L
    
    #define MF_POPUP            0x00000010L
    #define MF_MENUBARBREAK     0x00000020L
    #define MF_MENUBREAK        0x00000040L
    
    #define MF_UNHILITE         0x00000000L
    #define MF_HILITE           0x00000080L
    
    #if(WINVER >= 0x0400)
    #define MF_DEFAULT          0x00001000L
    #endif /* WINVER >= 0x0400 */
    #define MF_SYSMENU          0x00002000L
    #define MF_HELP             0x00004000L
    #if(WINVER >= 0x0400)
    #define MF_RIGHTJUSTIFY     0x00004000L
    #endif /* WINVER >= 0x0400 */
    
    #define MF_MOUSESELECT      0x00008000L
    #if(WINVER >= 0x0400)
    #define MF_END              0x00000080L  /* Obsolete -- only used by old RES files */
    #endif /* WINVER >= 0x0400 */
    

    根据这些属性可以大致对菜单项进行分类:

    • MF_POPUP & MF_ENABLED 可以打开子菜单,每个子菜单都有菜单句柄
    • MF_ENABLED 命令项,点击会发送WM_COMMAND消息,每个命令项都有ID号
    • MF_SEPARATOR 分割线
      EnableMenuItemCheckMenuItemSetMenuItemInfoA可以修改菜单项的标志位。
  • 设计菜单
    菜单项的设计一般在资源管理界面中进行,但也可以在代码中使用CreateMenuAppendMenu设计菜单,还可以使用DeleteMenuInsertMenuModifyMenuRemoveMenu来修改菜单。需要注意DeleteMenuRemoveMenu的区别。如果菜单项是个子菜单项,DeleteMenu会销毁子菜单,并释放其内存;RemoveMenu不会销毁子菜单,还可以继续使用该子菜单,但需要在RemoveMenu前获取它的句柄。

  • 使用菜单
    菜单设计完成后,可以在注册窗口类时指定窗口类的菜单,或者在创建窗口后使用LoadMenu把菜单资源加载到内存,再使用SetMenu设置窗口菜单,这两种方法都可以把菜单显示在窗口的菜单栏中。

    也可以使用TrackPopupMenu来在窗口的任意位置打开菜单,通常由鼠标右键激活。

    显示在窗口菜单栏的菜单,会在窗口销毁时随着窗口一起被销毁,而没被窗口引用的菜单,必须显式调用DestroyMenu销毁。

  • 菜单相关消息
    点击命令项时会发送WM_COMMAND消息:

    LOWORD(wParam)菜单ID
    HIWORD(wParam)0
    lParam0

    鼠标在菜单项间移动时发送WM_MENUSELECT消息。

    LOWORD(wParam)菜单项ID或下拉菜单索引
    HIWORD(wParam)选择标记
    lParam包含所选菜单项的菜单句柄

    打开下拉菜单时发送WM_INITMENUPOPUP消息。

    wParam下拉菜单句柄
    LOWORD(lParam)下拉菜单索引
    HIWORD(lParam)1:系统菜单;0:其他菜单
  • 系统菜单
    CreateWindow时使用WS_SYSMENU样式创建窗口,窗口标题栏的左边会有一个系统菜单。windows为系统菜单定义了很多菜单项ID,但默认情况下系统菜单只包含几个菜单项,我们可以使用GetSystemMenu获取系统菜单句柄,然后使用上面提到的函数来修改系统菜单。可以添加windows预定义的系统菜单项,或添加自定义的菜单项,也可以删除默认显示的系统菜单项。点击系统菜单的命令项不是发送WM_COMMAND消息,而是发送WM_SYSCOMMAND消息:

    LOWORD(wParam) & 0xFFF0菜单ID
    HIWORD(wParam)0
    GET_X_LPARAM(lParam)低位字表示屏幕x坐标
    GET_Y_LPARAM(lParam)高位字表示屏幕y坐标

    wParam参数的最低4位由系统内部使用,所以测试wParam的值时应该先和0xFFF0进行与操作。
    lParam参数带有屏幕坐标信息,是有符号数。取值为有符号数的坐标数据时应该使用GET_X_LPARAMGET_Y_LPARAM,而不是LOWORDHIWORD

  • 菜单相关函数
    DrawMenuBar:强制重绘菜单栏
    GetSubMenu:获取子菜单句柄
    GetMenuItemCount:获取菜单项数目
    GetMenuItemID:获取菜单项菜单ID
    GetMenuString:获取菜单项文本
    GetMenuState:获取菜单项标志

7、键盘加速键

键盘加速键是键盘按键组合,被定义为键盘加速键的键盘组合按键会被翻译为WM_COMMANDWM_SYSCOMMAND消息。
一个键盘加速键由4个属性描述:类型、ID、修饰符和键。键盘加速键有两种类型:

  • 虚拟键类型,修饰符可以是CtrlShiftAlt
  • ASCII字符类型,修饰符只有Alt的组合键,但可以通过在ASCII字符前加^字符指定和Ctrl组合。

可以在资源管理界面中添加加速键表、定义加速建。

使用加速键时,需要使用LoadAccelerators先把加速键表加载到内存,然后在消息循环代码段中增加TranslateAccelerator来翻译加速键。TranslateAccelerator先判断msg是否是键盘消息。如果是,则在hAccel指定的加速键表中匹配加速键,如果匹配成功,则发送WM_COMMANDWM_SYSCOMMAND消息到hwnd指定的窗口过程。TranslateAccelerator发送WM_COMMANDWM_SYSCOMMAND前,会先把msg中的hwnd替换为TranslateAccelerator的第一传参,所以所有的键盘加速键消息都会被发送到统一个窗口。如果TranslateAccelerator把消息翻译了,返回非0值,不需要再把消息传给TranslateMessageDispatchMessage;否则返回0值。

while (GetMessage(&msg, NULL, 0, 0))
{
	if (!TranslateAccelerator(hwnd, hAccel, &msg))
	{
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}
}

当加速键ID和系统菜单项ID一致时,TranslateAccelerator向窗口过程发送WM_SYSCOMMAND消息,否则发送WM_COMMAND消息。

当加速键ID和菜单项ID一致时,窗口过程还会收到WM_INITMENUWM_INITMENUPOPUPWM_MENUSELECT消息,就像菜单被选择了一样。

当加速键对应一个MF_GRAYED或者MF_DISABLED菜单项时,TranslateAccelerator不会发送WM_COMMANDWM_SYSCOMMAND

LOWORD(wParam)加速键ID
HIWORD(wParam)1
lParam0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值