《Windows程序设计》读书笔记之十

菜单及其他资源
                                                                                    见钱眼开 于 2005-5-21
       图标、光标、菜单和对话框等都是Windows的资源类型。资源就是数据,它们被存储在程序的.EXE文件中,但并非驻留在程序的数据区域。因此资源无法通过程序源代码中定义的变量直接访问,必须通过Windows提供的API函数(如LoadCursor和LoadIcon等)直接或间接加载到内存使用。
       将一个图标文件最终包含到.EXE文件中,经过两个步骤:1。创建一个相应的资源描述文件(.RC),通过资源编译器(比如RC.EXE)编译成资源文件(.RES);2。资源文件(.RES)在链接过程中和.OBJ、.LIB等文件一起包含到.EXE文件。通常我们只需将图标文件和资源描述文件(.RC)添加到项目工程中即可,开发环境将自动完成后续工作。
       资源描述文件是文本文件,包含对引用资源的文本形式描述。在该文件中,每一个资源都唯一对应一个ID。
       下面是IconDemo.RC文件中图标资源的引用描述:
       #include “Resource.h”
       IDI_ICON   ICON    DISCARDABLE     “IconDemo.ico”
       IDI_ICON是图标标志ID;ICON表示资源类型为图标;DISCARDABLE是一个关键字,表示必要时Windows可以从内存中丢弃图标,以获得额外空间。之后无需程序特定操作,Windows能够重新加载该图标。
       程序可通过以下方式获取图标句柄:
       hIcon = LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON));
       第一个参数指出资源所在模块的实例句柄。如果为NULL,调用Windows预定义的图标。
       MAKEINTRESOURCE是个宏,具体定义如下:
       #define MAKEINTRESOURCE(i) (LPTSTR)((DWORD)((WORD)(i)))
       它的作用是把一个数字转换为一个高16位为0的字符串指针。LoadIcon函数通过判断高16位是否为0,知道该参数赋予的是标识ID还是字符串。因此,图标资源标识符必须是16位数值。
       如果Resource.h文件中并未定义IDI_ICON,那么还可以把它作为字符串来调用:
       hIcon = LoadIcon(hInstance, TEXT(“IDI_ICON”));
 
       动态设置窗口图标:
       SetClassLong(hWnd,GCL_HICON,LoadIcon(hInstance,MAKEINTRESOURCE(IDI_ICON)));
       返回窗口图标:
       hIcon = (HICON)GetClassLong(hWnd,GCL_HICON);
       LoadIcon返回句柄后不需要负责销毁。比起LoadIcon,Windows文档更推荐使用LoadImage。
 
       光标和图标的使用方法很相似。自定义光标一般为单色,大小为32*32象素。
       动态设置窗口光标:
       SetClassLong(hWnd,GCL_HCURSOR,LoadCursor(hInstance,”IDC_CURSOR”));
       SetCursor(hCursor);
       SetCursor必须在每次接收WM_MOUSEMOVE消息被调用,否则Windows将替换为窗口类预定义的光标。
       使用字符串资源是为了更好的支持多语言。
       在资源描述中,字符串显示在一个多行的语句中,如:
       STRINGTABLE DISCARDABLE
       BEGIN
              IDS_STRING1,”character string 1”
              IDS_STRING2,”character string 2”
       END
       每个字符串占一行,最多4097格字符。以/t作为制表符,/n用于行尾。
       将字符串载入到数据缓冲区中:
       LoadString(hInstance,IDS_STRING1,szBuffer,iMaxLen);
 
       我们还可以将自定义的资源链接到目标.EXE中。例如一个BinData.bin文件,可以在资源描述文件中这样定义:
       IDR_BINTYPE BINTYPE BinData.bin
       “BINTYPE”是自定义的资源类型。IDR_BINTYPE是资源标识符。
       成功编译后,我们首先调用FindResource函数返回程序模块中该类型资源的方位:
       HRSRC hrBin = FindResource(hInstance,
                             TEXT(“BINTYPE”),
                             MAKEINTRESOURCE(IDR_BINTYPE));
       再调用LoadResource函数载入资源( 注意:该函数返回值为 HGLOBAL 类型是出于兼容性考虑,该值并非是一个全局内存句柄,不要将它传给 GlobalLock GlobalFree 函数):
       HGLOBAL hgBin = LoadResource(hInstance,
                                 hrBin);
       最后调用LockResource函数锁定该资源返回数据指针:
       pBinData = LocakResource(hgBin);     
       调用FreeResouce函数释放该资源,不过不调用也没有关系,程序终止时会自动释放。
 
 
    菜单是一系列可用的选项,每个可选的菜单项被赋予唯一的ID。用户选择一个菜单项时,Windows会给程序发送包含该ID的WM_COMMAND消息。
    在窗口上紧接在标题栏下的菜单条,被称为“主菜单”或“顶层菜单”。经过顶层菜单项弹出的菜单是“下拉菜单”或“子菜单”。
    子菜单的各项可以被选中;顶层菜单的各项不可被选中。
    顶层菜单和子菜单可以被“启用”/“禁用”、“灰化”。
    顶层菜单和子菜单都拥有各自的菜单句柄。
    一个菜单项具有三个基本特性:标题/图标、ID、属性。
    菜单项标题中键入“&“字符,随后的字符在显示菜单时加下划线。按下”Alt”键加该字符可选中该菜单项。
 
    除了在定义窗口类和调用CreateWindow函数时可以指定菜单,还可以动态修改菜单:
    hMenu = LoadMenu(hInstance,MAKEINTRESOURCE(ID_MENU));
    SetMenu(hWnd,hMenu);
    销毁窗口时,所有未与窗口关联的菜单应该调用DestroyMenu显示清除。
   
    WM_INITMENU 消息在菜单即将被激活而且首次被激活时触发。wParam参数包含被激活菜单句柄。
    WM_MENUSELECT 消息在一个菜单项被选中时触发。如果该菜单项是一个命令项,wParam参数低16位包含该菜单项ID,lParam参数包含属主菜单句柄;如果是弹出项,则包含弹出或子菜单在主菜单中的索引,而lParam参数包含主菜单句柄(调用GetSubMenu返回弹出或子菜单句柄)。wParam参数高16位包含该菜单项标志,由以下标志构成:
MF_BITMAP           显示位图
MF_CHECKED          被选中
MF_DISABLED         禁用
MF_GRAYED           灰化
MF_HILITE           高亮
MF_MOUSESELECT      鼠标选中
MF_OWNERDRAW        自绘菜单项
MF_POPUP            打开弹出或子菜单
MF_SYSMENU          系统菜单项
    WM_INITMENUPOPUP 消息在弹出或子菜单即将被激活时触发。wParam参数包含被激活菜单句柄。lParam参数低16位包含被激活菜单索引,高16位在系统菜单时为1,否则为0。
    WM_COMMAND消息在选中一个菜单项时触发,该消息也可以由子窗口控件产生。不过有一点不同,菜单项产生的消息 lParam值为0,而子窗口控件为其句柄。
    WM_SYSCOMMAND消息在选中一个系统菜单的菜单项时触发。该消息 wParam 参数低4位系统内部使用,要想获得正确ID,应先和0xfff0进行与运算。系统菜单中自定义菜单项ID为避免和预定义值冲突,务必小于0xf000。
    最后一个与菜单相关的消息是WM_MENUCHAR。当一个下拉菜单被激活时,按下一个与菜单项热键不匹配的键,则该消息被发送给菜单属主窗口。
    菜单可通过定义资源描述文件实现;也可以通过调用API函数实现。
    HMENU hMainMenu = CreateMenu();     // 创建一个主菜单
    HMENU hPopupMenu = CreateMenu();        // 创建一个弹出菜单
    AppendMenu(hPopupMenu,MF_STRING,ID_MENUITEM,”&New”); // 在弹出菜单插入一个                  标题为“New”的命令菜单项
    AppendMenu(hMainMenu,MF_POPUP,hPopupMenu,”&File”);    //在主菜单插入一个标题为“ File”的弹出菜单项
    TrackPopupMenu(hPopupMenu,TPM_RIGHTBUTTON,x,y,0,hWnd,NULL); //在鼠标右键按下的屏幕坐标方位弹出一个菜单
   
    使用WS_SYSMENU风格创建的主窗口在其标题栏左侧有一个系统菜单。
    HMENU hMenu = GetSystemMenu(hWnd,FALSE);    // 返回主窗口系统菜单
    AppendMenu(hMenu,MF_SEPARATOR,0,NULL);      // 插入一个分隔符
    AppendMenu(hMenu,MF_STRING,IDM_SYS_ABOUT,”About”);    // 插入一个菜单项
   
    另外,其他编辑菜单的API函数还有:
    DeleteMenu      删除菜单中一个菜单项
    InsertMenu      在菜单中某个位置插入一个新项
    ModifyMenu      修改现有菜单项
    RemoveMenu      从菜单中删除某一项
    DeleteMenu 和RemoveMenu的区别是,当菜单项是一个弹出项时,DeleteMenu删除该菜单项和对应弹出菜单;而RemoveMenu仅仅删除该菜单项,不处理弹出菜单。
    DrawMenu(hWnd); // 重新绘制主窗口顶层菜单
    hPopupMenu = GetSubMenu(hMainMenu,iIndex); // 返回一个弹出菜单
    iCount = GetMenuItemCount(hMenu);   // 返回菜单项数量
    …
   
    快捷键 (Accelerator Key)是产生WM_COMMAND或WM_SYSCOMMAND消息的键组合。
    快捷键通常被用于加快菜单项操作。不过一个快捷键并非必须对应一个菜单命令。
    通常Windows将键盘消息发送给目前活动窗口的窗口过程,而按下快捷键后的键盘消息经 TranslateAccelerator函数转换后可以直接发送给指定窗口过程。这样的话,即使当前输入焦点在子窗口,主窗口菜单仍旧可以及时响应。
    任何虚拟键或者字符键连同 Shift键、Ctrl键或Alt键都可以定义快捷键。不过应该避免包含Tab、Enter、Esc和Spacebar键,防止和系统快捷键冲突。
 
    以下是资源描述文件中包含的快捷键定义描述:
IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE
BEGIN
   "N",            IDA_NEW,                VIRTKEY, ALT, NOINVERT
   "O",            IDA_OPEN,               ASCII, ALT, NOINVERT
   VK_ESCAPE,     IDA_EXIT,               VIRTKEY, CONTROL, NOINVERT
END
 
    和其他资源的载入方法很相似,使用 LoadAccelerators载入“快捷键”表:
HANDLE hAccel = LoadAccelerators(hInstance,TEXT ("MyAccelerators"));
    使用TranslateAccelerator实现 键盘消息转换。如果键盘消息被成功转换为 WM_COMMAND或WM_SYSCOMMAND消息,那么TranslateAccelerator返回真,TranslateMessage无需再处理该键盘消息。
while(GetMessage(&msg,NULL,0,0))
{
   if(!TranslateAccelerator(hwnd,hAccel,&msg))
   {
       TranslateMessage(&msg);
       DispatchMessage(&msg);
    }
}
    如果快捷键与一个菜单项对应,那么窗口过程还会收到 WM_INITMENU、WM_INITMENUPOPUP和WM_MENUSELECT消息,就好像选中了菜单选项一样。
   如果快捷键与一个禁用或者无效化的菜单项相对应,那么, TranslateAccelerator函数就不会向窗口过程发送WM_COMMAND或WM_SYSCOMMAND消息。
    如果活动窗口已经被最小化,那么 TranslateAccelerator将向窗口过程发送WM_SYSCOMMAND消息,而不是WM_COMMAND消息。TranslateAccelerator也会为没有对应任何菜单项的快捷键,向窗口过程发送WM_COMMAND消息。
 
 
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值