返回首页


{S0}简介
我是找一个代​​码执行一个所有者,绘制在WTL上下文菜单,但找不到任何,我发现的一切将修改的CCommandBarCtrl的行为,并可能不被显示由一个上下文菜单中使用,让我们也就是说,一个编辑控制。
在这篇文章中,虐待你展示如何实现所有者绘制的上下文菜单,以及如何添加到您的应用程序真正轻松冷静的寻找菜单,使用我的类CCoolContextMenu。实施
为了使项目业主制定项目,你必须创建一个新的菜单项,或者修改现有的设置MFT_OWNERDRAW菜单标志之一。
您可以使用的InsertMenuItem或SetMenuItemInfo功能设置或更改菜单项的信息。调用这两个函数时,你必须指定一个指针到MENUITEMINFO结构,它指定的菜单项的属性。
您需要指定一个项目,FTYPE成员MFT_OWNERDRAW价值,成为所有者绘制的项目。您还可以关联一个应用程序定义的价值,这就是所谓的项目数据,每个菜单项。 CCoolContextMenu类定义MenuItemData的结构,它包含用于绘制菜单项的信息。应用程序使用的dwItemData存储一个指针,这个结构的成员。
MenuItemData结构菜单的所有者窗口发送WM_MEASUREITEM和WM_DRAWITEM消息。 GetMenuItemInfo函数是用来检索在任何time.LRESULT InitMenuPopupHandler菜单项目(UINT uMsg,WPARAM wParam的数据,   ; LPARAM lParam的,BOOLamp; bHandled){ / /系统菜单,什么也不做 ((BOOL)HIWORD(LPARAM))  ; { bHandled = FALSE;  0; 返回1; } CMenuHandle menupopup中=(HMENU)的wParam; ATLASSERT(menu​​Popup.m_hMenu = NULL!); TCHAR szString [MAX_MENU_ITEM_TEXT_LENGTH]; BOOL BRET = FALSE; (I = 0;我LT; menuPopup.GetMenuItemCount();我) {  60; CMenuItemInfo信息产业部; mii.cch = MAX_MENU_ITEM_TEXT_LENGTH; mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE; mii.dwTypeData = szString;  0; BRET = menuPopup.GetMenuItemInfo(我,没错,AMP; MII); ATLASSERT(BRET);  60; ((mii.fType放大器; MFT_OWNERDRAW!)) &# 160;/ /尚未的OwnerDraw项目 {   ; MenuItemData * PMI =新MenuItemData; & #160; ATLASSERT(PMI = NULL); 如果(PMI) &# 160; { / /使这所有者描述的菜单项  0; mii.fType | = MFT_OWNERDRAW; & #160; PMI - GT; FTYPE = mii.fType;   ; PMI - GT; fState = mii.fState; / /关联菜单项的图像 static_castlt,T * GT(本)- GT; AssociateImage(MII,PMI);   ; PMI - GT; lpstrText =新TCHAR [lstrlen(szString)1];  60; ATLASSERT(PMI - GT!lpstrText = NULL);  60; 如果(PMI - GT!lpstrText = NULL) lstrcpy(PMI - GT; lpstrText,szString); &# 160; mii.dwItemData =(ULONG_PTR)PMI; & #160; BRET = menuPopup.SetMenuItemInfo(我,没错,AMP; MII); & #160; ATLASSERT(BRET); } } } / /添加到列表 m_stackMenuHandle.Push(menu​​Popup.m_hMenu); 返回0;}
内部,CCoolContextMenu实现WM_MEASUREITEM,WM_DRAWITEM,WM_INITMENUPOPUP和WM_MENUSELECT消息,所以你不必担心什么。使用代码
要使用CCoolContextMenu类,所有你所要做的的是从CCoolContextMenu派生你的类,并按照以下几个步骤:类CCoolEdit:公共CWindowImpllt; CCoolEdit,CRichEditCtrlgt; &# 160; 公共CRichEditCommandslt; CCoolEditgt; 公共CCoolContextMenult; CCoolEditgt;
在消息映射,使用CHAIN​​_MSG_MAP重定向消息CCoolContextMenu的消息映射:BEGIN_MSG_MAP(CCoolEdit) ... ... CHAIN​​_MSG_MAP(CCoolContextMenult; CCoolEditgt;)END_MSG_MAP()
在OnInitDialog()函数的对话框类,或在OnCreate()函数的窗口类,调用GetSystemSettings()CCoolContextMenu的方法:LRESULT的OnInitDialog(UINT uMsg,WPARAM wParam参数,   ; LPARAM lParam的,BOOLamp; bHandled){ ... ... GetSystemSettings(); ... ...}
别急!什么图像?不要担心,刚刚创建的图像列表和实施AssociateImage(CMenuItemInfoamp;信息产业部,MenuItemData * PMI)在你CCoolContextMenu的函数派生类:无效AssociateImage(CMenuItemInfoamp;信息产业部,MenuItemData * PMI){ 开关(mii.wID) { 案件ID_EDIT_UNDO: PMI - GT; iImage = 17;   ; 打破; 案件ID_EDIT_CUT: & #160;PMI - GT; iImage = 3; 打破; 案件ID_EDIT_COPY: PMI - GT; iImage = 4; 打破; 案件ID_EDIT_PASTE:  0; PMI - GT; iImage = 5; 打破; & #160; 案件ID_EDIT_CLEAR: PMI - GT; iImage = 20; 打破; 默认值: & #160; PMI - GT; iImage = -1; 打破;&# 160; }}结论
CCoolContextMenu让您好看的上下文菜单,只需几行代码添加到您的应用程序;相结合,让 - 米歇尔 - 我的代码,您的Windows看起来完全不同。我要感谢吉恩Michel LE FOL在菜单自定义代码]不要在点阵图年轻的金]Bjarke Vikse和Justin河西回答我的问题上]历史2006年3月13日 - 首次发布。2006年3月15日 - 把在CCoolContextMenu类消息映射。耶尔Sigvardsson建议。2006年4月24日 - 增加了一个默认实现的AssociateImage功能的CCoolContextMenu类。免责声明
本软件和相关的文件分发"原样"和不附带任何明示或暗示的保证。对于可能损害不承担责任可以采取。使用本软件的用户必须承担全部风险。|伊戈尔Vigdorchik

回答

评论会员:游客 时间:2011/12/06
有一个代码行:CBoldDC大胆(*PDC(lpDrawItemStruct-GT;itemState放大器;ODS_DEFAULT)=0!);但它从来没有使用的DrawItem()是否有意义
?约翰后腿
评论会员:游客 时间:2011/12/06
应用bobnob以下建议的修复,还修复rajas指出的问题的IF,你可以添加一个CMainFrame的,它会皮条客主菜单!此外,如果你添加一个任务托盘菜单,它是自动以及pimped!伟大的工作-很多很多的感谢
约翰后腿
评论会员:游客 时间:2011/12/06
测试和适应此代码时,我发现了几件事情:1。该代码假定的MenuItem将始终位于左侧的菜单DC。这种情况并非如此,如果菜单分割成多个列。这是很容易的固定在几个地方使用矩形的左坐标,而不是0。2。,通过WM_UNINITMENUPOPUP清理代码,而比WM_MENUSELECT它可以简化和更强大的(即你的菜单句柄,所以你不再需要在数组中存储这些和它的作品,如果菜单是不选择的情况下被解雇)。3。WM_MEASUREITEM处理程序代码和m_menufont成员NULL的条件,可避免需要设置调用的,所以它得到做一次。4。一个整齐的图标附件自动的方式是简单地存储在单个图标上键入的命令ID的资源(在完全相同的方式,字符串资源用于提供命令状态栏的帮助)
。伊戈尔Vigdorchik: |约翰,

感谢您的意见。我不知道我理解你在3日和4的意思。你能否解释
评论会员:?约翰后腿 时间:2011/12/06
!当然

其实我重构代码,使字体缓存代码是在MeasureItem和m_bFlatMenus标志是在构造函数中设置。不过,你可以简单地做:

如果GetSystemSettings()(m_fontMenu.IsNull())

在MeasureItem开始。这样就避免了代码的用户需要显式调用GetSystemSettings。

InitMenuPopupHandler,我把下面的代码行:

PMI ->的hIcon =(HICON)的LoadImage(_Module.GetResourceInstance(),MAKEINTRESOURCE(mii.wID),IMAGE_ICON,16,16,LR_DEFAULTCOLOR);

HICON取代MenuItemData结构的iImage和DrawItem简化为直接得出这样的图标(除非它是空的,这将是如果资源是缺席)。图标删除,再次在我的WM_UNINITMENUPOPUP处理程序。添加一个图标,你需要做的的就是把资源之一,并给它的菜单项相同的ID(方便,您可以使用相同的符号常量)。这遵循相同的模式,ATL / WTL / MFC的使用与菜单项关联的字符串表中的帮助字符串。

我也重构了代码,所以它是自成体系,并纳入侧边栏的能力基于
评论会员:。伊戈尔Vigdorchik 时间:2011/12/06
感谢了很多,约翰
评论会员:。约翰后腿 时间:2011/12/06
// JHCCMenu.h - implementation of the CCMenu class

// ===============================================

// Add-in template to pimp and add features to menus. May be added to CFrameWindowImpl

// class or any CWindowImpl class with a context menu. In former case, pimps main menu

// and any task-bar menu; in the latter, any context menus. Two steps are needed to use:

// 1-Add this template to the inheritance list of the class which implements the menus;

// 2-Add CHAIN_MSG_MAP(CCMenu<xxx>) to the class message map.

//

// Menus created from resources are converted automatically. Items with id = 0

// and MF_DISABLED are rendered as headings - horizontal unless the NEXT item

// has MF_MENUBARBREAK in which case a vertical sidebar. Icons from resources are

// used if they have a numeric id which matches the command id (similar to the way

// help string resources are matched to menu items).

//

// Menus created programatically have more flexibility. Use AppendCCMenu which takes

// the same parameters as AppendMenu but adds hIcon and uExtras parameters. You can

// specify the icon (or NULL). Extras flags are MFT_EX_HTITLE (= 1); MFT_EX_VTITLE

// (= 2) and MFT_EX_KEEP (= 4). The first two specify horizontal and vertical

// titles, the last prevents automatic clean-up when the menu closes. Use MFT_EX_KEEP

// if you create the menu once and then re-use it; you must then call DestroyCCMenu

// for each menu created (must be called for sub-menus too). If you create the menu

// anew each time in the WM_INITMENUPOPUP handler, leave this flag out and cleanup

// will be automatic (including destroying the icon if any).

//

// References:

// http://www.codeproject.com/KB/wtl/WTLOwnerDrawCtxtMenu.aspx

// http://www.codeproject.com/KB/wtl/sidebarmenu.aspx

// http://dvinogradov.blogspot.com/2007_01_01_archive.html

/////////////////////////////////////////////////////////////////////////////

 

#pragma once

 

#include "stdafx.h"

 

#define MAX_MENU_ITEM_TEXT_LENGTH       (100)

#define IMGPADDING                      (6)

#define TEXTPADDING                     (8)

 

#define SIDEBAR_FONT					(_T("TREBUCHET"))

#define TITLE_BG						(::GetSysColor(COLOR_HIGHLIGHT))

#define TITLE_TX						(::GetSysColor(COLOR_HIGHLIGHTTEXT))

#define MENU_BG							(HLS_TRANSFORM(::GetSysColor(COLOR_3DFACE), -4, 60))

#define ICON_BG							(HLS_TRANSFORM(::GetSysColor(COLOR_3DFACE), +20, 60))

#define MENU_TX							(::GetSysColor(COLOR_MENUTEXT))

#define MENU_DT							(::GetSysColor(COLOR_GRAYTEXT))

#define SELECT_BG						(HLS_TRANSFORM(::GetSysColor(COLOR_HIGHLIGHT), +70, -57))

#define SELECT_BR						(::GetSysColor(COLOR_HIGHLIGHT))

#define SEPARATOR_PN					(::GetSysColor(COLOR_HIGHLIGHT))

 

#ifndef OBM_CHECK

#define OBM_CHECK                       32760

#endif

 

#ifndef SPI_GETFLATMENU

	const UINT SPI_GETFLATMENU = 0x1022;

#endif

 

// Bit flags for "fExtra":

#define MFT_EX_HTITLE					(0x00000001L)

#define MFT_EX_VTITLE					(0x00000002L)

#define MFT_EX_KEEP						(0x00000004L)

 

template <class T>

class CCMenu

{

private:

    int m_cxExtraSpacing;

    COLORREF m_clrMask;

    SIZE m_szBitmap;

    SIZE m_szButton;

    CFont m_fontMenu;

    bool m_bFlatMenus;

	UINT m_itemHeight;

	bool m_bEnabled;

 

protected:

	struct MenuItemData	

	{

		LPTSTR lpstrText;

		UINT fType;

		UINT fState;

		UINT fExtra;

        HICON hIcon;

	};

 

	// Transforms an RGB colour by increasing or reducing its luminance and/or saturation in HLS space.

	COLORREF HLS_TRANSFORM(COLORREF rgb, int percent_L, int percent_S)

	{

		WORD h, l, s;

		ColorRGBToHLS(rgb, &h, &l, &s);

		if ( percent_L > 0 )

		{

			l = WORD(l + ((240 - l) * percent_L) / 100);

		}

		else if ( percent_L < 0 )

		{

			l = WORD((l * (100 + percent_L)) / 100);

		}

		if ( percent_S > 0 )

		{

			s = WORD(s + ((240 - s) * percent_S) / 100);

		}

		else if ( percent_S < 0 )

		{

			s = WORD((s * (100 + percent_S)) / 100);

		}

		if (l > 240) l = 240; if (l < 0) l = 0;

		if (s > 240) s = 240; if (s < 0) s = 0;

		return ColorHLSToRGB(h, l, s);

	}

 

	// Handles the WM_MEASUREITEM message.

	void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)

	{

		MenuItemData* pmd = (MenuItemData*)lpMeasureItemStruct->itemData;

 

		if (m_fontMenu.IsNull())

		{	// First time only, cache the font and some drawing metrics

			NONCLIENTMETRICS info = { sizeof(NONCLIENTMETRICS), 0 };

			#if (WINVER >= 0x0600)

			OSVERSIONINFO osvi = { sizeof(OSVERSIONINFO), 0 };

			GetVersionEx(&osvi);

			if (osvi.dwMajorVersion < 6) info.cbSize -= sizeof(int);

			#endif

			::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, info.cbSize, &info, 0);

			HFONT hFontMenu = ::CreateFontIndirect(&info.lfMenuFont);

			ATLASSERT(hFontMenu != NULL);

			m_fontMenu.Attach(hFontMenu);

			CWindowDC dc(NULL);

			HFONT hFontOld = dc.SelectFont(m_fontMenu);

			RECT rcText = { 0, 0, 0, 0 };

			dc.DrawText(_T("\t"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);

			if ((rcText.right - rcText.left) < 4)

			{

				::SetRectEmpty(&rcText);

				dc.DrawText(_T("x"), -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);

				m_cxExtraSpacing = rcText.right - rcText.left;

			}

			else

			{

				m_cxExtraSpacing = 0;

			}

			m_itemHeight = abs(info.lfMenuFont.lfHeight) + 10;

			dc.SelectFont(hFontOld);

		}

 

		if (pmd->fType & MFT_SEPARATOR)

		{   // separator - use quarter system height and leave width for system to calculate

			lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU) / 4;

			lpMeasureItemStruct->itemWidth  = 0;

		}

		else if (pmd->fExtra & MFT_EX_VTITLE)

		{	// Sidebar - set width to height of normal item and leave height for system to calculate

			lpMeasureItemStruct->itemWidth = ::GetSystemMetrics(SM_CYMENU) - (::GetSystemMetrics(SM_CXMENUCHECK) - 1);

			lpMeasureItemStruct->itemHeight  = 0;

		}

		else

		{	// Compute size of text - use DrawText with DT_CALCRECT

			CWindowDC dc(NULL);

			CFont fontBold;

			HFONT hOldFont = NULL;

			if ((pmd->fState & MFS_DEFAULT) || (pmd->fExtra & MFT_EX_HTITLE))

			{	// Need bold version of font

				LOGFONT lf = { 0 };

				m_fontMenu.GetLogFont(lf);

				lf.lfWeight += 200;

				fontBold.CreateFontIndirect(&lf);

				ATLASSERT(fontBold.m_hFont != NULL);

				hOldFont = dc.SelectFont(fontBold);

                fontBold.DeleteObject();

			}

			else

			{	// Standard font

				hOldFont = dc.SelectFont(m_fontMenu);

			}

			RECT rcText = { 0, 0, 0, 0 };

			dc.DrawText(pmd->lpstrText, -1, &rcText, DT_SINGLELINE | DT_LEFT | DT_VCENTER | DT_CALCRECT);

            int cx = rcText.right - rcText.left;

			dc.SelectFont(hOldFont);

			cx += 4;                    // L/R margin for readability

			cx += 1;                    // space between button and menu text

			cx += 2 * m_szButton.cx;    // button width

			cx += m_cxExtraSpacing;     // extra between item text and accelerator keys

			cx -= ::GetSystemMetrics(SM_CXMENUCHECK) - 1;

			lpMeasureItemStruct->itemWidth = cx;

			lpMeasureItemStruct->itemHeight = m_itemHeight;

		}

	}

 

	// Draw the icon in greyscale within the given rectangle in the device context.

	void DrawDisabledIcon(HDC DC, CRect& Rect, HICON Icon)

	{

		WTL::CDC MemDC(CreateCompatibleDC(DC));

		BITMAPINFO bmi;

		ZeroMemory(&bmi, sizeof(BITMAPINFO));

		bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);

		bmi.bmiHeader.biWidth = Rect.Width();

		bmi.bmiHeader.biHeight = Rect.Height();

		bmi.bmiHeader.biPlanes = 1;

		bmi.bmiHeader.biBitCount = 32;

		bmi.bmiHeader.biCompression = BI_RGB;

		bmi.bmiHeader.biSizeImage = bmi.bmiHeader.biWidth * bmi.bmiHeader.biHeight * 4;

		VOID *pvBits;

		WTL::CBitmap Bitmap(::CreateDIBSection(MemDC, &bmi, DIB_RGB_COLORS, &pvBits, NULL, 0));

		WTL::CBitmapHandle PrevBitmap(MemDC.SelectBitmap(Bitmap));

		MemDC.DrawIconEx(0, 0, Icon, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight);

		for (unsigned char *p = (unsigned char*)pvBits, *end = p + bmi.bmiHeader.biSizeImage; p < end; p += 4)

		{	// Gray = 0.3*R + 0.59*G + 0.11*B

			p[0] = p[1] = p[2] = (static_cast<unsigned int>(p[2]) *  77 + static_cast<unsigned int>(p[1]) * 151 +

				static_cast<unsigned int>(p[0]) *  28) >> 8;

		}

		BLENDFUNCTION BlendFunction;

		BlendFunction.BlendOp = AC_SRC_OVER;

		BlendFunction.BlendFlags = 0;

		BlendFunction.SourceConstantAlpha = 0x60;  // half transparent

		BlendFunction.AlphaFormat = AC_SRC_ALPHA;  // use bitmap alpha

		AlphaBlend(DC, Rect.left, Rect.top, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight,

			MemDC, 0, 0, bmi.bmiHeader.biWidth, bmi.bmiHeader.biHeight, BlendFunction);

		MemDC.SelectBitmap(PrevBitmap);

	}

 

	// Draw a vertical (sidebar) title item.

	void DrawVTitle(LPDRAWITEMSTRUCT lpDrawItemStruct)

	{

		MenuItemData* pmd = (MenuItemData*)lpDrawItemStruct->itemData;

		CDCHandle dc = lpDrawItemStruct->hDC;

        CRect rc(lpDrawItemStruct->rcItem);

        CString sCaption = pmd->lpstrText;

		RECT rct; dc.GetClipBox(&rct);

		rc.bottom = rct.bottom - rct.top;

        dc.FillSolidRect(rc, TITLE_BG);

		rc.DeflateRect(2,2);

		HFONT hFont = CreateFont(rc.right - rc.left, 0, 900, 900, FW_BOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET,

			OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, PROOF_QUALITY, DEFAULT_PITCH | FF_DONTCARE, SIDEBAR_FONT);

		rc.InflateRect(2,2);

		int oldbkm = dc.SetBkMode(TRANSPARENT);

		COLORREF oldcolor = dc.SetTextColor(TITLE_TX);

		HFONT fontold = dc.SelectFont(hFont);

		dc.DrawText(sCaption, sCaption.GetLength(), rc, DT_SINGLELINE|DT_LEFT|DT_BOTTOM);

		dc.SelectFont(fontold);

		dc.SetTextColor(oldcolor);

		dc.SetBkMode(oldbkm);

	}

 

	// Draw a horizontal title item.

	void DrawHTitle(LPDRAWITEMSTRUCT lpDrawItemStruct)

	{

		MenuItemData* pmd = (MenuItemData*)lpDrawItemStruct->itemData;

		CDCHandle dc = lpDrawItemStruct->hDC;

        CRect rc(lpDrawItemStruct->rcItem);

		CRect rcx(rc);

        rcx.right = rc.left + m_szBitmap.cx + IMGPADDING;

        dc.FillSolidRect(rcx, ICON_BG);

        rcx.left = rcx.right;

        rcx.right = rc.right;

        dc.FillSolidRect(rcx, TITLE_BG);

		dc.SetTextColor(TITLE_TX);

		dc.SetBkMode(TRANSPARENT);

        CString sCaption = pmd->lpstrText;

		HFONT m_hDefFont = NULL;

		LOGFONT lf;

		CFont m_fontBold;

		dc.GetCurrentFont().GetLogFont(&lf);

		lf.lfWeight = FW_BOLD;

		m_fontBold.CreateFontIndirect(&lf);

		m_hDefFont = dc.SelectFont(m_fontBold);

        dc.DrawText(sCaption, sCaption.GetLength(), rcx, DT_SINGLELINE|DT_VCENTER|DT_CENTER);

		dc.SelectFont(m_hDefFont);

	}

 

	// Draw a horizontal separator bar.

	void DrawSeparator(LPDRAWITEMSTRUCT lpDrawItemStruct)

	{

		MenuItemData* pmd = (MenuItemData*)lpDrawItemStruct->itemData;

		CDCHandle dc = lpDrawItemStruct->hDC;

		CRect rc(lpDrawItemStruct->rcItem);

		CRect rcx(rc);

        rcx.right = rc.left + m_szBitmap.cx + IMGPADDING;

        dc.FillSolidRect(rcx, ICON_BG);

        rcx.left = rcx.right;

        rcx.right = rc.right;

        dc.FillSolidRect(rcx, MENU_BG);

		rcx.top += (rc.bottom - rc.top) / 2;

		rcx.left += 2; rcx.right -= 2;

		CPen newpen;

		HPEN oldpen;

		newpen.CreatePen(PS_SOLID, 1, SEPARATOR_PN);

		oldpen = dc.SelectPen(newpen);

		dc.MoveTo(CPoint(rcx.left, rcx.top));

		dc.LineTo(CPoint(rcx.right, rcx.top));

		dc.SelectPen(oldpen);

	}

 

	// Draw a normal menu item.

	void DrawActiveItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

	{

		MenuItemData* pmd = (MenuItemData*)lpDrawItemStruct->itemData;

		CDCHandle dc = lpDrawItemStruct->hDC;

		CRect rc(lpDrawItemStruct->rcItem);

		BOOL bDisabled = lpDrawItemStruct->itemState & ODS_GRAYED;

 		BOOL bChecked = lpDrawItemStruct->itemState & ODS_CHECKED;

		BOOL bSelected = lpDrawItemStruct->itemState & ODS_SELECTED;

		BOOL bDefault = pmd->fState & MFS_DEFAULT;

 

        if (bSelected && !bDisabled)

        {	// Draw the selected item background

			HPEN oldpen;

			CPen newpen;

			newpen.CreatePen(PS_SOLID, 1, SELECT_BR);

			oldpen = dc.SelectPen(newpen);

			HBRUSH oldbrush;

			CBrush newbrush;

			newbrush.CreateSolidBrush(SELECT_BG);

			oldbrush = (HBRUSH)::SelectObject(dc, newbrush);

            dc.Rectangle(rc);

			dc.SelectBrush(oldbrush);

			dc.SelectPen(oldpen);

        }

        else

        {   // Draw the unselected item background

            CRect rcx(rc);

            rcx.right = rc.left + m_szBitmap.cx + IMGPADDING;

            dc.FillSolidRect(rcx, ICON_BG);

            rcx.left = rcx.right;

            rcx.right = rc.right;

            dc.FillSolidRect(rcx, MENU_BG);

        }

 

        // Draw the text

        CRect rcx(rc);

        CString sCaption = pmd->lpstrText;

        int nTab = sCaption.Find('\t');

        if (nTab >= 0) sCaption = sCaption.Left (nTab);

		dc.SetTextColor(bDisabled ? MENU_DT : MENU_TX);

		dc.SetBkMode(TRANSPARENT);

		HFONT m_hDefFont = NULL;

		if (bDefault)

		{	// If the item is default, use a bold font

			LOGFONT lf;

			CFont m_fontBold;

			CFontHandle ((HFONT)::GetCurrentObject (dc, OBJ_FONT)).GetLogFont (&lf);

			lf.lfWeight = FW_BOLD;

			m_fontBold.CreateFontIndirect (&lf);

			m_hDefFont = (HFONT)::SelectObject(dc, m_fontBold);

		}

        rcx.left += m_szBitmap.cx + IMGPADDING + TEXTPADDING;

        dc.DrawText(sCaption, sCaption.GetLength(), rcx, DT_SINGLELINE|DT_VCENTER|DT_LEFT);

        if (nTab >= 0)

        {    

            rcx.right -= TEXTPADDING + 4;

            dc.DrawText(pmd->lpstrText + nTab + 1, _tcslen(pmd->lpstrText + nTab + 1), rcx, DT_SINGLELINE|DT_VCENTER|DT_RIGHT);

        }

		if (m_hDefFont != NULL) dc.SelectFont(m_hDefFont);

 

		if (bChecked)

        {	// Draw the check mark:

			HPEN oldpen;

			CPen newpen;

			newpen.CreatePen(PS_SOLID, 1, SELECT_BR);

			oldpen = dc.SelectPen(newpen);

			HBRUSH oldbrush;

			CBrush newbrush;

			newbrush.CreateSolidBrush(bDisabled ? ICON_BG : (bSelected ? SELECT_BG : ICON_BG));

			oldbrush = (HBRUSH)::SelectObject(dc, newbrush);

            dc.Rectangle(CRect(rc.left + 1, rc.top + 1, rc.left + m_szButton.cx - 2, rc.bottom - 1));

			dc.SelectBrush(oldbrush);

			dc.SelectPen(oldpen);

			CRect rcx(rc);

            rcx.left  = rc.left + 2;

            rcx.right = rc.left + m_szBitmap.cx + IMGPADDING;

            dc.SetBkColor(bSelected? SELECT_BG : ICON_BG);

			rcx.top += 3; rcx.left += 2;

            HBITMAP hBmp = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CHECK));

            BOOL bRet = dc.DrawState(rcx.TopLeft(), rcx.Size(), hBmp, DSS_NORMAL, (HBRUSH)NULL);

            DeleteObject(hBmp);

        }

        else if (pmd->hIcon != NULL)

        {	// Draw the icon:

            if (bDisabled)

			{

				DrawDisabledIcon(dc, CRect(rc.left + 3, rc.top + 4, rc.left + 3 + m_szBitmap.cx, rc.top + 4 + m_szBitmap.cx), pmd->hIcon);

			}

			else

            {

				dc.DrawIconEx(CPoint(rc.left + 3, rc.top + 4), pmd->hIcon, CSize(m_szBitmap.cx, m_szBitmap.cx));

            }

        }

	}

 

	// Determine which type of item is to be drawn.

    void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)

	{

		MenuItemData* pmd = (MenuItemData*)lpDrawItemStruct->itemData;

        if (pmd->fType & MFT_SEPARATOR)

        {

			DrawSeparator(lpDrawItemStruct);

		}

		else if (pmd->fExtra & MFT_EX_VTITLE)

		{

			DrawVTitle(lpDrawItemStruct);

		}

		else if (pmd->fExtra & MFT_EX_HTITLE)

		{

			DrawHTitle(lpDrawItemStruct);

		}

		else

		{

			DrawActiveItem(lpDrawItemStruct);

		}

    }

 

	// Handle WM_INITMENUPOPUP by automatically converting non OWNERDRAW items.

    LRESULT InitMenuPopupHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

    {        

		if ((BOOL)HIWORD(lParam))

		{	// System menu, do nothing

			bHandled = FALSE;

			return 1;

		}

		CMenuHandle menuPopup = (HMENU)wParam;

		ATLASSERT(menuPopup.m_hMenu != NULL);

        TCHAR szString[MAX_MENU_ITEM_TEXT_LENGTH];

		MenuItemData* pMIlast = NULL;

        for (int i = 0; i < menuPopup.GetMenuItemCount(); i++)

        {	// Process every menuitem in menu

            CMenuItemInfo mii;

            mii.cch = MAX_MENU_ITEM_TEXT_LENGTH;

            mii.fMask = MIIM_CHECKMARKS | MIIM_DATA | MIIM_ID | MIIM_STATE | MIIM_SUBMENU | MIIM_TYPE;

            mii.dwTypeData = szString;

			menuPopup.GetMenuItemInfo(i, TRUE, &mii);

            if (!(mii.fType & MFT_OWNERDRAW))

            {   // Not already an ownerdraw item

                MenuItemData* pMI = new MenuItemData;

                ATLASSERT(pMI != NULL);

 				pMI->fExtra = 0;

				pMI->hIcon = NULL;

				pMI->fType = mii.fType;

				pMI->fState = mii.fState;

				if (pMIlast)

				{	// If last item was a title and this has MENUBARBREAK, last should be vertical

					if (pMI->fType & MFT_MENUBARBREAK) pMIlast->fExtra = MFT_EX_VTITLE;

					pMIlast = NULL;

				}

				if ((mii.wID == 0) && (mii.fState & MF_DISABLED))

				{	// If ID is zero and it's disabled, it is a title, establish if vertical next item

					pMIlast = pMI;

					pMI->fExtra = MFT_EX_HTITLE;

				}

				pMI->lpstrText = new TCHAR[lstrlen(szString) + 1];

                ATLASSERT(pMI->lpstrText != NULL);

				lstrcpy(pMI->lpstrText, szString);

                mii.dwItemData = (ULONG_PTR)pMI;

                mii.fType |= MFT_OWNERDRAW;

				pMI->hIcon = (HICON)LoadImage(_Module.GetResourceInstance(), MAKEINTRESOURCE(mii.wID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);

				menuPopup.SetMenuItemInfo(i, TRUE, &mii);

             }

        }

        return 0;

    }

 

	// For WM_MEASUREITEM check it is an owner-draw menu and if so handle it.

	LRESULT MeasureItemHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

	{

		LPMEASUREITEMSTRUCT lpMeasureItemStruct = (LPMEASUREITEMSTRUCT)lParam;

		MenuItemData* pmd = (MenuItemData*)lpMeasureItemStruct->itemData;

		if (lpMeasureItemStruct->CtlType == ODT_MENU && pmd != NULL)

		{

		    MeasureItem(lpMeasureItemStruct);

		}

		else

		{

			bHandled = FALSE;

		}

		return 1;

	}

 

	// For WM_DRAWITEM check it is an owner-draw menu and if so handle it.

    LRESULT DrawItemHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

    {

        LPDRAWITEMSTRUCT lpDrawItemStruct = (LPDRAWITEMSTRUCT)lParam;

        MenuItemData* pMI = (MenuItemData*)lpDrawItemStruct->itemData;

		if (lpDrawItemStruct->CtlType == ODT_MENU && pMI != NULL)

		{

            DrawItem(lpDrawItemStruct);

		}

		else

		{

			bHandled = FALSE;

		}

        return 1;

    }

 

public:

    CCMenu()

    {

		m_bEnabled = false;

        m_cxExtraSpacing = 0;

        m_clrMask = RGB(192, 192, 192);

        m_szBitmap.cx = 16;

        m_szBitmap.cy = 15;

    	m_szButton.cx = m_szBitmap.cx + 6;

		m_szButton.cy = m_szBitmap.cy + 6;

 

		// Query flat menu mode (Windows XP or later)

		OSVERSIONINFO ovi = { sizeof(OSVERSIONINFO) };

		::GetVersionEx(&ovi);

		if (((ovi.dwMajorVersion == 5) && (ovi.dwMinorVersion >= 1)) || (ovi.dwMajorVersion > 5))

		{

			BOOL bRetVal = FALSE;

			BOOL bRet = ::SystemParametersInfo(SPI_GETFLATMENU, 0, &bRetVal, 0);

			m_bFlatMenus = (bRet && bRetVal);

		}

		// Mark as enabled to process messages

		m_bEnabled = true;

	}

 

     CCMenu()

    {

        if (!m_fontMenu.IsNull()) m_fontMenu.DeleteObject();

    }

 

	// Note: do not forget to put CHAIN_MSG_MAP in your message map.

	BEGIN_MSG_MAP(CCMenu)

        MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)

		MESSAGE_HANDLER(WM_UNINITMENUPOPUP, OnUninitMenuPopup)

        MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)

        MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)

	END_MSG_MAP()

 

	// For programatic menu construction, works as AppendMenu with added optional hIcon and uExtras.

	BOOL AppendCCMenu(HMENU hMenu, UINT uFlags, UINT_PTR uIDNewItem = 0, LPCTSTR lpNewItem = NULL, HICON hIcon = NULL, UINT uExtras = 0)

	{

		if (m_bEnabled)

		{

			MenuItemData* pMI = new MenuItemData;

			pMI->lpstrText = new TCHAR[lstrlen(lpNewItem) + 1];

			ATLASSERT(pMI->lpstrText != NULL);

			if (lpNewItem == NULL)

				pMI->lpstrText[0] = 0;

			else

				lstrcpy(pMI->lpstrText, lpNewItem);

			pMI->fExtra = uExtras;

			pMI->hIcon = hIcon;

			pMI->fType = uFlags & (MF_BITMAP|MF_MENUBARBREAK|MF_MENUBREAK|MF_RIGHTJUSTIFY|MF_SEPARATOR|MF_STRING);

			pMI->fState = uFlags & (MF_CHECKED|MF_DEFAULT|MF_DISABLED|MF_GRAYED|MF_HILITE);

			return ::AppendMenu(hMenu, MF_OWNERDRAW | uFlags, uIDNewItem, (LPCWSTR)pMI);

		}

		else

		{

			return ::AppendMenu(hMenu, uFlags, uIDNewItem, lpNewItem);

		}

	}

 

	// Call this explicitly (defaulting the second parameter) if you use AppendCCmenu with the MFT_EX_KEEP

	// flag when you are done with the menu.

	void DestroyCCMenu(CMenuHandle menu, BOOL always = TRUE)

	{

        ATLASSERT(menu.m_hMenu != NULL);

        for (int i = 0; i < menu.GetMenuItemCount(); i++)

        {

			CMenuItemInfo mii;

            mii.fMask = MIIM_DATA | MIIM_TYPE;

            menu.GetMenuItemInfo(i, TRUE, &mii);

            MenuItemData* pMI = (MenuItemData*)mii.dwItemData;

            if (pMI != NULL)

            {

				if (!always) if (pMI->fExtra & MFT_EX_KEEP) return;

                mii.fMask = MIIM_DATA | MIIM_TYPE | MIIM_STATE;

                mii.fType = pMI->fType;

				mii.fState = pMI->fState;

                mii.dwTypeData = pMI->lpstrText;

                mii.cch = lstrlen(pMI->lpstrText);

                mii.dwItemData = NULL;

                menu.SetMenuItemInfo(i, TRUE, &mii);

				if (pMI->hIcon != NULL) DestroyIcon(pMI->hIcon);

                delete [] pMI->lpstrText;

                delete pMI;

            }

        }

	}

 

    LRESULT OnInitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

    {

		if (!m_bEnabled) {bHandled = FALSE; return 1;}

        return InitMenuPopupHandler(uMsg, wParam, lParam, bHandled);

    }

 

    LRESULT OnUninitMenuPopup(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

    {

		if (!m_bEnabled) {bHandled = FALSE; return 0;}

		HMENU hMenu = (HMENU)wParam;

        CMenuHandle menuPopup = hMenu;

		DestroyCCMenu(menuPopup, FALSE);

		bHandled = FALSE;

		return 1;

    }

 

    LRESULT OnMeasureItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

    {

		if (!m_bEnabled) {bHandled = FALSE; return 0;}

        return MeasureItemHandler(uMsg, wParam, lParam, bHandled);

    }

 

    LRESULT OnDrawItem(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)

    {

		if (!m_bEnabled) {bHandled = FALSE; return 0;}

        return DrawItemHandler(uMsg, wParam, lParam, bHandled);

    }

}

{BR
}
评论会员:rajas 时间:2011/12/06
谢谢你伟大的阶级
我想它,并认为我做的文章说。菜单长大,第一次everthing看起来不错,图像相关的正确和菜单看起来不错。然而,当我第二次调用的菜单,没有得出 - 没有文字,没有图像。菜单窗口开辟了正确的大小和小箭头绘制显示,从这个菜单的弹出菜单,但没有绘制 - 如果我把一个断点的DrawItem代码,它不叫所有。

我做错了
评论会员:伊戈尔Vigdorchik 时间:2011/12/06
以一个示范项目,并做完全相同的方式,将工作
"
评论会员:rajas 时间:2011/12/06
感谢 - 我看到我有什么不同?项目。特别是当它正常工作在另外一个地方ANE没有。

事实证明,你的类需要创建和销毁的菜单每次被调用时,我的。不过,我有另一个类(托盘图标)创建菜单第一次,然后保持它和重用,每次被调用的时间 - 现在有什么后首次绘制。我看你为每个菜单项中删除的数据。我要么在类中,或在其他的变化。我也有共享的ImageList的问题。所以我可能有一个共享图像列表的菜单选项,可以有一个较长的寿命比一个显示在您的类的变化。

谢谢你对一个非常漂亮的类
评论会员:。奥利弗Jennert 时间:2011/12/06
您好伊戈尔,

你提供了一个伟大的阶级,我也很喜欢的模板化设计。
的一件事,我认为是有点混乱的m_Imagelist类被销毁,但不创建。我喜欢的整个应用程序之一的ImageList的想法。
但是,如果我将它附加到多个窗口m_Imagelist,它会被摧毁的第一个窗口或对话框关闭。
因此,我建议使用像LVS_SHAREIMAGELISTS标志使用一个ListView,决定是否被销毁的ImageList。

奥利弗
评论会员:伊戈尔Vigdorchik 时间:2011/12/06
嗨,奥利弗,

感谢您的建议。

伊戈尔
评论会员:。machnotrix 时间:2011/12/06


4天前修改
评论会员:。伊戈尔Vigdorchik 时间:2011/12/06
您需要创建一个图像列表,并落实AssociateImage()函数正确的形象标识。只要按照示例代码,它都在那里。

的问候,
伊戈尔。
评论会员:SeekTruth 时间:2011/12/06
我发现我有呼叫Loadmenu和DestroyMenu每次同时处理WM_RBUTTONDOWN消息,是否有必要吗?
评论会员:伊戈尔Vigdorchik 时间:2011/12/06
是的,这是必要的。
评论会员:VALSalamakha 时间:2011/12/06
伊戈尔,

在右边的按钮,RichEdit控件是不集中,不显示光标。所以菜单项"全选"不能正常工作。

为了解决这个问题,它需要添加fuction SetFocus的()如下所示:

LRESULT OnRButtonUp(UINT / * uMsg * /,WPARAM / * wParam参数* /,LPARAM lParam的布尔/ * bHandled * /)
{
....{ BR}/ /光标的水平和垂直位置
口岸系统PT(GET_X_LPARAM(LPARAM),GET_Y_LPARAM(LPARAM))

/ /将客户坐标到屏幕坐标
ClientToScreen(PT);

 60; SetFocus的();
& #160;
&# 160; .....{ BR}
最好的问候,

VAL Salamakha
&# 160;
评论会员:伊戈尔Vigdorchik 时间:2011/12/06
有趣的,但它为我的作品。
没有其他人抱怨。
评论会员:VALSalamakha 时间:2011/12/06
伊戈尔,

也许我的电脑与CPU的HiPer技术的Intel P4 3.0 GHz的XP版本很早就问题。然而,同样的问题就已经出现在我的旧的英特尔P2的400兆赫与W2K。
评论会员:digitally_urs 时间:2011/12/06
你是男人(Y)的竖起大拇指。它无缝集成{S1},如果你不搞砸了您的ATL和WTL包括顺序为:P


评论会员:PrafullaTekawade 时间:2011/12/06
您好专家,
我参与到为IE工具栏的研究与开发。
,因为我有一个下拉菜单按钮。
我想这个菜单的菜单项被超链接。
单个菜单项可以有更多的比上的每个字poiting
不同的网站。
这些menutems都是业主的。
请告诉我,我怎么上的MenuItems的超链接。
我使用WTL的。
不过,如果有人知道如何在MFC中,让我知道。
我将它移植到WTL的自己!!!!!!!!
预先感谢


评论会员:bobnob 时间:2011/12/06
在InitMenuPopupHandler():

mii.fType后保存设置MFT_OWNERDRAW标志,所以恢复的菜单项,将有一个MFT_OWNERDRAW标志。只需将交换两线解决方案。

(PMI)​​
{
/ /这个菜单项的所有者绘制
mii.fType | = MFT_OWNERDRAW; / / FTYPE = mii.fType;
PMI -> fState = mii.fState;

顺便说一句,为什么不使用HMENU,而不是资源ID?我在运行时构造菜单,而不是从资源。
评论会员:bobnob 时间:2011/12/06
bobnob写道:"顺便说一句,为什么不使用的资源ID,而不是一个HMENU?
我的菜单在运行时构造,从资源。
哦,我犯了一个错误,菜单资源ID没有保存这一类


评论会员:sergytmp 时间:2011/12/06
!您好伊戈尔感谢您分享您的代码

1问题:然后我冷静菜单,在子对话框使用上下文菜单 - 一切OK。但父对话框的主菜单(主应用程序窗口的主菜单),更改它的外观也很酷。首先打开任何主菜单的子菜单是好的,但在第二次公开我看到,没有任何文字或冷却图形菜单 - 唯一的边框和背景

请你能不能给我一些答案吗?
评论会员:伊戈尔Vigdorchik 时间:2011/12/06
您好,
我的课应该只用于上下文菜单中选择"应用程序菜单,请使用