带图标的程序菜单
本文介绍在基于单文档程序中,如何实现带图标的程序菜单。如下:
1.
创建一个单文档工程:
AddIconMenu
2.
这个工程里面用到了一个类来实现对程序菜单图标的添加以及颜色的设定等等。添加到工程。头文件如下:
IconMenu.h
// IconMenu1.h: interface for the CIconMenu class.
//
//
#if
!defined(
AFX_ICONMENU1_H__FAA8B855_EE72_4332_96D7_73F8FA07E521__INCLUDED_
)
#define
AFX_ICONMENU1_H__FAA8B855_EE72_4332_96D7_73F8FA07E521__INCLUDED_
#if _MSC_VER
> 1000
#pragma
once
#endif
// _MSC_VER > 1000
const
int
MAX_MENUCOUNT
= 60,
ITEMHEIGHT
= 26,
ITEMWIDTH
= 120;
//
菜单项数量
/*************************************
CMenuItemInfo
结构用于记录菜单项信息
*************************************/
struct
CMenuItemInfo
{
CString
m_ItemText
;
//
菜单项文本
int
m_IconIndex
;
//
菜单项索引
int
m_ItemID
;
//
菜单标记
-2
顶层菜单
,-1
弹出式菜单
,0
分隔条
,
其他普通菜单
};
class
CIconMenu
:
public
CMenu
{
public
:
CMenuItemInfo
m_ItemLists
[
MAX_MENUCOUNT
];
//
菜单项信息
int
m_index
;
//
临时索引
int
m_iconindex
;
CImageList
m_imagelist
;
//
存储菜单项图标
CIconMenu
();
BOOL
ChangeMenuItem
(
CMenu
*
m_menu
,
BOOL
m_Toped
=
FALSE
);
BOOL
AttatchMenu
(
HMENU
m_hmenu
);
void
DrawItemText
(
CDC
*
m_pdc
,
LPSTR
str
,
CRect
m_rect
);
void
DrawTopMenu
(
CDC
*
m_pdc
,
CRect
m_rect
,
BOOL
m_selected
=
FALSE
);
//
绘制顶层菜单
void
DrawSeparater
(
CDC
*
m_pdc
,
CRect
m_rect
);
//
绘制分隔条
void
DrawComMenu
(
CDC
*
m_pdc
,
CRect
m_rect
,
COLORREF
m_fromcolor
,
COLORREF
m_tocolor
,
BOOL
m_selected
=
FALSE
);
void
DrawMenuIcon
(
CDC
*
m_pdc
,
CRect
m_rect
,
int
m_icon
);
//override memu's viutual method
virtual
~
CIconMenu
();
virtual
void
MeasureItem
(
LPMEASUREITEMSTRUCT
lpStruct
);
//
设置菜单项大小
virtual
void
DrawItem
(
LPDRAWITEMSTRUCT
lpStruct
);
//
重绘菜单项
};
#endif
// !defined(AFX_ICONMENU1_H__FAA8B855_EE72_4332_96D7_73F8FA07E521__INCLUDED_)
实现文件如下:
// IconMenu1.cpp: implementation of the CIconMenu class.
//
//
#include
"stdafx.h"
//#include "IconMenu.h"
//#include "IconMenu1.h"
#include
"AddIconMenu.h"
#include
"IconMenu.h"
#ifdef
_DEBUG
#undef
THIS_FILE
static
char
THIS_FILE
[]=
__FILE__
;
#define
new
DEBUG_NEW
#endif
//
// Construction/Destruction
//
CIconMenu
::
CIconMenu
()
{
m_index
= 0;
m_iconindex
= 0;
//
创建图像列表
m_imagelist
.
Create
(16,16,
ILC_COLOR24
|
ILC_MASK
,0,0);
//
添加图标
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON1
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON2
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON3
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON4
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON5
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON6
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON7
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON8
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON9
));
m_imagelist
.
Add
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON10
));
}
CIconMenu
::~
CIconMenu
()
{
m_imagelist
.
Detach
();
}
BOOL
CIconMenu
::
AttatchMenu
(
HMENU
m_hmenu
)
{
this
->
Attach
(
m_hmenu
);
return
TRUE
;
}
BOOL
CIconMenu
::
ChangeMenuItem
(
CMenu
*
m_menu
,
BOOL
m_Toped
)
{
if
(
m_menu
!=
NULL
)
{
int
m_itemcount
=
m_menu
->
GetMenuItemCount
();
for
(
int
i
=0;
i
<
m_itemcount
;
i
++)
{
m_menu
->
GetMenuString
(
i
,
m_ItemLists
[
m_index
].
m_ItemText
,
MF_BYPOSITION
);
int
m_itemID
=
m_menu
->
GetMenuItemID
(
i
);
if
(
m_itemID
==-1 &&
m_Toped
)
{
m_itemID
= -2;
//
顶层菜单
};
m_ItemLists
[
m_index
].
m_ItemID
=
m_itemID
;
if
(
m_itemID
>0)
{
m_ItemLists
[
m_index
].
m_IconIndex
=
m_iconindex
;
m_iconindex
+=1;
}
m_menu
->
ModifyMenu
(
i
,
MF_OWNERDRAW
|
MF_BYPOSITION
|
MF_STRING
,
m_ItemLists
[
m_index
].
m_ItemID
,(
LPSTR
)&(
m_ItemLists
[
m_index
]));
m_index
+=1;
CMenu
*
m_subMenu
=
m_menu
->
GetSubMenu
(
i
);
if
(
m_subMenu
)
{
ChangeMenuItem
(
m_subMenu
);
}
}
}
return
TRUE
;
}
void
CIconMenu
::
MeasureItem
(
LPMEASUREITEMSTRUCT
lpStruct
)
{
if
(
lpStruct
->
CtlType
==
ODT_MENU
)
{
lpStruct
->
itemHeight
=
ITEMHEIGHT
;
lpStruct
->
itemWidth
=
ITEMWIDTH
;
CMenuItemInfo
*
m_iteminfo
;
m_iteminfo
= (
CMenuItemInfo
*)
lpStruct
->
itemData
;
lpStruct
->
itemWidth
= ((
CMenuItemInfo
*)
lpStruct
->
itemData
)->
m_ItemText
.
GetLength
()*10;
switch
(
m_iteminfo
->
m_ItemID
)
{
case
0:
//
分隔条
{
lpStruct
->
itemHeight
= 1;
break
;
}
}
}
}
void
CIconMenu
::
DrawItem
(
LPDRAWITEMSTRUCT
lpStruct
)
{
if
(
lpStruct
->
CtlType
==
ODT_MENU
)
{
if
(
lpStruct
->
itemData
==
NULL
)
return
;
unsigned
int
m_state
=
lpStruct
->
itemState
;
CDC
*
m_dc
=
CDC
::
FromHandle
(
lpStruct
->
hDC
);
//m_dc.Attach(lpStruct->hDC);
CString
str
= ((
CMenuItemInfo
*)(
lpStruct
->
itemData
))->
m_ItemText
;
LPSTR
m_str
=
str
.
GetBuffer
(
str
.
GetLength
());
int
m_itemID
= ((
CMenuItemInfo
*)(
lpStruct
->
itemData
))->
m_ItemID
;
int
m_itemicon
= ((
CMenuItemInfo
*)(
lpStruct
->
itemData
))->
m_IconIndex
;
CRect
m_rect
=
lpStruct
->
rcItem
;
m_dc
->
SetBkMode
(
TRANSPARENT
);
switch
(
m_itemID
)
{
case
-2:
{
DrawTopMenu
(
m_dc
,
m_rect
,(
m_state
&
ODS_SELECTED
)||(
m_state
&0x0040));
//0x0040 ==ODS_HOTLIGHT
DrawItemText
(
m_dc
,
m_str
,
m_rect
);
break
;
}
case
-1:
{
DrawItemText
(
m_dc
,
m_str
,
m_rect
);
break
;
}
case
0:
{
DrawSeparater
(
m_dc
,
m_rect
);
break
;
}
default
:
{
DrawComMenu
(
m_dc
,
m_rect
,0xfaa0,0xf00ff,
m_state
&
ODS_SELECTED
);
DrawItemText
(
m_dc
,
m_str
,
m_rect
);
DrawMenuIcon
(
m_dc
,
m_rect
,
m_itemicon
);
break
;
}
}
}
}
/*************************************************************
功能描述
:
绘制菜单项文本
参数说明
: m_pdc
标识画布对象
,str
标识菜单文本
,m_rect
标识菜单区域
*************************************************************/
void
CIconMenu
::
DrawItemText
(
CDC
*
m_pdc
,
LPSTR
str
,
CRect
m_rect
)
{
m_rect
.
DeflateRect
(20,0);
m_pdc
->
DrawText
(
str
,
m_rect
,
DT_SINGLELINE
|
DT_VCENTER
|
DT_LEFT
);
}
void
CIconMenu
::
DrawTopMenu
(
CDC
*
m_pdc
,
CRect
m_rect
,
BOOL
m_selected
)
{
if
(
m_selected
)
{
m_pdc
->
SelectStockObject
(
BLACK_PEN
);
m_pdc
->
Rectangle
(&
m_rect
);
m_rect
.
DeflateRect
(1,1);
m_pdc
->
FillSolidRect
(
m_rect
,
RGB
(150, 185, 255));
}
else
{
CRect
rect
;
AfxGetMainWnd
()->
GetClientRect
(
rect
);
rect
.
top
=
m_rect
.
top
;
rect
.
bottom
=
m_rect
.
bottom
;
rect
.
left
= 360;
rect
.
right
+=4;
//CRect c_rect(m_rect);
m_pdc
->
FillSolidRect
(&
rect
,
RGB
(200,187, 255));
m_pdc
->
FillSolidRect
(&
m_rect
,
RGB
(200,187, 255));
//m_pdc->SelectStockObject(BLACK_PEN);
//m_pdc->FillSolidRect(m_rect,RGB(100, 185, 255));
}
}
void
CIconMenu
::
DrawSeparater
(
CDC
*
m_pdc
,
CRect
m_rect
)
{
if
(
m_pdc
!=
NULL
)
{
m_pdc
->
Draw3dRect
(
m_rect
,
RGB
(255,0,0),
RGB
(0,0,255));
}
}
void
CIconMenu
::
DrawComMenu
(
CDC
*
m_pdc
,
CRect
m_rect
,
COLORREF
m_fromcolor
,
COLORREF
m_tocolor
,
BOOL
m_selected
)
{
if
(
m_selected
)
{
m_pdc
->
Rectangle
(
m_rect
);
m_rect
.
DeflateRect
(1,1);
int
r1
,
g1
,
b1
;
//
读取渐变起点的颜色值
r1
=
GetRValue
(
m_fromcolor
);
g1
=
GetGValue
(
m_fromcolor
);
b1
=
GetBValue
(
m_fromcolor
);
int
r2
,
g2
,
b2
;
//
读取渐变终点的颜色值
r2
=
GetRValue
(
m_tocolor
);
g2
=
GetGValue
(
m_tocolor
);
b2
=
GetBValue
(
m_tocolor
);
float
r3
,
g3
,
b3
;
//
菜单区域水平方向每个点
RGB
值应该变化的度
(
范围
)
r3
= ((
float
)(
r2
-
r1
)) / (
float
)(
m_rect
.
Height
());
g3
= (
float
)(
g2
-
g1
)/(
float
)(
m_rect
.
Height
());
b3
= (
float
)(
b2
-
b1
)/(
float
)(
m_rect
.
Height
());
COLORREF
r
,
g
,
b
;
//
菜单区域水平方向每个点的颜色值
CPen
*
m_oldpen
;
for
(
int
i
=
m_rect
.
top
;
i
<
m_rect
.
bottom
;
i
++)
{
r
=
r1
+(
int
)
r3
*(
i
-
m_rect
.
top
);
g
=
g1
+(
int
)
g3
*(
i
-
m_rect
.
top
);
b
=
b1
+ (
int
)
b3
*(
i
-
m_rect
.
top
);
CPen
m_pen
(
PS_SOLID
,1,
RGB
(
r
,
g
,
b
));
m_oldpen
=
m_pdc
->
SelectObject
(&
m_pen
);
m_pdc
->
MoveTo
(
m_rect
.
left
,
i
);
m_pdc
->
LineTo
(
m_rect
.
right
,
i
);
}
m_pdc
->
SelectObject
(
m_oldpen
);
}
else
{
m_pdc
->
FillSolidRect
(
m_rect
,
RGB
(0x000000F9, 0x000000F8, 0x000000F7));
}
}
void
CIconMenu
::
DrawMenuIcon
(
CDC
*
m_pdc
,
CRect
m_rect
,
int
m_icon
)
{
m_imagelist
.
Draw
(
m_pdc
,
m_icon
,
CPoint
(
m_rect
.
left
+2,
m_rect
.
top
+4),
ILD_TRANSPARENT
);
}
当然这里面需要的图标资源,自己拷贝到
res
目录下即可。
3.
然后在文档类中添加
SetTitle
消息,可以修改标题栏信息,如下:
lpszTitle
=
"
基于单文档结构的带图标的程序菜单
"
;
4. CMainFrame
中添加一个上述类的变量:
CIconMenu
m_Menu
;
CMainFrame
的
OnCreate
函数中,添加经过上述类设置的菜单,代码如下:
m_Menu
.
AttatchMenu
(
this
->
GetMenu
()->
GetSafeHmenu
());
m_Menu
.
ChangeMenuItem
(&
m_Menu
,
TRUE
);
this
->
SetIcon
(
AfxGetApp
()->
LoadIcon
(
IDI_ICON1
),
TRUE
);
this
->
SetTitle
(
"IconMenuExample"
);
5.
分别为
CMainFrame
添加,如下两个消息函数
WM_DRAWITEM
()
和
WM_MEASUREITEM
()
,不知道为什么,我的消息函数中没有,所以就手工添加了。在消息映射中添加如下:
ON_WM_DRAWITEM
()
ON_WM_MEASUREITEM
()
然后添加函数及实现如下:
void
CMainFrame
::
OnDrawItem
(
int
nIDCtl
,
LPDRAWITEMSTRUCT
lpDrawItemStruct
)
{
m_Menu
.
DrawItem
(
lpDrawItemStruct
);
}
void
CMainFrame
::
OnMeasureItem
(
int
nIDCtl
,
LPMEASUREITEMSTRUCT
lpMeasureItemStruct
)
{
m_Menu
.
MeasureItem
(
lpMeasureItemStruct
);
}
OK
,好了,直接运行,即可。