全功能的自绘菜单BCmenu类

来源:互联网 发布:中国软件服务市场 编辑:程序博客网 时间:2024/05/22 06:28

翻译来源:https://www.codeproject.com/Articles/22/Cool-Owner-Drawn-Menus-with-Bitmaps-Version

这个类很常见,在很多源码中都有见到。

包含BCMenu.cpp和BCMenu.h

该类实现了一个所有者绘制的菜单类,模仿XP,Office和Visual C ++中使用的菜单样式
  • 下载MFC MDI示例 - 113 KB
  • 下载MFC对话框示例 - 68 KB

3.01版的新功能

您可以看到我已经添加了新的Office XP绘图样式的菜单。我刚刚收到一台带有Windows XP的机器,我注意到我们所有应用程序中的菜单看起来都很糟糕。所以我决定做一些事情,经过2年的不看课程,添加了新的菜单绘图风格,并添加了很多修复和用户请求。现在新的绘画风格不像微软那样,但是我觉得这样做对我来说看起来不错。对于使用旧类的人来说,使用BCMenu新的.cpp和.h文件是很简单的事情

该课程目前使用XP上的新样式和Win9x / NT和2000上的旧样式。但是,如果您喜欢新的样式,并且希望在所有Windows平台上使用它,只需更改BCMenu顶部的以下 .cpp文件来自:

UINT BCMenu::original_drawmode=BCMENU_DRAWMODE_ORIGINAL;

UINT BCMenu::original_drawmode=BCMENU_DRAWMODE_XP;

同样,如果你认为我做了一个糟糕的工作,你可以在所有平台上将绘图风格改成原来的样式。

其他添加包括支持大于16种颜色的图像。该示例包含256和1600万色的图像。还有一个如何绘制禁用选项的选项。在XP模式下,它们未被选中,但可以更改。我也修复了多个菜单项的问题与相同的命令ID没有获得图像(只有第一个!)。有关更新的更多信息,请参阅本文的底部。

介绍

该类BCMenu实现从CMenu派生的所有者绘制的菜单其目的是模仿Visual C ++ 5.0和MS Word中使用的菜单样式。我无法承担所有的代码,其中一部分取自本·阿什利和Girish Bharadwaj提供的代码。他们的代码和这个代码之间的区别是非常简单的,这使得使用位图在应用程序中构建这些酷菜单变得非常简单。我已经删除了图标加载的东西,并用位图替换它。位图允许您使用资源编辑器中的工具栏直接使用16X15工具条位图。同样,没有缩放位图,所以它们总是看起来不错。您还可以加载位图资源并为您的复选标记定义位图。我还添加了默认的勾号图纸,LoadMenu分隔符,键盘加速器文本的正确对齐,键盘快捷键,弹出菜单项的正确对齐,显示外观更改时适当的系统颜色更改,以及Ben Ashley 对复杂子菜单系统的功能的错误修复我做了很多其他修改,太多列表或记住了。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的DrawState功能要好得多如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。键盘快捷键,弹出菜单项的正确对齐,显示外观更改时适当的系统颜色更改,以及Ben Ashley 对复杂子菜单系统的功能的错误修复我做了很多其他修改,太多列表或记住了。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的功能要好多了如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。键盘快捷键,弹出菜单项的正确对齐,显示外观更改时适当的系统颜色更改,以及Ben Ashley 对复杂子菜单系统的功能的错误修复我做了很多其他修改,太多列表或记住了。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的功能要好得多如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。显示外观发生变化时,正确的系统颜色变化,以及Ben Ashley 对复杂子菜单系统的功能的修复我做了很多其他修改,太多列表或记住了。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的功能要好得多如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。显示外观发生变化时,正确的系统颜色变化,以及Ben Ashley 对复杂子菜单系统的功能的修复我做了很多其他修改,太多列表或记住了。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的功能要好得多如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的功能要好得多如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。我还使用Jean-Edouard Lachand-Robert的禁用位图抖动功能创建禁用的状态位图。我必须承认,这样做的功能要好得多如果您发现任何错误,内存泄漏或更好的做事方式,请让我知道。我使用Visual C ++ 5.0,我没有测试与早期VC版本的兼容性。我已经在Win 95 / NT上以各种分辨率和调色板大小进行了测试。

安装(MDI应用程序)

那么,无聊的东西,让我们谈谈实现。为了方便起见,我将首先列出将MDI菜单实现到MDI应用程序中的方法:

  1. 使用应用向导创建您的MDI应用程序。
  2. BCMenu .cpp和BCMenu .h文件插入到您的工作区。
  3. CMainFrame在MainFrm.h头文件中将以下公共成员函数添加到您的类中:
    HMENU NewMenu();HMENU NewDefaultMenu();
  4. CMainFrame在MainFrm.h头文件中将以下公共成员变量添加到您的类中:
    BCMenu m_menu,m_default;
  5. 添加行:
    #include <span class="code-string">"BCMenu.h"</span>

    到MainFrm.h头文件的顶部。

  6. 打开Mainfrm.cpp实现文件,并添加NewMenuNewDefaultMenu成员函数如下所列。重要信息:确保IDR_MYMENUTYPE将以下LoadMenu调用中的菜单ID替换为与应用程序中的菜单相关联的菜单ID。查看资源视图的菜单文件夹。
    HMENU CMainFrame::NewMenu(){  static UINT toolbars[]={      IDR_MAINFRAME  };  // Load the menu from the resources  // ****replace IDR_MENUTYPE with your menu ID****  m_menu.LoadMenu(IDR_MYMENUTYPE);    // One method for adding bitmaps to menu options is   // through the LoadToolbars member function.This method   // allows you to add all the bitmaps in a toolbar object   // to menu options (if they exist). The first function   // parameter is an array of toolbar id's. The second is   // the number of toolbar id's. There is also a function   // called LoadToolbar that just takes an id.  m_menu.LoadToolbars(toolbars,1);  return(m_menu.Detach());}HMENU CMainFrame::NewDefaultMenu(){  m_default.LoadMenu(IDR_MAINFRAME);  m_default.LoadToolbar(IDR_MAINFRAME);  return(m_default.Detach());}
  7. 编辑InitInstance您的CWinApp派生类成员函数,并在以下位置添加以下突出显示的代码:
    // create main MDI Frame windowCMainFrame* pMainFrame = new CMainFrame;if (!pMainFrame->LoadFrame(IDR_MAINFRAME))   return FALSE;m_pMainWnd = pMainFrame;// This code replaces the MFC created menus with // the Ownerdrawn versions pDocTemplate->m_hMenuShared=pMainFrame->NewMenu();pMainFrame->m_hMenuDefault=pMainFrame->NewDefaultMenu();// This simulates a window being opened if you don't have// a default window displayed at startuppMainFrame->OnUpdateFrameMenu(pMainFrame->m_hMenuDefault);// Parse command line for standard shell commands, // DDE, file openCCommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);
  8. 添加消息的处理程序WM_MEASUREITEMWM_MENUCHAR以及WM_INITMENUPOPUP邮件到您的CMainFrame类。通过右键单击CMainFrameClassView中类并选择添加Windows消息处理程序来执行此操作过滤器中选择用于类组合框的消息窗口选项选择消息并添加处理程序。然后编辑处理程序并添加以下代码。
    //This handler ensure that the popup menu items are // drawn correctlyvoid CMainFrame::OnMeasureItem(int nIDCtl,  LPMEASUREITEMSTRUCT lpMeasureItemStruct) {  BOOL setflag=FALSE;  if(lpMeasureItemStruct->CtlType==ODT_MENU){    if(IsMenu((HMENU)lpMeasureItemStruct->itemID)){      CMenu* cmenu =        CMenu::FromHandle((HMENU)lpMeasureItemStruct->itemID);      if(m_menu.IsMenu(cmenu)||m_default.IsMenu(cmenu)){        m_menu.MeasureItem(lpMeasureItemStruct);        setflag=TRUE;      }    }  }  if(!setflag)CMDIFrameWnd::OnMeasureItem(nIDCtl,                                           lpMeasureItemStruct);}//This handler ensures that keyboard shortcuts workLRESULT CMainFrame::OnMenuChar(UINT nChar, UINT nFlags,  CMenu* pMenu) {  LRESULT lresult;  if(m_menu.IsMenu(pMenu)||m_default.IsMenu(pMenu))    lresult=BCMenu::FindKeyboardShortcut(nChar, nFlags, pMenu);  else    lresult=CMDIFrameWnd::OnMenuChar(nChar, nFlags, pMenu);  return(lresult);}//This handler updates the menus from time to timevoid CMainFrame::OnInitMenuPopup(CMenu* pPopupMenu,  UINT nIndex, BOOL bSysMenu) {  CMDIFrameWnd::OnInitMenuPopup(pPopupMenu, nIndex, bSysMenu);  if(!bSysMenu){    if(m_menu.IsMenu(pPopupMenu)||m_default.IsMenu(pPopupMenu))      BCMenu::UpdateMenu(pPopupMenu);  }}
  9. 如果您正在调试或正在将标准菜单与BCMenu混合(也许您使用标准菜单使用不同的文档模板),则应在项目设置中打开RTTI。

那就是这样。编译程序并查看文件菜单。你应该看到位图。我已经尝试了菜单与上下文菜单,他们似乎工作正常。

安装(SDI应用)

  1. 使用应用向导创建您的SDI应用程序。
  2. BCMenu .cpp和BCMenu .h文件插入到您的工作区。
  3. CMainFrame在MainFrm.h头文件中将以下public成员函数添加到您的类中:
    HMENU NewMenu();</tt />
    </ tt />
  4. CMainFrame在MainFrm.h头文件中将以下公共成员变量添加到您的类中:
    BCMenu m_menu;</tt />
    </ tt />
  5. 添加行:
    #include <span class="code-string">"BCMenu.h"</tt /></span>
    </ tt />

    到MainFrm.h头文件的顶部。

  6. 打开Mainfrm.cpp实现文件,并添加NewMenuNewDefaultMenu成员函数如下所列。重要信息:确保IDR_MAINFRAME将以下LoadMenu调用中的菜单ID替换为与应用程序中的菜单相关联的菜单ID。查看资源视图的菜单文件夹。
    HMENU CMainFrame::NewMenu(){  // Load the menu from the resources // ****replace IDR_MAINFRAME with your menu ID****  m_menu.LoadMenu(IDR_MAINFRAME);   // One method for adding bitmaps to menu options is  // through the LoadToolbar member function.This method  // allows you to add all the bitmaps in a toolbar object  // to menu options (if they exist). The function parameter  // is an the toolbar id. There is also a function called  // LoadToolbars that takes an array of id's.  m_menu.LoadToolbar(IDR_MAINFRAME);  return(m_menu.Detach());}
  7. 编辑InitInstance您的CWinApp派生类成员函数,并在以下位置添加以下突出显示的代码:
      // Dispatch commands specified on the command line  if (!ProcessShellCommand(cmdInfo))     return FALSE;  CMenu* pMenu = m_pMainWnd->GetMenu();  if (pMenu)pMenu->DestroyMenu();  HMENU hMenu = ((CMainFrame*) m_pMainWnd)->NewMenu();  pMenu = CMenu::FromHandle( hMenu );  m_pMainWnd->SetMenu(pMenu);  ((CMainFrame*)m_pMainWnd)->m_hMenuDefault = hMenu;</tt />
    </ tt />
  8. 添加消息的处理程序WM_MEASUREITEMWM_MENUCHAR以及WM_INITMENUPOPUP邮件到您的CMainFrame类。通过右键单击CMainFrameClassView中类并选择添加Windows消息处理程序来执行此操作过滤器中选择用于类组合框的消息窗口选项选择消息并添加处理程序。然后编辑处理程序并从上面添加MDI代码。将引用替换CMDIFrameWndCFrameWnd
  9. 如果您正在调试或正在混合标准菜单BCMenu's(也许您使用标准菜单有不同的文档模板),那么您应该在项目设置中打开RTTI。