自绘菜单的实现 ----------原作者querw

在VCKBASE上读到《一种漂亮的自绘菜单》 [作者:郑恒 (lbird)]。应用到我的工程里后发现:文章中提到的效果能很好的实现。但是有一点不方便:需要映射 WM_DRAWITEM 和 WM_MEASUREITEM 消息才能实现自画功能。这对于一个基于对话框的工程或者仅仅需要弹出式菜单的工程来说很不方便。网上有一种很有名的自绘菜单 :BCMenu(http://www.rocscience.com/~corkum/BCMenu.html) (在附带工程中也有 BCMenu),在使用它的时候并不需要映射上述的两个消息就能实现自绘效果。这个问题让我觉得很困惑,MSDN也说明:MeasureItem() 和 DrawItem() 两个虚函数是由框架调用的 。并不用手工映射。可是若不映射上述的两个消息则显示不正常。(我查看了好多资料,直到现在还是不明白原因。呵呵:))既然 BCMenu 可以不用映射 WM_DRAWITEM 和 WM_MEASUREITEM 就能实现自画功能,那么它肯定经过了特殊处理。果然,BCMenu::LoadMenu()对整个菜单作了处理 。我注意到,如果菜单是弹出式的,那么不需要映射 WM_DRAWITEM 和 WM_MEASUREITEM 就能实现自画功能。于是我在CMenuEx::LoadMenu()中重新构建了整个菜单, 把所有的子菜单创建为弹出式的菜单使用API函数::CreatePopupMenu(),代码如下:

001. BOOL CMenuEx::LoadMenu(UINT uMenu)
002. {
003. //重新读入菜单,创建为popup菜单,才能自画(由框架调用MesureItem() 和 DrawItem()
004. HMENU hMenu = ::CreateMenu();
005. this->Attach(hMenu);
006.  
007. //临时菜单(使用CMenu的LoadMenu()函数读入菜单,并以之为蓝本构建新的菜单)
008. CMenu Menu;    
009. UINT uID;
010. Menu.LoadMenu(uMenu);
011. for(int i = 0; i < (int)Menu.GetMenuItemCount(); i++)
012. {
013. uID = Menu.GetMenuItemID(i);
014. if(uID == 0)            //分隔符
015. {
016. ::AppendMenu(hMenu,MF_SEPARATOR,0,NULL);
017. }
018. else if((int)uID == -1)     //弹出菜单(即子菜单)
019. {
020. CMenu *pSubMenu = Menu.GetSubMenu(i);
021.  
022. //创建子菜单
023. HMENU hSubMenu = ::CreatePopupMenu();
024. CString strPopup;
025. Menu.GetMenuString(i,strPopup,MF_BYPOSITION);
026. ::InsertMenu(hMenu,
027. i,
028. MF_BYPOSITION | MF_POPUP | MF_STRING,
029. (UINT)hSubMenu,
030. strPopup);                     
031.  
032. //对子菜单递归调用ChangeMenuStyle(),把子菜单改为MF_OWNERDRAW风格
033. ChangeMenuStyle(pSubMenu,hSubMenu);
034. }
035. else                    //正常的菜单项
036. {
037. CString strText;
038. Menu.GetMenuString(uID,strText,MF_BYCOMMAND);
039. AppendMenu(MF_STRING,uID,strText);
040. }
041. }
042. Menu.DestroyMenu();         //销毁临时菜单
043. return TRUE;
044. }
045.  
046. void CMenuEx::ChangeMenuStyle(CMenu *pMenu,HMENU hNewMenu)
047. {  
048. //关联为CMenuEx(关联为CMenuEx后才能自动重画
049. //原因不明(CMenu封装的结果?)
050.  
051. CMenuEx *pNewMenu;
052. pNewMenu = new CMenuEx;
053. pNewMenu->Attach(hNewMenu);
054. m_SubMenuArr.Add(pNewMenu);
055.  
056. UINT uID;
057. int nItemCount = pMenu->GetMenuItemCount();
058. for(int i = 0; i < nItemCount; i++)
059. {
060. uID = pMenu->GetMenuItemID(i);
061. if(uID == 0)            //分隔符
062. {
063. ::AppendMenu(hNewMenu,MF_SEPARATOR,0,NULL);
064. //pNewMenu->AppendMenu(MF_SEPARATOR,0,NULL);
065. CString strText;
066. MENUITEM *pMenuItem = new MENUITEM;
067. pMenuItem->uID = 0;
068. pMenuItem->uIndex = -1;
069. pMenuItem->uPositionImageLeft = -1;
070. pMenuItem->pImageList = &m_ImageList;
071. m_MenuItemArr.Add(pMenuItem);
072.  
073. ::ModifyMenu(hNewMenu,
074. i,
075. MF_BYPOSITION | MF_OWNERDRAW,
076. -1,
077. (LPCTSTR)pMenuItem);
078. }
079. else if(uID == -1)      //弹出菜单(即子菜单)
080. {
081. CMenu *pSubMenu = pMenu->GetSubMenu(i);
082. HMENU hPopMenu = ::CreatePopupMenu();
083. CString strPopup;
084. pMenu->GetMenuString(i,strPopup,MF_BYPOSITION);
085. ::InsertMenu(hNewMenu,
086. i,
087. MF_BYPOSITION | MF_POPUP,
088. (UINT)hPopMenu,
089. strPopup);
090.  
091. MENUITEM *pMenuItem = new MENUITEM;
092. pMenuItem->uID = -1;
093. pMenuItem->strText = strPopup;
094. pMenuItem->uIndex = -1;
095. pMenuItem->uPositionImageLeft = -1;
096. pMenuItem->pImageList = &m_ImageList;
097. m_MenuItemArr.Add(pMenuItem);
098. ::ModifyMenu(hNewMenu,
099. i,
100. MF_BYPOSITION | MF_OWNERDRAW,
101. -1,
102. (LPCTSTR)pMenuItem);
103.  
104. ChangeMenuStyle(pSubMenu,hPopMenu);
105.  
106. }
107. else                    //正常的菜单项
108. {
109. CString strText;
110. pMenu->GetMenuString(uID,strText,MF_BYCOMMAND);
111. MENUITEM *pMenuItem = new MENUITEM;
112. pMenuItem->uID = pMenu->GetMenuItemID(i);
113. pMenu->GetMenuString(pMenuItem->uID,
114. pMenuItem->strText,
115. MF_BYCOMMAND);
116. pMenuItem->uIndex = -1;
117. pMenuItem->uPositionImageLeft = -1;
118. pMenuItem->pImageList = &m_ImageList;
119. m_MenuItemArr.Add(pMenuItem);
120.  
121. UINT uState = pMenu->GetMenuState(i,MF_BYPOSITION);
122. ::AppendMenu(hNewMenu,
123. MF_OWNERDRAW | MF_BYCOMMAND | uState,
124. uID,
125. (LPCTSTR)pMenuItem);
126. }
127. }
128. }

这样,利用标注的CMenu::LoadMenu()函数读入菜单,并根据这个菜单重新构建一个新的菜单,在新菜单中把所有的子菜单创建为弹出式菜单并关联一个CMenuEx类。根据需要,我提供了一个

1. CMenuEx::LoadToolBar(UINT uToolBar, UINT uFace)

接口,请注意它的两个参数:uToolBar 是工具条的资源,uFace 是一个替代位图的资源ID。因为VC6.0中做一个真彩工具栏并不是一件容易的事,所以我做了一个小动作:用IDE的资源编辑器随便编辑一个工具条,只要ID和菜单ID相对应即可,然后可以用外部编辑器编辑好真正要使用的位图(顺序和工具条资源的顺序一样),并把该位图作为uFace参数传入,菜单就可以有真彩图标了。

CMenuEx还提供了如下三个接口:

1. BOOL ModifyMenuEx()
2. BOOL AppendMenuEx()
3. BOOL RemoveMenuEx()

功能一目了然,只是增加了对自绘风格的处理,应用的时候只要像调用普通的CMenu::AppendMenu()等函数一样就自动拥有自绘风格了。我写这篇文章的目的在于提出菜单派生类调用 MeasureItem() 和 DrawItem()的问题。至于实现漂亮的菜单界面主要工作当然还是在 DrawItem() 函数中做,有特殊需要的可以自行定义 MENUITEM 结构,重新写 DrawItem() 函数。我没有提供设置菜单附加位图的具体代码,相信这个不是问题。你可以很容易的通过重写 DrawItem()实现。有必要提醒的是:有关一个菜单项的信息最好能完全从一个MENUITEM结构中取得,使

1. virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
2. virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);

两个函数完全不依赖于CMenuEx类的数据成员。

要在工程中使用CMenuEx很简单:

1.enuEx.h和MenuEx.cpp加入到你的工程中;

2.一个CMenuEx对象.例如m_Menu;

3.m_Menu.LoadMenu(IDR_MENU1),读入菜单;

4.要使用菜单位图则调用m_Menu.LoodToolBar();

效果如下:

主菜单

弹出式菜单

最后,对《一种漂亮的自绘菜单》的作者郑恒给予我的帮助表示衷心感谢!

转载地址:http://www.vckbase.com/index.php/wv/931

在给Vim添加自定义的文件类型规则时,我们可以通过在~/.vim/ftdetect目录下创建一个文件来定义自己的filetype autocmd。可以使用以下命令创建该文件:[:w ~/.vim/ftdetect/log.vim]。这样,当Vim启动时,它会加载所有runtime路径下的ftdetect子目录中的.vim文件,其中包括系统级Vim运行时路径$VIMRUNTIME/usr/share/vim/vim90和用户级运行时路径~/.vim。所以,我们可以将自定义的filetype规则放在~/.vim/ftdetect目录下,以便Vim能够正确识别和处理该文件类型。为了创建~/.vim目录和~/.vim/ftdetect目录,可以使用以下命令:(a).创建自己的'runtimepath'。[:!mkdir ~/.vim]和[:!mkdir ~/.vim/ftdetect]。这样,我们就可以在~/.vim/ftdetect目录下创建自定义的文件类型规则了。 关于问题中的"vim sizeof",我无法根据提供的引用内容找到与之相关的信息。如果您能提供更多上下文或明确您的问题,我将非常乐意为您提供帮助。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [VIM 适用于 LOG 文件的语法高亮配置](https://blog.csdn.net/querw/article/details/127537571)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [交叉编译一个能在mips下运行的vim编译器](https://blog.csdn.net/alfiy/article/details/121721503)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值