分享一个我自己写的较简单的菜单美化类CMenuEx

zhllxt 2011-03-18 08:40:53

源代码:http://download.csdn.net/source/3105184

工作时遇到对话框上的LISTCTRL的右键菜单想要美化一下,然后看了一些网上的美化菜单类,自己做了一个适合自己的。包含头文件后只需要在CMainFrame的OnCreate 或 CDialog的OnInitDialog 函数中加入代码 CMenuEx::SubclassMenu( this ); 即可。没有非常繁杂的在这里那里加入代码的操作。

可以美化单文档,对话框,对话框上的LISTCTRL的右键菜单等。多文档存在一些问题,我看过网上的其它的MENU美化类,对多文档也存在一些BUG。没有深入的研究,能够满足我平常的应用了。

代码比较简单,初学者看看应该有好处。

这里贴图太麻烦,就不帖图了。

平台是VS 2008的。
...全文
419 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
向立天 2011-04-11
  • 打赏
  • 举报
回复
您好
我是本版版主
此帖已多日无人关注
请您及时结帖
如您认为问题没有解决可按无满意结帖处理
另外本版设置了疑难问题汇总帖
并已在版面置顶
相关规定其帖子中有说明
您可以根据规定提交您帖子的链接
如您目前不想结帖只需回帖说明
我们会删除此结帖通知

见此回复三日内无回应
我们将强制结帖
相关规定详见界面界面版关于版主结帖工作的具体办法
zgsdzhaolanxiang1 2011-03-18
  • 打赏
  • 举报
回复
支持一下,,
zhllxt 2011-03-18
  • 打赏
  • 举报
回复


void CMenuEx::OnDrawItem( CWnd * pWnd,int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct )
{
//判断是不是菜单自绘,因为按钮也可以自绘
if( nIDCtl == 0 )//If a menu sent the message, nIDCtl contains 0.
{
CDC* pDC = CDC::FromHandle( lpDrawItemStruct->hDC );//得到菜单设备指针,用来绘制菜单字串
if( pDC )
{
int nSavedDC = pDC->SaveDC();

CRect rcItem( lpDrawItemStruct->rcItem );//得到当前绘制菜单选项项大小
CRect rcLeftSpace( rcItem.left,rcItem.top,rcItem.left + 24,rcItem.bottom );
CRect rcRightSpace( rcItem.left + 32,rcItem.top,rcItem.right,rcItem.bottom );

if( lpDrawItemStruct->itemID != ID_SEPARATOR ) //菜单和分隔栏分别绘制
{
CMenu * pMenu = CMenu::FromHandle( (HMENU)lpDrawItemStruct->hwndItem );//
if( pMenu && pMenu->GetSafeHmenu() && IsMenu( pMenu->m_hMenu ) )
{
pDC->SetBkMode( TRANSPARENT );

CString strText;
UINT uFormat;
pMenu->GetMenuString( lpDrawItemStruct->itemID,strText,MF_BYCOMMAND );//得到当前绘制菜单选项文本
if( lpDrawItemStruct->itemData & 0x80000000 )//顶层框架菜单项,如“文件”“编辑”等
{
CRect rcFrameMenuItem( rcItem );
rcFrameMenuItem.InflateRect( -1,-1 );
pDC->FillSolidRect( rcFrameMenuItem,GetSysColor( COLOR_3DFACE ) );//用指定色填充背景
if( lpDrawItemStruct->itemState & ODS_SELECTED )
{
pDC->FillSolidRect( rcFrameMenuItem,0xffffff ); //绘制
pDC->FrameRect( rcFrameMenuItem,&CBrush( 0xC56A31 ) );
}
else if( lpDrawItemStruct->itemState & ODS_HOTLIGHT )
{
pDC->FillSolidRect( rcFrameMenuItem,0xEDD2C1 ); //绘制
pDC->FrameRect( rcFrameMenuItem,&CBrush( 0xC56A31 ) );
}
pDC->SetTextColor( ( lpDrawItemStruct->itemState & ODS_GRAYED ) ? 0x99A8AC : 0x000000 );
uFormat = DT_CENTER | DT_VCENTER | DT_WORDBREAK | DT_SINGLELINE | DT_EXPANDTABS | DT_TABSTOP;
pDC->DrawText( strText,rcFrameMenuItem,uFormat );//打印出字体
}
else
{
pDC->FillSolidRect( rcItem,0xF9F9F9 );//用白色填充背景
pDC->FillSolidRect( rcLeftSpace,0xD8E9ED );//在左侧画阴影
if( lpDrawItemStruct->itemState & ODS_SELECTED )//菜单处于选中状态
{
if( !( lpDrawItemStruct->itemState & ODS_GRAYED ) )//不是灰色菜单
{
pDC->FillSolidRect( rcItem,0xEDD2C1 ); //绘制
pDC->FrameRect( rcItem,&CBrush( 0xC56A31 ) );
}
}
if( lpDrawItemStruct->itemState & ODS_CHECKED )//
{
CRect rcCheck( rcLeftSpace );
rcCheck.InflateRect( -2,-2 );
if( lpDrawItemStruct->itemState & ODS_SELECTED )//菜单处于选中状态
pDC->FillSolidRect( rcCheck,0xE4BBA2 );
else
pDC->FillSolidRect( rcCheck,0xF6E8E0 );
pDC->FrameRect( rcCheck,&CBrush( 0xC56A31 ) );
uFormat = DT_CENTER | DT_VCENTER | DT_SINGLELINE;
pDC->DrawText( _T("√"),rcCheck,uFormat );//打印出字体
}
//画图标
if( m_pImageList != NULL )
{
int i,nCount = m_nResourceIDArray.GetCount();
for( i = 0; i < nCount; i++ )
{
if( lpDrawItemStruct->itemID == m_nResourceIDArray.GetAt( i ) && m_pImageList->GetImageCount() > i )
{
IMAGEINFO ImageInfo;
memset( &ImageInfo,0,sizeof( IMAGEINFO ) );
m_pImageList->GetImageInfo( i,&ImageInfo );
CRect rcBitmap( rcLeftSpace );
rcBitmap.left += ( rcBitmap.Width() - ( ImageInfo.rcImage.right - ImageInfo.rcImage.left ) + 1 ) / 2;
rcBitmap.top += ( rcBitmap.Height() - ( ImageInfo.rcImage.bottom - ImageInfo.rcImage.top ) + 1 ) / 2;
if( ( lpDrawItemStruct->itemState & ODS_SELECTED ) && !( lpDrawItemStruct->itemState & ODS_GRAYED ) )//菜单处于选中状态
{
rcBitmap.left -= 1;
rcBitmap.top -= 1;
}
m_pImageList->Draw( pDC,i,rcBitmap.TopLeft(),ILD_TRANSPARENT );
}
}
}
//写文字
CString strLeft( strText ),strRight;
int nTabIndex = strText.Find('\t');
if( nTabIndex > 0 )
{
strLeft = strText.Left( nTabIndex );
strRight = strText.Right( strText.GetLength() - nTabIndex - 1 );
}
pDC->SetTextColor( ( lpDrawItemStruct->itemState & ODS_GRAYED ) ? 0x99A8AC : 0x000000 );
uFormat = ( 10 << 8 ) | DT_VCENTER | DT_WORDBREAK | DT_SINGLELINE | DT_EXPANDTABS | DT_TABSTOP;
pDC->DrawText( strLeft,rcRightSpace,uFormat );//打印出字体
if( !strRight.IsEmpty() )
{
CRect rcRightText( rcRightSpace.left,rcRightSpace.top,rcRightSpace.right - 16,rcRightSpace.bottom );
uFormat = DT_RIGHT | DT_VCENTER | DT_WORDBREAK | DT_SINGLELINE | DT_EXPANDTABS | DT_TABSTOP;
pDC->DrawText( strRight,rcRightText,uFormat );//打印出字体
}
}
}
}
else
{
pDC->FillSolidRect( rcItem,0xF9F9F9 );//用白色填充背景
pDC->FillSolidRect( rcLeftSpace,0xD8E9ED );//在左侧画阴影
CRect rcSeparator( rcRightSpace.left,rcRightSpace.top + rcRightSpace.Height() / 2,rcRightSpace.right,rcRightSpace.top + rcRightSpace.Height() / 2 + 1 );
pDC->FillRect( rcSeparator,&CBrush( 0x99A8AC ) );//绘制分隔栏
}
pDC->RestoreDC( nSavedDC );
}
}
}

LRESULT CALLBACK CMenuEx::WindowProc( HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam )
{
LRESULT lResult = 0;
CMenuEx * pMenu = (CMenuEx *)GetProp( hWnd,CMenuEx_Window_Prop_Name );
if( pMenu )
{
WNDPROC wndProcPrev = NULL;
if( pMenu->m_mapWndProc.Lookup( hWnd,wndProcPrev ) )
{
switch(uMsg)
{
case WM_INITMENU:
lResult = CallWindowProc( wndProcPrev,hWnd,uMsg,wParam,lParam );
pMenu->OnInitMenu( CWnd::FromHandle( hWnd ),CMenu::FromHandle( (HMENU)wParam ) );
return lResult;
case WM_INITMENUPOPUP:
lResult = CallWindowProc( wndProcPrev,hWnd,uMsg,wParam,lParam );
pMenu->OnInitMenuPopup( CWnd::FromHandle( hWnd ),CMenu::FromHandle( (HMENU)wParam ),LOWORD( lParam ),HIWORD( lParam ) );
return lResult;
case WM_MEASUREITEM:
pMenu->OnMeasureItem( CWnd::FromHandle( hWnd ),wParam,(LPMEASUREITEMSTRUCT)lParam );
break;
case WM_DRAWITEM:
pMenu->OnDrawItem( CWnd::FromHandle( hWnd ),wParam,(LPDRAWITEMSTRUCT)lParam );
break;
case WM_NCDESTROY:
SetWindowLong( hWnd,GWL_WNDPROC,(LONG)wndProcPrev );//设置回以前的窗口过程
RemoveProp( hWnd,CMenuEx_Window_Prop_Name );//移除窗口标记
pMenu->m_mapWndProc.RemoveKey( hWnd );//移除 窗口句柄-窗口过程 MAP对
break;
default:
break;
}
return CallWindowProc( wndProcPrev,hWnd,uMsg,wParam,lParam );
}
}
return 0L;
}
zhllxt 2011-03-18
  • 打赏
  • 举报
回复
这是源文件:

// MenuEx.cpp : 实现文件
//

#include "stdafx.h"
#include "MenuEx.h"


// CMenuEx

CMenuEx::CMenuEx()
{
m_pImageList = NULL;
}

CMenuEx::~CMenuEx()
{
if( m_pImageList )
{
m_pImageList->DeleteImageList();
delete m_pImageList;
m_pImageList = NULL;
}
m_Bitmap.DeleteObject();
}

CMenuEx * CMenuEx::SubclassMenu( CWnd * pWnd )
{
if( pWnd && pWnd->GetSafeHwnd() && IsWindow( pWnd->m_hWnd ) )
{
static CMenuEx menu;

WNDPROC wndProcPrev = NULL;
if( menu.m_mapWndProc.Lookup( pWnd->m_hWnd,wndProcPrev ) )//此窗口菜单已经被设置自绘则返回
{
return &menu;
}

wndProcPrev = (WNDPROC)::SetWindowLong( pWnd->m_hWnd,GWL_WNDPROC,(LONG)WindowProc );
menu.m_mapWndProc.SetAt( pWnd->m_hWnd,wndProcPrev );
if( SetProp( pWnd->m_hWnd,CMenuEx_Window_Prop_Name,(HANDLE)(&menu) ) )
{
return &menu;
}
else
{
::SetWindowLong( pWnd->m_hWnd,GWL_WNDPROC,(LONG)wndProcPrev );
return NULL;
}
}
return NULL;
}

void CMenuEx::ModifyMenuStyle( CMenu* pMenu,UINT nItem,BOOL bByPos,BOOL bFrameMenu/* = FALSE*/ )
{
if( pMenu && pMenu->GetSafeHmenu() && IsMenu( pMenu->m_hMenu ) )
{
MENUITEMINFO MenuItemInfo;
memset( &MenuItemInfo,0,sizeof(MenuItemInfo) );
MenuItemInfo.cbSize = sizeof(MENUITEMINFO);
MenuItemInfo.fMask = MIIM_ID | MIIM_TYPE | MIIM_DATA;

if( pMenu->GetMenuItemInfo( nItem,&MenuItemInfo,bByPos ) )
{
MenuItemInfo.fType |= MF_OWNERDRAW;
if( MenuItemInfo.dwItemData == 0 )
{
MenuItemInfo.dwItemData = (DWORD)(pMenu->GetSafeHmenu());
if( bFrameMenu )
{
//菜单项的句柄是int型,int型的最高位用来表示int的正负,但菜单项句柄不会为负数,所以用这里的最高位表示此菜单项是否是顶层框架菜单项
MenuItemInfo.dwItemData |= 0x80000000;//或者 MenuItemInfo.dwItemData |= 0x00000001 << 31 即二进制的 1000 0000 0000 0000 0000 0000 0000 0000;
}
}

pMenu->SetMenuItemInfo( nItem,&MenuItemInfo,bByPos );
}
}
}

void CMenuEx::InitFrameMenu( CWnd * pWnd )
{
if( pWnd && pWnd->GetSafeHwnd() )
{
CMenu * pMenu = pWnd->GetMenu();
if( pMenu && pMenu->GetSafeHmenu() )
{
int i,nCount = pMenu->GetMenuItemCount();
for( i = 0; i < nCount; i++ )
{
ModifyMenuStyle( pMenu,i,TRUE,TRUE );
}
}
}
}

void CMenuEx::OnInitMenu( CWnd * pWnd,CMenu* pMenu )
{
if( pWnd->IsIconic() )
return;
EnumMenus( pMenu );
}

void CMenuEx::OnInitMenuPopup( CWnd * pWnd,CMenu* pMenu,UINT nIndex,BOOL bSysMenu )
{
if( !bSysMenu )//为“最近的文件”菜单项添加自绘标志
{
int i,nID,nCount = pMenu->GetMenuItemCount();
for( i = 0; i < nCount; i++ )
{
nID = pMenu->GetMenuItemID( i );
if( nID >= ID_FILE_MRU_FIRST && nID <= ID_FILE_MRU_LAST )
{
ModifyMenuStyle( pMenu,i,TRUE );
}
}
}
}

void CMenuEx::EnumMenus( CMenu * pMenu )
{
if( pMenu && pMenu->GetSafeHmenu() )
{
int i,nCount = pMenu->GetMenuItemCount();
for( i = 0; i < nCount; i++ )
{
ModifyMenuStyle( pMenu,i,TRUE );

EnumMenus( pMenu->GetSubMenu( i ) );
}
}
}

void CMenuEx::OnMeasureItem( CWnd * pWnd,int nIDCtl,LPMEASUREITEMSTRUCT lpMeasureItemStruct )
{
if( lpMeasureItemStruct->CtlType == ODT_MENU )//判断是不是菜单要自绘
{
//OnMeasureItem函数对每个菜单项只会调用一次,下次再次弹出菜单式此函数不会再次调用
if( lpMeasureItemStruct->itemID != ID_SEPARATOR )//
{
CMenu * pMenu = CMenu::FromHandle( (HMENU)(lpMeasureItemStruct->itemData & 0x7FFFFFFF) );
if( pMenu && pMenu->GetSafeHmenu() && IsMenu( pMenu->m_hMenu ) )
{
CDC * pDC = pWnd->GetDC();
if( pDC )
{
CString strText;
pMenu->GetMenuString( lpMeasureItemStruct->itemID,strText,MF_BYCOMMAND );
CSize size = pDC->GetTabbedTextExtent( strText,0,NULL );
if( lpMeasureItemStruct->itemData & 0x80000000 )//顶层框架菜单项,如“文件”“编辑”等
lpMeasureItemStruct->itemWidth = size.cx - 8;
else
lpMeasureItemStruct->itemWidth = size.cx + 32;//普通菜单项 宽度 所有菜单项都设置宽度后,显示时会自动扩展到以最长宽度为准
pWnd->ReleaseDC( pDC );
}
}
lpMeasureItemStruct->itemHeight = 24;//普通菜单高度
}
else
{
lpMeasureItemStruct->itemHeight = 8;//分隔栏高度
lpMeasureItemStruct->itemWidth = 1;//分隔栏宽度
}
}
}

void CMenuEx::SetImageList( UINT nBitmapResourceID,COLORREF crMask,int cx,int cy,UINT * nResourceIDArray,UINT nResourceIDCount )
{
if( m_pImageList == NULL )
{
m_pImageList = new CImageList();
}
m_pImageList->DeleteImageList();
m_nResourceIDArray.RemoveAll();
UINT i;
for( i = 0; i < nResourceIDCount; i++ )
{
m_nResourceIDArray.Add( nResourceIDArray[i] );
}
if( m_pImageList->Create( cx,cy,ILC_MASK | ILC_COLOR24,8,1 ) )
{
m_Bitmap.DeleteObject();
m_Bitmap.LoadBitmap( nBitmapResourceID );
m_pImageList->Add( &m_Bitmap,crMask );
}
}

zhllxt 2011-03-18
  • 打赏
  • 举报
回复
再帖上代码吧。
这是头文件:


#define CMenuEx_Window_Prop_Name _T("CMenuEx_Window_Prop_Name")

class CMenuEx
{
public:
CMenuEx();
virtual ~CMenuEx();

public:
static CMenuEx * SubclassMenu( CWnd * pWnd );

void InitFrameMenu( CWnd * pWnd );
void SetImageList( UINT nBitmapResourceID,COLORREF crMask,int cx,int cy,UINT * nResourceIDArray,UINT nResourceIDCount );

public:
void OnInitMenu( CWnd * pWnd,CMenu* pMenu );
void OnInitMenuPopup( CWnd * pWnd,CMenu* pMenu,UINT nIndex,BOOL bSysMenu );

void OnMeasureItem( CWnd * pWnd,int nIDCtl,LPMEASUREITEMSTRUCT lpMeasureItemStruct );
void OnDrawItem( CWnd * pWnd,int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct );

protected:
void ModifyMenuStyle( CMenu* pMenu,UINT nItem,BOOL bByPos,BOOL bFrameMenu = FALSE );
void EnumMenus( CMenu * pMenu );

static LRESULT CALLBACK WindowProc( HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam );

protected:
CBitmap m_Bitmap;//设定为成员变量的原因:The application must call the DeleteObject function to delete each bitmap handle returned by the LoadBitmap function.
CImageList * m_pImageList;
CUIntArray m_nResourceIDArray;

CMap< HWND,HWND,WNDPROC,WNDPROC > m_mapWndProc;
};

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧