MenuEx.cpp
上传用户:lj3531212
上传日期:2007-06-18
资源大小:346k
文件大小:12k
源码类别:

绘图程序

开发平台:

Visual C++

  1. // MenuEx.cpp: implementation of the CMenuEx class.
  2. //
  3. //////////////////////////////////////////////////////////////////////
  4. #include "stdafx.h"
  5. #include "MenuEx.h"
  6. #ifdef _DEBUG
  7. #undef THIS_FILE
  8. static char THIS_FILE[]=__FILE__;
  9. #define new DEBUG_NEW
  10. #endif
  11. //////////////////////////////////////////////////////////////////////
  12. // Construction/Destruction
  13. //////////////////////////////////////////////////////////////////////
  14. CMenuEx::CMenuEx():m_szImage(16,15)
  15. {
  16. m_colMenu =::GetSysColor(COLOR_MENU);
  17. m_colText =RGB(0,0,0);
  18. m_colTextSelected =RGB(0,0,255);
  19. //////////////////////////////////////////////////////////////////////
  20. // MODULE   :
  21. // ABSTRACT :
  22. // FUNCTION :
  23. // NOTE     :
  24. // RETURN   :
  25. // ARGUMENTS:
  26. //              I/O           TYPE      NAME       EXPLANATION
  27. //
  28. // CREATE   :  FNST)LiYang  2004-4-14
  29. // UPDATE   :  FNST)WangLin 2004-4-14
  30. //          : Modify reason
  31. //////////////////////////////////////////////////////////////////////
  32. m_bInitial =FALSE;
  33. m_bHasImageLeft =FALSE;
  34. m_nSeparator = 10; //sparator的默认高度
  35. }
  36. CMenuEx::~CMenuEx()
  37. {
  38. m_ImageList.DeleteImageList();
  39. while(!m_ListMenu.IsEmpty())
  40. delete m_ListMenu.RemoveHead();
  41. if(m_bHasImageLeft)
  42. m_bmpImageLeft.DeleteObject();
  43. }
  44. /////////////////////////////////////////////////
  45. //当菜单项为不可用时绘制灰色的文本
  46. void CMenuEx::GrayString(CDC *pDC, const CString &str, const CRect rect)
  47. {
  48. CRect rt(rect);
  49. //int nMode =pDC->SetBkMode(TRANSPARENT);
  50. rt.left +=1;
  51. rt.top +=1;
  52. pDC->SetTextColor(RGB(255,255,255));
  53. pDC->DrawText(str,&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE);
  54. rt.left -=1;
  55. rt.top -=1;
  56. pDC->SetTextColor(RGB(127,127,127));
  57. pDC->DrawText(str,&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE);
  58. //pDC->SetBkMode(nMode);
  59. }
  60. /////////////////////////////////////////////////
  61. //绘制菜单项位图
  62. void CMenuEx::DrawMenuItemImage(CDC *pDC, CRect &rect, BOOL bSelected, BOOL bChecked,
  63. BOOL bGrayed, BOOL bHasImage,LPMENUITEM lpItem)
  64. {
  65. CRect rt(rect.left ,rect.top ,rect.left + m_szImage.cx + 4,
  66. rect.top + m_szImage.cy + 4);
  67. if(bChecked)
  68. {
  69. if(bGrayed)
  70. {
  71. //菜单不可用
  72. GrayString(pDC,"√",rt);
  73. }
  74. else
  75. {
  76. if(bSelected)
  77. {
  78. //菜单选中
  79. //当该项被选中仅多绘制一个立体矩形
  80. pDC->Draw3dRect(&rt,RGB(127,127,255),RGB(200,200,100));
  81. }
  82. rt.InflateRect(-2,-2);
  83. //画出"√"
  84. pDC->SetBkMode(TRANSPARENT);
  85. pDC->SetTextColor(m_colText);
  86. pDC->DrawText("√",&rt,DT_EXPANDTABS|DT_VCENTER|DT_SINGLELINE);
  87. }
  88. rect.left +=m_szImage.cx + 4 +2 ;
  89. return ;
  90. }
  91. if(bHasImage)
  92. {
  93. CPoint pt(rt.left+2 , rt.top+2 );
  94. UINT uStyle =ILD_TRANSPARENT; //CImageList::Draw()绘制位图的风格
  95. if(bGrayed)
  96. {
  97. uStyle |=ILD_BLEND50; //菜单不可用所以位图较暗
  98. }
  99. else
  100. {
  101. if(bSelected)
  102. {
  103. //当该项被选中仅多绘制一个立体矩形
  104. pDC->Draw3dRect(&rt,RGB(255,255,255),RGB(127,127,127));
  105. }
  106. }
  107. m_ImageList.Draw(pDC,lpItem->uIndex,pt,uStyle); //在菜单项中绘制位图
  108. //调整可绘制矩形的大小
  109. //4:位图外接矩形比位图大4
  110. //2:菜单文本与位图外接矩形的间隔为2
  111. rect.left  +=m_szImage.cx + 4 + 2;
  112. }
  113. }
  114. /////////////////////////////////////////////////
  115. //绘制菜单项文本
  116. //参数:rect:立体矩形的RECT
  117. // rtText:菜单文本的RECT
  118. void CMenuEx::TextMenu(CDC *pDC, CRect &rect,CRect rtText,BOOL bSelected, BOOL bGrayed, LPMENUITEM lpItem)
  119. {
  120. //选中状态的菜单项要先画出立体矩形
  121. if(bSelected)
  122. pDC->Draw3dRect(&rect,RGB(127,127,255),RGB(200,200,100));
  123. if(bGrayed)
  124. {
  125. GrayString(pDC,lpItem->strText,rtText);
  126. }
  127. else
  128. {
  129. pDC->DrawText(lpItem->strText,rtText,DT_VCENTER|DT_EXPANDTABS|DT_SINGLELINE);
  130. }
  131. }
  132. void CMenuEx::DrawImageLeft(CDC *pDC, CRect &rect,LPMENUITEM lpItem)
  133. {
  134. if(!m_bHasImageLeft || lpItem->uPositionImageLeft ==-1)
  135. return ;
  136. CDC  memDC;
  137. memDC.CreateCompatibleDC(pDC);
  138. CBitmap *oldBmp =(CBitmap *) memDC.SelectObject(&m_bmpImageLeft);
  139. int cy; //设定该菜单项应从哪画起
  140. if(m_szImageLeft.cy >= lpItem->uPositionImageLeft + rect.Height())
  141. {
  142. cy =(int) m_szImageLeft.cy - lpItem->uPositionImageLeft - rect.Height();
  143. ASSERT(cy>=0);
  144. }
  145. else
  146. cy =0;
  147. pDC->BitBlt(rect.left ,rect.top ,m_szImageLeft.cx ,rect.Height(),&memDC,0,cy,SRCCOPY);
  148. memDC.SelectObject(oldBmp);
  149. memDC.DeleteDC();
  150. rect.left +=m_szImageLeft.cx+1;
  151. }
  152. void CMenuEx::DrawItem(LPDRAWITEMSTRUCT lpDIS)
  153. {
  154. CDC dc;
  155. LPMENUITEM lpItem;
  156. CRect rect(lpDIS->rcItem);
  157. dc.Attach(lpDIS->hDC);
  158. lpItem =(LPMENUITEM)lpDIS->itemData;
  159. if(lpDIS->itemState & ODS_SELECTED)
  160. dc.SetTextColor(m_colTextSelected);
  161. else
  162. dc.SetTextColor(m_colText);
  163. //设定背景色
  164. CBrush brush(m_colMenu);
  165. dc.FillRect(&rect, &brush);
  166. //设定显示模式
  167. dc.SetBkMode(TRANSPARENT);
  168. //绘制侧边位图
  169. DrawImageLeft(&dc,rect,lpItem);
  170. if(lpItem->uID==0)//分隔条
  171. {
  172. rect.top =rect.Height()/2+rect.top ;
  173. rect.bottom =rect.top +2;
  174. rect.left +=2;
  175. rect.right -=2;
  176. dc.Draw3dRect(rect,RGB(64,0,128),RGB(255,255,255));
  177. }
  178. else
  179. {
  180. BOOL bSelected =lpDIS->itemState & ODS_SELECTED;
  181. BOOL bChecked  =lpDIS->itemState & ODS_CHECKED;
  182. BOOL bGrayed   =lpDIS->itemState & ODS_GRAYED;
  183. BOOL bHasImage =(lpItem->uIndex!=-1);
  184. //设定菜单文本的区域
  185. CRect rtText(rect.left+m_szImage.cx+4+2, rect.top,rect.right ,rect.bottom );
  186. rtText.InflateRect(-2,-2);
  187.    
  188. //绘制菜单位图
  189. DrawMenuItemImage(&dc,rect,bSelected,bChecked,bGrayed,bHasImage,lpItem);
  190. //绘制菜单文本
  191. TextMenu(&dc,rect,rtText,bSelected,bGrayed,lpItem);
  192. #ifdef MENUCHAR
  193. //加入当前菜单链表
  194. m_currentListMenu.AddTail(lpItem);
  195. #endif
  196. }
  197. dc.Detach();
  198. }
  199. //////////////////////////////////////////////////////////
  200. //改变菜单风格
  201. //注意第二个参数:FALSE:表示pMenu指向的不是第一级菜单
  202. void CMenuEx::ChangeStyle(CMenu *pMenu,CToolBar *pToolBar,BOOL bIsMainMenu)
  203. {
  204. ASSERT(pMenu);
  205. TRACE("ChangeStylen");//AfxMessageBox("");
  206. LPMENUITEM lpItem;
  207. CMenu *pSubMenu;
  208. int  m,nPosition=0; //该变量用来绘制侧边位图的位置
  209. int          inx;
  210. UINT      idx,x;
  211. for(int i=(int)pMenu->GetMenuItemCount()-1 ;i>=0; i--)
  212. {
  213. lpItem =new MENUITEM;
  214. lpItem->uID =pMenu->GetMenuItemID(i);
  215. if(!bIsMainMenu) //不是第一级菜单
  216. lpItem->uPositionImageLeft =-1;//二级以下菜单不支持侧边位图
  217. else
  218. lpItem->uPositionImageLeft =nPosition;
  219. if(lpItem->uID >0)
  220. {
  221. if(bIsMainMenu)
  222. nPosition +=m_szImage.cy+4;
  223. //保存菜单文本
  224. pMenu->GetMenuString(i,lpItem->strText,MF_BYPOSITION);
  225. #ifdef MENUCHAR
  226. //保存菜单文本中&后的字符
  227. //如果没有则lpItem->uChr为0
  228. int ret=lpItem->strText.Find('&');
  229. lpItem->uChr =0;
  230. if(ret>=0)
  231. lpItem->uChr =lpItem->strText[ret+1];
  232. //字符统一成大小
  233. lpItem->uChr &=~0x20;
  234. #endif
  235. //由工具栏位图中寻找菜单项的位图
  236. //如果没有则uIndex为-1
  237. lpItem->uIndex =-1;
  238. if(pToolBar)
  239. {
  240. for(m=0; m<(pToolBar->GetToolBarCtrl().GetButtonCount()) ;m++)
  241. {
  242. pToolBar->GetButtonInfo(m,idx,x,inx);
  243. if(idx==lpItem->uID)
  244. {
  245. lpItem->uIndex=inx;
  246. break;
  247. }
  248. }
  249. }
  250. //如果该项下还有子菜单,则递归调用该函数来修改其子菜单的风格
  251. pSubMenu =pMenu->GetSubMenu(i);
  252. if(pSubMenu)
  253. ChangeStyle(pSubMenu,pToolBar,TRUE);
  254. }
  255. else
  256. {
  257. if(bIsMainMenu)
  258. nPosition +=m_nSeparator;
  259. }
  260. //修改菜单风格为自绘
  261. pMenu->ModifyMenu(i,MF_BYPOSITION|MF_OWNERDRAW,lpItem->uID,(LPCTSTR)lpItem);
  262. m_ListMenu.AddTail(lpItem);
  263. }
  264. }
  265. //////////////////////////////////////////////////////////
  266. //由工具栏的位图来产生菜单所用的位图列表m_ImageList
  267. int CMenuEx::GetImageFromToolBar(UINT uToolBar, CToolBar *pToolBar,COLORREF crMask/*工具栏位图的掩码*/)
  268. {
  269. if(!pToolBar)
  270. return 0;
  271. CBitmap bmp;
  272. int nWidth,nHeight;
  273. BITMAP bmpInfo;
  274. bmp.LoadBitmap(uToolBar);
  275. bmp.GetBitmap(&bmpInfo);
  276. //得到位图的高度
  277. nHeight =bmpInfo.bmHeight;
  278. int nCount=0;
  279. int ret =pToolBar->GetToolBarCtrl().GetButtonCount();
  280. //得到工具栏中位图的个数nCount
  281. for(int i=0;i<ret;i++)
  282. if(pToolBar->GetItemID(i)!=ID_SEPARATOR)
  283. nCount ++;
  284. //计算出位图的宽度
  285. nWidth =bmpInfo.bmWidth/nCount;
  286. bmp.DeleteObject();
  287. TRACE("Menu Bitmap--width:%dtheight:%dn",nWidth,nHeight);
  288. //创建位图列表
  289. m_ImageList.Create(uToolBar,nWidth,nHeight,crMask);
  290. m_szImage.cx =nWidth;
  291. m_szImage.cy =nHeight;
  292. return nCount;
  293. }
  294. void CMenuEx::InitMenu(CMenu *pMenu, UINT uToolBar, CToolBar *pToolBar)
  295. {
  296. //已设定了风格
  297. if(m_bInitial)
  298. return ;
  299. GetImageFromToolBar(uToolBar,pToolBar);
  300. CMenu *pSubMenu,*pSubsub;
  301. MENUITEM *lpItem;
  302. UINT i;
  303. int j,m;
  304. int  nPosition; //该变量用来绘制侧边位图的位置
  305. for(i=0;i<pMenu->GetMenuItemCount();i++)
  306. {
  307. pSubMenu =pMenu->GetSubMenu(i);
  308. if(pSubMenu)
  309. {
  310. nPosition =0;
  311. //注意j一定要为int类型,如果为UINT是检查不出j>=0!
  312. for(j=(int)pSubMenu->GetMenuItemCount()-1;j>=0;j--)
  313. {
  314. lpItem =new MENUITEM;
  315. lpItem->uID =pSubMenu->GetMenuItemID(j);
  316. lpItem->uPositionImageLeft =nPosition;
  317. if(lpItem->uID>0)
  318. {
  319. nPosition +=m_szImage.cy+4;
  320. pSubMenu->GetMenuString(j,lpItem->strText,MF_BYPOSITION);
  321. #ifdef MENUCHAR
  322. //保存菜单文本中&后的字符
  323. //如果没有则lpItem->uChr为0
  324. int ret =lpItem->strText.Find('&');
  325. lpItem->uChr=0;
  326. if(ret>=0)
  327. lpItem->uChr =lpItem->strText[ret+1];
  328. //统一大小
  329. lpItem->uChr &=~0x20;
  330. #endif
  331. //由工具栏位图中寻找菜单项的位图
  332. //如果没有则uIndex为-1
  333. lpItem->uIndex =-1;
  334. for(m=0; m<(pToolBar->GetToolBarCtrl().GetButtonCount()) ;m++)
  335. {
  336. int inx;
  337. UINT idx,x;
  338. pToolBar->GetButtonInfo(m,idx,x,inx);
  339. if(idx==lpItem->uID)
  340. {
  341. lpItem->uIndex=inx;
  342. break;
  343. }
  344. }
  345. }
  346. else
  347. {
  348. //separator
  349. nPosition +=m_nSeparator;
  350. }
  351. m_ListMenu.AddTail(lpItem);
  352. pSubMenu->ModifyMenu(j,MF_BYPOSITION|MF_OWNERDRAW,
  353. lpItem->uID,LPCTSTR(lpItem));
  354. pSubsub =pSubMenu->GetSubMenu(j);
  355. //只有第一级菜单才由工具栏获得位图!!
  356. if(pSubsub)
  357. ChangeStyle(pSubsub,pToolBar);
  358. }
  359. }
  360. }
  361. m_bInitial =TRUE;
  362. }
  363. void CMenuEx::MeasureItem(LPMEASUREITEMSTRUCT  lpMIS)
  364. {
  365. MENUITEM *lpItem =(LPMENUITEM)lpMIS->itemData;
  366. if(lpItem->uID==0)//分隔条
  367. {
  368. lpMIS->itemHeight =m_nSeparator;
  369. //lpMIS->itemWidth  =50;
  370. }
  371. else
  372. {
  373. CDC  *pDC =AfxGetMainWnd()->GetDC();
  374. CString strText=lpItem->strText;
  375. CSize  size;
  376. size=pDC->GetTextExtent(lpItem->strText);
  377. lpMIS->itemWidth = size.cx +m_szImage.cx+4;
  378. lpMIS->itemHeight =m_szImage.cy+4;
  379. AfxGetMainWnd()->ReleaseDC(pDC);
  380. }
  381. }
  382. void CMenuEx::SetImageLeft(UINT idBmpLeft)
  383. {
  384. m_bmpImageLeft.LoadBitmap(idBmpLeft);
  385. m_bHasImageLeft = TRUE;
  386. BITMAP bmpInfo;
  387. m_bmpImageLeft.GetBitmap(&bmpInfo);
  388. m_szImageLeft.cx =bmpInfo.bmWidth;
  389. m_szImageLeft.cy =bmpInfo.bmHeight;
  390. }
  391. #ifdef MENUCHAR
  392. LRESULT CMenuEx::MenuChar(UINT nChar)
  393. {
  394. nChar &=~0x20;
  395. MENUITEM *lpItem;
  396. for(POSITION pos=m_currentListMenu.GetHeadPosition();pos;)
  397. {
  398. lpItem =(LPMENUITEM)m_currentListMenu.GetNext(pos);
  399. if(lpItem->uChr ==nChar)
  400. {
  401. AfxGetMainWnd()->SendMessage(WM_COMMAND,lpItem->uID);
  402. return 1L;
  403. }
  404. }
  405. return 0L;
  406. }
  407. #endif
  408. void CMenuEx::SetTextColor(COLORREF crColor)
  409. {
  410. m_colText =crColor;
  411. }
  412. void CMenuEx::SetBackColor(COLORREF crColor)
  413. {
  414. m_colMenu =crColor;
  415. }
  416. void CMenuEx::SetHighLightColor(COLORREF crColor)
  417. {
  418. m_colTextSelected =crColor;
  419. }
  420. //////////////////////////////////////////////////////
  421. //修改菜单的风格
  422. //与InitMenu不同的是:InitMenu并不修改第一级菜单为自绘风格,而
  423. //该函数有包括第一级菜单
  424. //但必须注意:该类的任一实例都只能调用这两个函数中的一个,不能一同使用
  425. void CMenuEx::InitPopupMenu(CMenu *pPopupMenu,UINT uToolBar, CToolBar *pToolBar)
  426. {
  427. //已设定了主窗口菜单风格
  428. if(m_bInitial)
  429. return ;
  430. GetImageFromToolBar(uToolBar,pToolBar);
  431. ChangeStyle(pPopupMenu,pToolBar,TRUE);
  432. m_bInitial =TRUE;
  433. }
  434. void CMenuEx::DeleteItem(UINT nID)
  435. {
  436. int n=m_ListMenu.GetCount();
  437. POSITION pos2,pos=m_ListMenu.GetHeadPosition();
  438. MENUITEM* pMenuItem;
  439. for(int i=0;i<n;i++)
  440. {
  441. pos2=pos;
  442. if((pMenuItem=(MENUITEM*)m_ListMenu.GetNext(pos))->uID==nID){
  443.             m_ListMenu.RemoveAt(pos2);
  444. delete pMenuItem;
  445. }
  446. }
  447. }