15,979
社区成员
发帖
与我相关
我的任务
分享
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;
}
// 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 );
}
}
#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;
};