WTL
程序时,菜单基本都是标配,比如菜单栏菜单,右键上下文菜单,按钮菜单等等。但是如何设置菜单的字体,大小,颜色,或者说自绘菜单?WTL
提供的CMenu
类,并不是一个窗口类,它只是封装了一个HMENU
菜单句柄,并不是我们所熟悉的窗口句柄HWND
。所以它不会接收到WM_PAINT
消息。template <bool t_bManaged>
class CMenuT
{
public:
// Data members
HMENU m_hMenu;
// Constructor/destructor/operators
CMenuT(HMENU hMenu = NULL) : m_hMenu(hMenu)
{ }
CMenu
的AppendMenu
方法,也只是调用了Win32
的API ::AppendMenu
函数,关键这个方法参数nFlags
的意义,我们看到有一个样式是MF_OWNERDRAW
.BOOL AppendMenu(UINT nFlags, UINT_PTR nIDNewItem = 0, LPCTSTR lpszNewItem = NULL)
{
ATLASSERT(::IsMenu(m_hMenu));
return ::AppendMenu(m_hMenu, nFlags, nIDNewItem, lpszNewItem);
}
MF_OWNERDRAW
: 指定这个菜单项是自绘的菜单项。在菜单显示之前,拥有菜单的窗口接收到WM_MEASUREITEM
消息查找菜单项的宽和高。而在菜单项更新时,WM_DRAWITEM
消息会被发送大这个窗口的窗口处理函数里,可以通过这个消息绘制菜单项.
以下的样式不能用在一起, 因为MF_STRING
和MF_OWNERDRAW
不能用在一起,所以我们在创建菜单项时单独使用MF_OWNERDRAW
.
MF_BITMAP, MF_STRING, and MF_OWNERDRAW
MF_CHECKED and MF_UNCHECKED
MF_DISABLED, MF_ENABLED, and MF_GRAYED
MF_MENUBARBREAK and MF_MENUBREAK
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(MF_OWNERDRAW,ID_EDIT_COPY,L"Copy-2");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_OWNERDRAW,ID_EDIT_CUT,L"Cut-2");
menu.AppendMenu(MF_OWNERDRAW,ID_EDIT_PASTE,L"Paste-2");
menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON,pt.x,pt.y,m_hWnd,NULL);
WM_MEASUREITEM
消息里我们设置菜单项的宽和高。在WM_DRAWITEM
消息里我们绘制菜单项,比如菜单项背景色,字体,字体颜色,选中颜色等。而这两个消息是属于OWNERDRAW
类型的,在WTL
了提供了一个类COwnerDraw
映射了这两个消息,所以我们只需要继承这个类,并且重载以下两个方法即可:void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
// View.h : interface of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#pragma once
#include
#include
#include
#include
#include
#include
enum
{
kMyStaticId = WM_USER+1,
};
class CView : public CWindowImpl<CView>,public COwnerDraw<CView>
{
public:
DECLARE_WND_CLASS(NULL)
BOOL PreTranslateMessage(MSG* pMsg);
BEGIN_MSG_MAP_EX(CView)
MSG_WM_CREATE(OnCreate)
MESSAGE_HANDLER(WM_PAINT, OnPaint)
COMMAND_ID_HANDLER_EX(ID_EDIT_COPY, OnOperate)
COMMAND_ID_HANDLER_EX(ID_EDIT_CUT, OnOperate)
COMMAND_ID_HANDLER_EX(ID_EDIT_PASTE, OnOperate)
MSG_WM_CONTEXTMENU(OnContextMenu)
COMMAND_HANDLER_EX(kMyStaticId,STN_CLICKED,OnStaticClick)
CHAIN_MSG_MAP_ALT(COwnerDraw<CView>, 0)
REFLECT_NOTIFICATIONS()
END_MSG_MAP()
// Handler prototypes (uncomment arguments if needed):
// LRESULT MessageHandler(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
// LRESULT CommandHandler(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
// LRESULT NotifyHandler(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
int OnCreate(LPCREATESTRUCT lpCreateStruct);
LRESULT OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/);
void UpdateLayout();
void OnContextMenu(HWND hwnd, CPoint point);
void OnStaticClick(UINT uNotifyCode, int nID, HWND wndCtl);
void OnOperate(UINT uNotifyCode, int nID, HWND wndCtl);
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
private:
std::wstring GetControlText(HWND hwnd,wchar_t* buf = NULL);
CFont font_normal_;
CStatic text_logo_;
HICON icon_;
CBrushHandle brush_white_;
CBrushHandle brush_hollow_;
CBrush brush_red_;
public:
};
// View.cpp : implementation of the CView class
//
/////////////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "resource.h"
#include
#include
#include "View.h"
#include
#include
#include
BOOL CView::PreTranslateMessage(MSG* pMsg)
{
return FALSE;
}
LRESULT CView::OnPaint(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
{
CPaintDC dc(m_hWnd);
CMemoryDC mdc(dc,dc.m_ps.rcPaint);
CRect rect_client;
GetClientRect(&rect_client);
mdc.FillSolidRect(rect_client,RGB(255,255,255));
//TODO: Add your drawing code here
return 0;
}
// https://docs.microsoft.com/en-us/windows/win32/menurc/using-menus#setting-fonts-for-menu-item-text-strings
void CView::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
if(lpDrawItemStruct->CtlType == ODT_MENU){
COLORREF crSelText = GetSysColor(COLOR_HIGHLIGHTTEXT);
COLORREF crSelBkgnd = GetSysColor(COLOR_HIGHLIGHT);
COLORREF crText = -1;
COLORREF crBkgnd = -1;
BOOL fSelected = FALSE;
CDCHandle cdc(lpDrawItemStruct->hDC);
auto& rcItem = lpDrawItemStruct->rcItem;
auto wCheckX = GetSystemMetrics(SM_CXMENUCHECK);
CRect rect(rcItem.left,rcItem.top,rcItem.right,rcItem.bottom);
crBkgnd = cdc.GetBkColor();
cdc.FillSolidRect(rect,crBkgnd);
if(lpDrawItemStruct->itemState & ODS_SELECTED){
crText = cdc.SetTextColor(crSelText);
crBkgnd = cdc.SetBkColor(crSelBkgnd);
cdc.FillSolidRect(rect,crSelBkgnd);
fSelected = TRUE;
}
auto text = (LPCTSTR)lpDrawItemStruct->itemData;
cdc.SelectFont(font_normal_);
CSize size;
cdc.GetTextExtent(text,wcslen(text),&size);
rect.left += wCheckX;
rect.top += ((rect.Height()-size.cy)/2);
cdc.DrawText(text,wcslen(text),rect,DT_LEFT);
if (fSelected){
cdc.SetTextColor(crText);
cdc.SetBkColor(crBkgnd);
}
SetMsgHandled(TRUE);
}else{
SetMsgHandled(FALSE);
}
}
void CView::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
{
if(lpMeasureItemStruct->CtlType == ODT_MENU){
auto hdc = GetDC();
CDCHandle cdc(hdc);
cdc.SelectFont(font_normal_);
auto text = (LPCTSTR)lpMeasureItemStruct->itemData;
CSize size;
cdc.GetTextExtent(text,wcslen(text),&size);
lpMeasureItemStruct->itemWidth = size.cx+4;
lpMeasureItemStruct->itemHeight = size.cy+4;
SetMsgHandled(TRUE);
}else{
SetMsgHandled(FALSE);
}
}
void CView::OnContextMenu(HWND hwnd, CPoint pt)
{
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(MF_OWNERDRAW,ID_EDIT_COPY,L"Copy-2");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_OWNERDRAW,ID_EDIT_CUT,L"Cut-2");
menu.AppendMenu(MF_OWNERDRAW,ID_EDIT_PASTE,L"Paste-2");
menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|TPM_LEFTBUTTON,pt.x,pt.y,m_hWnd,NULL);
}
static HFONT GetFont(int pixel,bool bold,const wchar_t* font_name)
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT)); // zero out structure
lf.lfHeight = pixel; // request a 8-pixel-height font
if(bold)
{
lf.lfWeight = FW_BOLD;
}
lstrcpy(lf.lfFaceName, font_name); // request a face name "Arial"
HFONT font = ::CreateFontIndirect(&lf);
return font;
}
void CView::OnOperate(UINT uNotifyCode, int nID, HWND wndCtl)
{
switch(nID)
{
case ID_EDIT_COPY:
{
MessageBox(L"Copy-2");
}
break;
case ID_EDIT_CUT:
MessageBox(L"Cut-2");
break;
case ID_EDIT_PASTE:
MessageBox(L"Paste-2");
break;
}
}
std::wstring CView::GetControlText(HWND hwnd,wchar_t* buf)
{
auto length = ::GetWindowTextLength(hwnd);
bool bufNull = false;
if(!buf){
buf = new wchar_t[length+1]();
bufNull = true;
}
::GetWindowText(hwnd,buf,length+1);
std::wstring str(buf);
if(bufNull)
delete []buf;
return str;
}
static std::wstring GetProductBinDir()
{
static wchar_t szbuf[MAX_PATH];
GetModuleFileName(NULL,szbuf,MAX_PATH);
PathRemoveFileSpec(szbuf);
int length = lstrlen(szbuf);
szbuf[length] = L'\\';
szbuf[length+1] = 0;
return std::wstring(szbuf);
}
int CView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
font_normal_ = ::GetFont(16,false,L"Arial");
// 1.单击icon弹出菜单.
icon_ = AtlLoadIcon(IDR_MAINFRAME);
text_logo_.Create(m_hWnd,0,L"",WS_CHILD|WS_VISIBLE|SS_ICON|SS_NOTIFY,0,kMyStaticId);
text_logo_.SetIcon(icon_);
brush_hollow_ = AtlGetStockBrush(HOLLOW_BRUSH);
brush_white_ = AtlGetStockBrush(WHITE_BRUSH);
brush_red_.CreateSolidBrush(RGB(255,0,0));
UpdateLayout();
return 0;
}
void CView::OnStaticClick(UINT uNotifyCode, int nID, HWND wndCtl)
{
CMenu menu;
menu.CreatePopupMenu();
menu.AppendMenu(MF_STRING,ID_EDIT_COPY,L"Copy");
menu.AppendMenu(MF_STRING,ID_EDIT_CUT,L"Cut");
menu.AppendMenu(MF_STRING,ID_EDIT_PASTE,L"Paste");
CRect rect;
text_logo_.GetWindowRect(&rect);
auto ret = menu.TrackPopupMenu(TPM_LEFTALIGN|TPM_TOPALIGN|
TPM_RETURNCMD|TPM_LEFTBUTTON,rect.left,rect.bottom,m_hWnd,NULL);
switch(ret)
{
case ID_EDIT_COPY:
MessageBox(L"Copy");
break;
case ID_EDIT_CUT:
MessageBox(L"Cut");
break;
case ID_EDIT_PASTE:
MessageBox(L"Paste");
break;
}
}
void CView::UpdateLayout()
{
CRect rect;
GetClientRect(&rect);
CClientDC dc(m_hWnd);
dc.SelectFont(font_normal_);
CSize size_control;
wchar_t* buf = new wchar_t[MAX_PATH]();
CRect rect_control = CRect(CPoint(100,100),CSize(32,32));
text_logo_.MoveWindow(rect_control);
}
图2:
Setting Fonts for Menu-Item Text Strings
Using Menus
AppendMenu function