在现代的Windows应用程序中,用户界面的美观性越来越受到重视。Office XP风格因其简洁、现代的界面设计而受到许多开发者的青睐。本文将介绍如何使用C++和MFC/ATL技术实现具有Office XP风格的自定义菜单栏。
自定义菜单栏通常涉及到重写窗口消息处理函数,以及自定义绘制消息。在Office XP风格中,菜单栏的绘制需要考虑多种状态,如普通、高亮、选中等。此外,还需要处理菜单项的文本和图标的绘制。
实现自定义Office XP风格菜单栏的步骤可以分为以下几个部分:
首先,需要定义一个自定义菜单类,该类继承自MFC或ATL的菜单栏控件类。在这个类中,将重写消息映射和处理函数,以实现自定义绘制。
在自定义菜单类中,需要重写消息映射,以便捕获并处理与菜单绘制相关的消息。这包括父窗口消息、MDI客户窗口消息和消息钩子消息。
自定义绘制函数是实现Office XP风格菜单栏的关键。在这个函数中,将根据菜单项的状态(如高亮、选中等)来绘制菜单项的背景、文本和图标。
在自定义绘制函数中,还需要处理菜单项的文本和图标。这包括根据菜单项的状态选择正确的颜色,以及在需要时绘制图标。
// 自定义菜单类的定义
template <class T, class TBase = CCommandBarCtrlBase, class TWinTraits = CControlWinTraits>
class CCommandBarCtrlImplXP : public CCommandBarCtrlImpl<T, TBase, TWinTraits>
{
public:
DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
// 消息映射和处理函数
typedef CCommandBarCtrlImplXP<T, TBase, TWinTraits> thisClass;
typedef CCommandBarCtrlImpl<T, TBase, TWinTraits> baseClass;
BEGIN_MSG_MAP(CCommandBarCtrlXP)
CHAIN_MSG_MAP(baseClass)
ALT_MSG_MAP(1)
NOTIFY_CODE_HANDLER(NM_CUSTOMDRAW, OnCustomDraw)
CHAIN_MSG_MAP_ALT(baseClass, 1)
ALT_MSG_MAP(2)
CHAIN_MSG_MAP_ALT(baseClass, 2)
ALT_MSG_MAP(3)
CHAIN_MSG_MAP_ALT(baseClass, 3)
END_MSG_MAP()
LRESULT OnCustomDraw(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
{
TCHAR sClass[128];
GetClassName(pnmh->hwndFrom, sClass, 128);
if (_tcscmp(sClass, _T("WTL_CommandBarXP")))
{
return CDRF_DODEFAULT;
}
NMCUSTOMDRAW* pCustomDraw = (NMCUSTOMDRAW*)pnmh;
if (pCustomDraw->dwDrawStage == CDDS_PREPAINT)
{
// Request prepaint notifications for each item
return CDRF_NOTIFYITEMDRAW;
}
if (pCustomDraw->dwDrawStage == CDDS_ITEMPREPAINT)
{
CDCHandle cDC(pCustomDraw->hdc);
CRect rc = pCustomDraw->rc;
TCHAR sBtnText[128];
::SendMessage(pnmh->hwndFrom, TB_GETBUTTONTEXT, pCustomDraw->dwItemSpec, (LPARAM)sBtnText);
if (pCustomDraw->uItemState & CDIS_HOT)
{
COLORREF crHighLight = ::GetSysColor(COLOR_HIGHLIGHT);
CPenDC pen(cDC, crHighLight);
CBrushDC brush(cDC, (pCustomDraw->uItemState & CDIS_SELECTED)? HLS_TRANSFORM(crHighLight, +50, -50) : HLS_TRANSFORM(crHighLight, +70, -57));
cDC.Rectangle(rc);
cDC.SetTextColor((pCustomDraw->uItemState & CDIS_SELECTED)? ::GetSysColor(COLOR_HIGHLIGHTTEXT) : RGB(0, 0, 0));
}
else
{
cDC.FillSolidRect(rc, HLS_TRANSFORM(::GetSysColor(COLOR_3DFACE), +20, 0));
cDC.SetTextColor(::GetSysColor(m_bParentActive ? COLOR_BTNTEXT : COLOR_3DSHADOW));
}
cDC.SetBkMode(TRANSPARENT);
cDC.SelectFont((HFONT)GetStockObject(DEFAULT_GUI_FONT));
cDC.DrawText(sBtnText, _tcslen(sBtnText), rc, DT_CENTER|DT_VCENTER|DT_SINGLELINE);
return CDRF_SKIPDEFAULT;
}
bHandled = FALSE;
return CDRF_DODEFAULT;
}
};