MFC 菜单自绘

2023-11-11 11:18
文章标签 mfc 菜单 自绘

本文主要是介绍MFC 菜单自绘,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、要想自绘菜单,首要的就是子类化菜单类,拥有自己的自定义菜单类。

也有大神子类化CWnd。。。这应该属于高度定制了,表示驾驭不了,还是看子类化的吧。 关于自绘菜单类很多大神有分享,由于自己水平有限,也只能是拿来主义。

1.总结起来,这个类通常必需要重写的方法有

1.1、BOOL CMyMenu::OnDrawItem(int nIDCtl,DRAWITEMSTRUCT*pDIS)

该方法用于自绘制每一菜单项,在菜单显示,刷新时调用。通常做法是根据菜单项属性,判断属于哪一类菜单,再决定如何绘制,一般分为顶层菜单项,一般菜单项、分隔符、系统菜单等。

1.2、BOOL CMyMenu:OnMeasureItem(int nIDCtl,MEASUREITEMSTRUCT*pMIS)

该方法用于设置菜单项的尺寸,在菜单创建时调用。如可以简单地设置,菜单项宽高为

        pMIS->itemHeight    =20;pMIS->itemWidth     =200;
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

2.重写了最重要的两个类,就有了绘制菜单的基础工具,但是还需要我们添加具体的绘制方法 ,如绘制顶层菜单的方法,绘制一般菜单、绘制分割符、绘制系统菜单图标、绘制背景等。

3.有了以上方法,我们绘制菜单的工具算是齐备了,但是还少一些东西,那就是菜单的原料了,比如配色,字体,图标等属性。

另外:这些类中比较重要的是有一套绘制逻辑,比如如何匹配要加载的图标,根据菜单属性分类绘制顶层菜单,一般菜单等不同菜单项的逻辑等。不过大牛已经有现成的给我了,大家可以参考资源中的不同实现方法。

参考代码1:http://download.csdn.net/detail/u010679316/9552044 
参考代码2:http://download.csdn.net/download/exceed_me/2750768


二、在MFC中使用自定义菜单类

1.在应用菜单窗口中,如CMainFrame添加消息映射:
ON_WM_DRAWITEM()
ON_WM_MEASUREITEM()
  • 1
  • 2
  • 1
  • 2
2.然后重写它们对应的函数:
void CMainFrame::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{//CustomMenu为自定义菜单类的实例m_CustomMenu.DrawItem(lpDrawItemStruct);
}
void CMainFrame::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{m_CustomMenu.MeasureItem(lpMeasureItemStruct);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

3.创建自定义菜单类实例,将其与主窗口绑定 
m_CustomMenu.Attach(this->GetMenu()->GetSafeHmenu()); 
或者 SetMenu(m_CustomMenu);

这样,自绘菜单基本上就算完成了


三、相关细节的处理

虽然有前人铺路,但是完全拿来用做项目的应用总是不现实的,总有些效果还需要自己来调。。。 
现在来看,比较容易做到的是改变菜单项的背景,字体的颜色和字号,菜单贴图等。但是整体看来,菜单效果并不理想,主要在以下几个方面:

1.菜单栏背景的绘制

网上的例程中,有些只做了顶层每个菜单项的背景设置,而菜单右侧仍然是系统默认的丑陋的背景色; 
如图: 
这里写图片描述
有一种关于菜单栏背景色绘制的思路是,在绘制顶层菜单时,额外绘制菜单的右侧区域,虽然可以实现显示效果,但是感觉上这样做不科学,额外产生多次绘制。重要的是系统默认背景色如果和你自己设置的菜单项背景色差很大的话,当频繁刷新菜单,系统配色和你的配色切换时就会产生闪烁,这不是我们想要的。 
所以,如果有一种办法,能够在绘制菜单项前就将菜单栏背景色设置为同样的颜色,就会避免了闪烁了。具体如何做呢?上代码:

::MENUINFO mnInfo;
mnInfo.cbSize = sizeof(MENUINFO);
mnInfo.fMask = MIM_BACKGROUND;
mnInfo.hbrBack = (HBRUSH)mnBgBrush;//mnBgBrush 背景色画刷
::SetMenuInfo(menu->m_hMenu, &mnInfo);//menu指向要绘制的菜单
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

也就是说,需要在绘制每项菜单时,先价格整个菜单背景被设置为相同颜色,就不会出现菜单重绘产生的闪烁的问题了。上图: 
这里写图片描述
另外:这个设置还意外地解决了弹出菜单默认的粗边框的问题:如图我们可以看到示例程序中,如果不执行上述代码,只是将每个菜单项的背景设置为了黑色,弹出菜单项会显示一个比较丑的粗的白色边框,这个边框颜色应该是系统默认色。 
这里写图片描述 
之前查了好久,去掉这个粗边框的办法。虽然网上有说可以用消息钩子重绘非客户等一些办法,但是这些总会产生一些其他绘制问题,最终没有使用。但是只要在绘制菜单项背景时确保菜单的背景已经设置为和菜单项相似的颜色,就会只显示一个细边框,看起来就比较舒服了。如图: 
这里写图片描述 
其实,如果我们将绘制菜单项的背景色和上述代码中背景画刷的颜色设为不同颜色就会看到,菜单绘制的具体过程。如果背景画刷为红色,可以看到: 
这里写代码片 
经过单步调试发现,菜单首先获取画刷,绘制一个背景,然后再绘制每一菜单项。我们之前看到的粗边框其实有一部分是整个菜单的背景,也就是没有被单个菜单项遮挡的部分。 
因为自己不清楚菜单绘制机制,走了好多弯路。。。

2、菜单快捷键显示

完成自绘之后,菜单的快捷键均显示下划线。我们希望的是,在菜单没有获得焦点时,不能响应快捷键,不显示下划线,当按下Alt键时才显示下划线。 
解决思路:在菜单没有焦点时,将菜单文本中的“&”去掉,也就不显示下划线。在获得焦点时,显示下划线。 
绘制文本的代码:

if(state &ODS_NOACCEL)
{//没有快捷键,不显示下划线CString str = pText;//pText 为菜单文本str.Replace(_T("&"),_T(""));DrawItemText(pCdc,str,Rect,state,TRUE);//绘制文本
}
else
{//有快捷键,显示下划线DrawItemText(pCdc,pText,Rect,state,TRUE);//绘制文本
}

这篇关于MFC 菜单自绘的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/389672

相关文章

禁止平板,iPad长按弹出默认菜单事件

通过监控按下抬起时间差来禁止弹出事件,把以下代码写在要禁止的页面的页面加载事件里面即可     var date;document.addEventListener('touchstart', event => {date = new Date().getTime();});document.addEventListener('touchend', event => {if (new

Windows如何添加右键新建菜单

Windows如何添加右键新建菜单 文章目录 Windows如何添加右键新建菜单实验环境缘起以新建`.md`文件为例第一步第二步第三步 总结 实验环境 Windows7 缘起 因为我习惯用 Markdown 格式写文本,每次新建一个.txt后都要手动修改为.md,真的麻烦。如何在右键新建菜单中添加.md选项呢? 网上有很多方法,这些方法我都尝试了,要么太麻烦,要么不凑效

MFC中Spin Control控件使用,同时数据在Edit Control中显示

实现mfc spin control 上下滚动,只需捕捉spin control 的 UDN_DELTAPOD 消息,如下:  OnDeltaposSpin1(NMHDR *pNMHDR, LRESULT *pResult) {  LPNMUPDOWN pNMUpDown = reinterpret_cast(pNMHDR);  // TODO: 在此添加控件通知处理程序代码    if

控制台和MFC中内存泄露工具vld的使用

最近想检测下项目中内存泄露的情况,选中了vld这款。在查找使用方法的时候,大都是控制台下的示例,添加到main函数所在的源文件上。换成MFC就纠结了,不知道添加到哪里去。本文记录控制台和MFC中的使用vld过程。    vld资源:    1)、大家可以移步下边的网址下载:     http://vld.codeplex.com/releases/view/82311    2

MFC中App,Doc,MainFrame,View各指针的互相获取

纸上得来终觉浅,为了熟悉获取方法,我建了个SDI。 首先说明这四个类的执行顺序是App->Doc->Main->View 另外添加CDialog类获得各个指针的方法。 多文档的获取有点小区别,有时间也总结一下。 //  App void CSDIApp::OnApp() {      //  App      //  Doc     CDocument *pD

PNG透明背景按钮的实现(MFC)

问题描述: 当前要在对话框上添加一个以两个PNG图片作为背景的按钮,PNG图的背景是透明的,按钮也要做出相同的透明效果。并且鼠标不在按钮上时,按钮显示"bg1.png";鼠标移动到按钮上时,按钮显示"bg2.png" 开发环境为VS2010。 解决办法: 使用GDI+库装载PNG图片,并使用MFC Button Control和CMFCButton类结合,调用CMFCButton

MFC 控件重绘(2) NM_CUSTOMDRAW, WM_DRAWITEM, 虚函数DrawItem

控件重绘有三种方法: 1 设定界面属性 2 利用Windows的消息机制,通过Windows消息映射(Message Mapping)和反映射(Message Reflecting),在合适的时机修改控件的状态和行为。此方式涉及NM_CUSTOMDRAW和WM_DRAWITEM 3 利用虚函数机制,重载虚函数。即DrawItem虚函数。 对于NM_CUSTOMDRAW,某些支持此消息的控件

几种MFC对话框的隐藏方法

修改CXXAPP中的InitInstance函数,将原来的模态对话框改为非模态对话框,及修改 [cpp]  view plain copy INT_PTR nResponse = dlg.DoModal();     为 [cpp]  view plain copy dlg.Create(CModalHideDlg::IDD);

如何在Qt的widget上右键显示菜单

如何在Qt的widget上右键显示菜单 今天早上一来,我老大叫我在widget上点击右键加上一个菜单,并相应其响应的功能,因为我成刚接触Qt,所以看了下QtGUI编程这本书,做出来,记录下来,说不定哪天还用得上啊! 废话不多说,直接上代码: 方法一: m_text = QTextCodec::codecForLocale(); ui->tableWidget->addAction(ne

java AWT PopupMenu(右键菜单)

右键菜单使用PopupMenu对象表示,创建步骤如下: (1)创建PopupMenu的实例。 (2)创建多个MenuItem的多个实例,依次将这些实例加入到PopupMenu中。 (3)将PopupMenu加入到目标组件中。 (4)为需要出现上下文菜单的组件编写鼠标监听器,当用户释放鼠标右键时弹出右键菜单。 package javaAWT;import java.awt.BorderLa