最近公司要求写一个OCX的插件,把那种多文档的整个框架界面全部都分装到插件里面,碰到的第一个问题就是不能正常的加载显示菜单,在网上找了相关的资料都说用按钮来替代菜单,于是本人本着这种思路自定义了一个菜单类,拿来与大家分享一下,封装的不是很到位,后来也懒得改,贴出来让大家看看,相互交流下经验
菜单的样式就是这样,下面说下具体思路
1.创建一个对话框,在对话框上动态的创建菜单
CRect RectMenu(ClineRect.left,ClineRect.top,ClineRect.right,ClineRect.top+120);
m_pMenuDlg = new CDlgMenuCmd;
BOOL bRet = m_pMenuDlg->CreateEx(NULL,NULL,_T(""),WS_CHILD|WS_VISIBLE,RectMenu,this,IDD_DLG_MENUCDM);
if(!bRet)
{
AfxMessageBox(_T("创建失败!"));
}
2.在菜单对话框的Oncreate函数里创建菜单
CRect rect(0,0,lpCreateStruct->cx,lpCreateStruct->cy);
m_Menu.LoadMenu(IDR_KQVIEW_TMPL);//注:IDR_KQVIEW_TMPL是资源里创建的菜单,当然菜单分为下面10个大项,下面添加菜单的代码实际可以通过遍历m_Menu添加,因为懒所以没改了
AddMenu(new CStaticMenu(_T("文件"),&m_Menu,0,IDC_STATIC_MENU0));
AddMenu(new CStaticMenu(_T("编辑"),&m_Menu,1,IDC_STATIC_MENU1));
AddMenu(new CStaticMenu(_T("视图"),&m_Menu,2,IDC_STATIC_MENU2));
AddMenu(new CStaticMenu(_T("格式"),&m_Menu,3,IDC_STATIC_MENU3));
AddMenu(new CStaticMenu(_T("公式"),&m_Menu,4,IDC_STATIC_MENU4));
AddMenu(new CStaticMenu(_T("表页"),&m_Menu,5,IDC_STATIC_MENU5));
AddMenu(new CStaticMenu(_T("数据"),&m_Menu,6,IDC_STATIC_MENU6));
AddMenu(new CStaticMenu(_T("工具"),&m_Menu,7,IDC_STATIC_MENU7));
AddMenu(new CStaticMenu(_T("窗口"),&m_Menu,8,IDC_STATIC_MENU8));
AddMenu(new CStaticMenu(_T("帮助"),&m_Menu,9,IDC_STATIC_MENU9));
添加后创建菜单项
for (std::vector<CStaticMenu *>::iterator item=m_MenuVector.begin(); item != m_MenuVector.end(); item++)
{
CStaticMenu * pMenu = (CStaticMenu *)(*item);
int cx = pMenu->GetTextCx();
//nTotalX += cx;
/*if (nTotalX > lpCreateStruct->cx)
{
nPreLeft = rect.left;
nPreTop = lpCreateStruct->cy;
nTotalX = 0;
MoveWindow(0,0,lpCreateStruct->cx,lpCreateStruct->cy*2);
}*/
MenuRect.SetRect(nPreLeft,nPreTop,nPreLeft+cx,nPreTop + 23);
nPreLeft = nPreLeft+cx;
pMenu->Create(NULL,WS_CHILD|WS_VISIBLE|SS_CENTER|SS_NOTIFY,MenuRect,this,pMenu->m_StaticID);
}
3.下面是CStaticMenu类的具体实现,当然这个类可以做其他的很多用途,熟悉c++的继承写起来当然是很简单的
头文件CStaticMenu.h
class CStaticMenu : public CStatic
{
DECLARE_DYNAMIC(CStaticMenu)
public:
//CStaticMenu();
CStaticMenu(CString strText,CMenu * pMenu,int nMenuIndext,UINT StaticID);
virtual ~CStaticMenu();
protected:
DECLARE_MESSAGE_MAP()
private:
COLORREF m_BgColor;//背景颜色
COLORREF m_DefaultColor;
COLORREF m_TextColor;//文本颜色
CString m_strText;
int m_TextBold;//粗体
CString strFontName;//字体名称
BOOL m_TextUnderLine;//下划线
BOOL m_TextItalic;//斜体
int m_FontSize;//字体大小
UINT m_Format;//绘制位置
BOOL m_bIsMouseEnter;//鼠标进入
BOOL m_bIsLButtomDwon;//左键按下
int m_nMenuIndext;
public:
void SetBgColor(COLORREF BgColor);
void SetTextColor(COLORREF TextColor);
void SetText(CString strText);
void SetFontBold(BOOL bBold);
void SetFontName(const CString& strFont);
void SetFontUnderline(BOOL bSet);
void SetFontItalic(BOOL bSet);
void SetFontSize(int nSize);
void SetFormat(UINT uFormat = DT_CENTER|DT_VCENTER);
void SetDefaultBgColor();
void SetAttrib(COLORREF BgColor,COLORREF TextColor,CString strText,BOOL bBold,CString strFont,BOOL bUnderLine,BOOL bItatc,int nSize);
int GetTextCx();
CMenu * m_pMenu;
UINT m_StaticID;
public:
afx_msg void OnPaint();
afx_msg BOOL OnEraseBkgnd(CDC* pDC);
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnTimer(UINT_PTR nIDEvent);
afx_msg void OnFormCell();//单元格设置
};
CStaticMenu.cpp文件的实现
IMPLEMENT_DYNAMIC(CStaticMenu, CStatic)
//CStaticMenu::CStaticMenu()
//{
// m_BgColor = RGB(173,185,205);
// m_TextColor = RGB(0,0,0);
// m_TextBold = 400;
// strFontName = _T("宋体");
// m_TextUnderLine = FALSE;
// m_TextItalic = FALSE;
// m_FontSize = 14;
// m_strText = _T("");
// m_Format = DT_LEFT |DT_VCENTER;
// m_bIsMouseEnter = FALSE;
// m_bIsLButtomDwon = FALSE;
// m_Menu.LoadMenu(IDR_MENU1);
//}
CStaticMenu::CStaticMenu(CString strText,CMenu * pMenu,int nMenuIndext,UINT StaticID)
{
m_BgColor = RGB(173,185,205);
m_DefaultColor = RGB(173,185,205);
m_TextColor = RGB(0,0,0);
m_TextBold = 400;
strFontName = _T("宋体");
m_TextUnderLine = FALSE;
m_TextItalic = FALSE;
m_FontSize = 14;
m_strText = strText;
m_Format = DT_CENTER |DT_VCENTER;
m_bIsMouseEnter = FALSE;
m_nMenuIndext = nMenuIndext;
m_pMenu = pMenu;
m_StaticID = StaticID;
}
CStaticMenu::~CStaticMenu()
{
}
BEGIN_MESSAGE_MAP(CStaticMenu, CStatic)
ON_WM_PAINT()
ON_WM_ERASEBKGND()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_TIMER()
END_MESSAGE_MAP()
// CStaticMenu 消息处理程序
void CStaticMenu::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CStatic::OnPaint()
CRect rect;
GetClientRect(rect);
CBrush brush(m_BgColor);
dc.FillRect(rect, &brush);
if (!m_strText.IsEmpty())
{
CFont TempFont;
TempFont.CreateFont(m_FontSize,0,0,0,m_TextBold,m_TextItalic,m_TextUnderLine,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,strFontName);
CFont * pOldFont = dc.SelectObject(&TempFont);
dc.SetBkColor(m_BgColor);
int nOldMode = dc.SetBkMode(TRANSPARENT);
dc.SetTextColor(m_TextColor);
dc.DrawText(m_strText,rect,m_Format |DT_SINGLELINE |DT_NOPREFIX );//| DT_SINGLELINE
dc.SetBkMode(nOldMode);
dc.SelectObject(pOldFont);
TempFont.DeleteObject();
}
}
BOOL CStaticMenu::OnEraseBkgnd(CDC* pDC)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
return TRUE;
//return CStatic::OnEraseBkgnd(pDC);
}
void CStaticMenu::SetFormat(UINT uFormat)
{
m_Format = uFormat;
Invalidate();
}
void CStaticMenu::SetBgColor(COLORREF BgColor)
{
m_BgColor = BgColor;
Invalidate();
}
void CStaticMenu::SetTextColor(COLORREF TextColor)
{
m_TextColor = TextColor;
Invalidate();
}
void CStaticMenu::SetText(CString strText)
{
m_strText = strText;
Invalidate();
}
void CStaticMenu::SetFontBold(BOOL bBold)
{
if (bBold == TRUE)
{
m_TextBold = 700;
}
else
{
m_TextBold = 400;
}
Invalidate();
}
void CStaticMenu::SetFontName(const CString& strFont)
{
strFontName = strFont;
Invalidate();
}
void CStaticMenu::SetFontUnderline(BOOL bSet)
{
m_TextUnderLine = bSet;
Invalidate();
}
void CStaticMenu::SetFontItalic(BOOL bSet)
{
m_TextItalic = bSet;
Invalidate();
}
void CStaticMenu::SetFontSize(int nSize)
{
m_FontSize = nSize;
Invalidate();
}
void CStaticMenu::SetAttrib(COLORREF BgColor,COLORREF TextColor,CString strText,BOOL bBold,CString strFont,BOOL bUnderLine,BOOL bItatc,int nSize)
{
m_BgColor = BgColor;
m_TextColor = TextColor;
if (bBold == TRUE)
{
m_TextBold = 700;
}
else
{
m_TextBold = 400;
}
strFontName = strFont;
m_TextUnderLine = bUnderLine;
m_TextItalic = bItatc;
m_FontSize = nSize;
m_strText = strText;
Invalidate();
}
int CStaticMenu::GetTextCx()
{
HDC hdc = ::GetDC(NULL);
CDC *pDC = CDC::FromHandle(hdc);
if(pDC == NULL)
{
return 0;
}
CFont TempFont;
TempFont.CreateFont(m_FontSize,0,0,0,m_TextBold,m_TextItalic,m_TextUnderLine,FALSE,FALSE,FALSE,FALSE,FALSE,FALSE,strFontName);
CFont * pOldFont = pDC->SelectObject(&TempFont);
CSize size = pDC->GetTextExtent(m_strText);
pDC->SelectObject(pOldFont);
::ReleaseDC(NULL,hdc);
return (size.cx+15);
}
void CStaticMenu::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(m_bIsMouseEnter == FALSE)
{
m_bIsMouseEnter = TRUE;
m_BgColor = RGB(255,255,183);
Invalidate();
SetTimer(1,200,NULL);
CRect rect;
GetClientRect(rect);
}
CStatic::OnMouseMove(nFlags, point);
}
void CStaticMenu::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_bIsLButtomDwon = TRUE;
CRect rect;
GetClientRect(rect);
CPoint Menupoint(rect.left,rect.bottom);
ClientToScreen(&Menupoint);//
CMenu* pPopup = m_pMenu->GetSubMenu(m_nMenuIndext);
CWnd * pParentWnd = this->GetParent();
if (pParentWnd != NULL)
{
m_BgColor = RGB(255,255,183);
Invalidate();
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, Menupoint.x, Menupoint.y, pParentWnd); //TPM_NONOTIFY
m_BgColor = RGB(173,185,205);
Invalidate();
}
CStatic::OnLButtonDown(nFlags, point);
}
void CStaticMenu::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (m_bIsMouseEnter)
{
// PostMessage(WM_MOUSEENTER...) or call some function.
CPoint pt;
CRect rect;
GetCursorPos(&pt);
GetWindowRect(rect);
if (!PtInRect(&rect,pt))
{
m_BgColor = RGB(173,185,205);
Invalidate();
KillTimer(1); // kill self.
}
m_bIsMouseEnter = FALSE;
SetTimer(1,200,NULL);
}
CStatic::OnTimer(nIDEvent);
}
void CStaticMenu::SetDefaultBgColor()
{
m_BgColor = m_DefaultColor;
Invalidate();
}
这样整个菜单的实现就可以如上图所示那样,如有什么不懂的地方可以问,当然同时也欢迎支出代码的瑕疵地方,大家相互学习