实现自绘菜单

简介: 为了实现菜单的自绘,花了我几个小时,其实真正解决后又发现很简单。实现菜单的自绘只需要三个步骤: 第一步:将所有菜单项设置为MF_OWNERDRAW,即自绘模式 第二步:在WM_MEASUREITEM消息中设置菜单项的大小 第三步:在WM_DRAWITEM消息中进行菜单项的绘制 问题首先出现在...

为了实现菜单的自绘,花了我几个小时,其实真正解决后又发现很简单。实现菜单的自绘只需要三个步骤:

第一步:将所有菜单项设置为MF_OWNERDRAW,即自绘模式

第二步:在WM_MEASUREITEM消息中设置菜单项的大小

第三步:在WM_DRAWITEM消息中进行菜单项的绘制

问题首先出现在了第一步,我要绘制的是一个上下文菜单,即右键菜单,要将菜单项设置为MF_OWNERDRAW,需要用到ModifyMenu函数,起始由于ModifyMenu函数的参数设置错误,导致程序怎么也响应不了WM_MEASUREITEM和WM_DRAWITEM消息,所以建议在使用ModifyMenu时对返回值进行检查。

void CMainWindow::OnRButtonDown(UINT nFlags, CPoint point) {     ClientToScreen(&point);     CMenu Menu;     Menu.LoadMenuW(IDR_MENU2);     CMenu *pMenu = Menu.GetSubMenu(0);     CString strText;     for (int i = 0; i < pMenu->GetMenuItemCount(); i++)     {         BOOL bModi = pMenu->ModifyMenuW(ID_123_456 + i, MF_BYCOMMAND|MF_OWNERDRAW, ID_123_456 + i);         if (!bModi)        {               TRACK("ModifyMenu fail!");        }         pMenu->GetMenuStringW(i, strText, MF_BYPOSITION);     }     pMenu->TrackPopupMenu(TPM_LEFTBUTTON|TPM_LEFTALIGN,         point.x,         point.y,         this); }

第一步的问题解决后,接在在第二步的WM_MEASUREITEM消息中设置菜单项的大小:

void CMainWindow::OnMeasureItem(int nIDCtl, LPMEASUREITEMSTRUCT lpmis) {     //lpmis->itemWidth = ::GetSystemMetrics(SM_CYMENU) * 4;     lpmis->itemWidth = 150;     lpmis->itemHeight = ::GetSystemMetrics(SM_CYMENU); }  在WM_MEASUREITEM消息中设置的菜单项大小会传入WM_DRAWITEM消息中,然后再在WM_DRAWITEM消息中根据菜单项的大小来进行重绘。

到第三步也遇到了几个问题,由于最初对WM_DRAWITEM消息中的LPDRAWITEMSTRUCT结构体不了解,以致写出的程序不管在什么时候都会作同一个绘制操作,先来看看WM_DRAWITEM消息的声明:

afx_msg void CMainWindow::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis);

在这个消息中有两个参数,在自绘菜单时,两个参数都要用到。其中nIDCtl,书上说是所属控件的ID,不太明白是什么意思,在MSDN看到,对于菜单发出的WM_DRAWITEM消息,nIDCtl为0。再说LPDRAWITEMSTRUCT结构体,该结构体中包含了菜单复选状态、选中状态以及菜单项的大小等信息。

下面是OnDrawItem消息的实现代码:

void CMainWindow::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpdis) {     CBrush *brush = new CBrush;     CPen *pen = new CPen;     CString strText;     CDC *pDC = CDC::FromHandle(lpdis->hDC); //获取菜单项的设备句柄     //菜单项是否为选中状态     if ((lpdis->itemState & ODS_SELECTED))     {         //在菜单项上自绘矩形框的背景颜色         brush->CreateSolidBrush(RGB(182, 189,210));         //在菜单项自绘矩形的边框颜色         pen->CreatePen(PS_SOLID, 1, RGB(10,36,106));         //设置菜单项的文字背景颜色         pDC->SetBkColor(RGB(182,189,210));     }     else     {         brush->CreateSolidBrush(GetSysColor(COLOR_MENU));         pen->CreatePen(PS_SOLID, 0, GetSysColor(COLOR_MENU));         pDC->SetBkColor(GetSysColor(COLOR_MENU));     }     pDC->SelectObject(pen);     pDC->SelectObject(brush);     //在当前菜单项上画一个矩形框     pDC->Rectangle(lpdis->rcItem.left,         lpdis->rcItem.top,         lpdis->rcItem.right,         lpdis->rcItem.bottom);     /*--------------------------------------*/     //获取当前消息所在菜单项的文本     CMenu menu;     menu.Attach((HMENU)lpdis->hwndItem);     menu.GetMenuStringW(lpdis->itemID, strText,MF_BYCOMMAND);     /*--------------------------------------*/     //如果为菜单发出的DrawItem消息     if (nIDCtl == 0)     {         //在菜单项上输出菜单文本         pDC->TextOutW(lpdis->rcItem.left + 20, lpdis->rcItem.top + 4, strText.GetBuffer(0), strText.GetLength());     }     menu.Detach();     delete brush;     delete pen; }

效果图:

 

参考资料:http://www.vckbase.com/document/viewdoc/?id=1583

目录
相关文章
|
4月前
|
搜索推荐 区块链 C++
C++ Qt开发:ToolBar与MenuBar菜单组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍`ToolBar`工具栏组件以及与之类似的`MenuBar`菜单栏组件的常用方法及灵活运用。
87 1
|
4月前
|
C++ UED 索引
C++ Qt开发:StatusBar底部状态栏组件
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍`QStatusBar`底部状态栏组件的常用方法及灵活运用。`QStatusBar` 是 Qt 中用于在主窗口底部显示状态信息的部件。它通常用于向用户提供应用程序的当前状态、进度信息、或者其他与应用程序运行相关的消息。通过在状态栏上显示文本、永久部件、进度条等内容,可以为用户提供清晰的反馈和实时信息。在设计应用程序界面时,使用状态栏有助于提升用户体验。
37 0
C++ Qt开发:StatusBar底部状态栏组件
从零开始学Pyqt5之【控件介绍】(17):菜单栏QMenuBar、QToolBar工具栏、QStatusBar状态栏
从零开始学Pyqt5之【控件介绍】(17):菜单栏QMenuBar、QToolBar工具栏、QStatusBar状态栏
从零开始学Pyqt5之【控件介绍】(17):菜单栏QMenuBar、QToolBar工具栏、QStatusBar状态栏
UGUI系列-鼠标移动到按钮上显示信息(Unity3D)
有时候图标不能很好的说明这个功能的解释,就需要一些说明性文字显示。就比如可以在鼠标移动到UI上面的时候显示文字。 那么如何在UGUI上,鼠标移动上去显示文字说明呢。 大家都知道,当鼠标移动到button按钮上面的时候会出现变化,主要是button这个组件在控制
C# winform 获取标题栏,状态栏,菜单栏的高度
//获得当前窗体标题栏高度 MessageBox.Show("当前窗体标题栏高度"+(this.
1687 0
Qt-网易云音乐界面实现-1 窗口隐藏拖拽移动,自定义标题栏
最近也换了公司,也换了新的工作,工资也象征性的涨了一点点,但是最近心里还是慌慌,不知道为什么,没有那种踏实感,感觉自己随时可以被抛弃的感觉。感觉自己在荒废时间,也感觉自己在浪费生命。
239 0
Qt-网易云音乐界面实现-1 窗口隐藏拖拽移动,自定义标题栏
QT 标题栏隐藏可拖拽
这个也是我网上找到了 为了方便,记录一下
111 0
半透明菜单导航
在线演示 本地下载
783 0