📄 menuext.cpp
字号:
CMenuExtData *pData = NULL;
int i;
for(i = 0; i <= m_MenuList.GetUpperBound(); i++){
if (m_MenuList[i]->nID == nID){
pData = m_MenuList[i];
break;
}
}
if (!pData){
int loc;
CMenuExt *pMenu = FindMenuOption(nID, loc);
ASSERT(pMenu != this);
if (loc >= 0){
return pMenu->FindMenuItem(nID);
}
}
return pData;
}
CMenuExt *CMenuExt::FindMenuOption(int nId,int& nLoc)
{
CMenuExt *pSubMenu,*pGoodMenu;
for(int i=0;i<(int)(GetMenuItemCount());++i)
{
#ifdef _CPPRTTI
pSubMenu = dynamic_cast<CMenuExt *>(GetSubMenu(i));
#else
pSubMenu=(CMenuExt *)GetSubMenu(i);
#endif
if(pSubMenu)
{
pGoodMenu= pSubMenu->FindMenuOption(nId,nLoc); //递归查找,遍历所有的弹出菜单
// 若在下面的某个弹出菜单中找到了,可以直接逐级返回了
if(pGoodMenu) return pGoodMenu;
}
else if(nId == (int)GetMenuItemID(i))
{
nLoc = i; //在弹出菜单中的位置
return this; //返回当前所在的弹出菜单(CMenuExt)
}
}
nLoc = -1; //没有找到
return NULL;
}
CMenuExtData *CMenuExt::FindMenuOption(wchar_t *lpstrText)
{
int i,j;
CMenuExt *psubmenu;
CMenuExtData *pmenulist;
for(i=0;i<(int)(GetMenuItemCount());++i){
#ifdef _CPPRTTI
psubmenu=dynamic_cast<CMenuExt *>(GetSubMenu(i));
#else
psubmenu=(CMenuExt *)GetSubMenu(i);
#endif
if(psubmenu){
pmenulist=psubmenu->FindMenuOption(lpstrText);
if(pmenulist)return(pmenulist);
}
else{
const wchar_t *szWide;//SK: we use const to prevent misuse of this Ptr
for(j=0;j<=m_MenuList.GetUpperBound();++j){
szWide = m_MenuList[j]->GetWideString ();
if(szWide && !wcscmp(lpstrText,szWide))//SK: modified for dynamic allocation
return(m_MenuList[j]);
}
}
}
return(NULL);
}
BOOL CMenuExt::LoadMenu(UINT nID)
{
return CMenuExt::LoadMenu(MAKEINTRESOURCE(nID));
}
BOOL CMenuExt::LoadMenu(LPCTSTR lpszResourceName)
{
if(lpszResourceName == NULL) return FALSE;
// 查找菜单资源
HINSTANCE m_hInst = AfxFindResourceHandle(lpszResourceName,RT_MENU);
HRSRC hRsrc = ::FindResource(m_hInst,lpszResourceName,RT_MENU);
if(hRsrc == NULL) return FALSE;
// 获得菜单资源的大小
DWORD dwSize = SizeofResource(NULL, hRsrc);
// 调入菜单资源
HGLOBAL hGlobal = LoadResource(m_hInst, hRsrc);
if(hGlobal == NULL) return FALSE;
// 创建菜单
if(!CMenu::CreateMenu()) return FALSE;
// 获得菜单模板头,并计算出菜单项列表的偏移量位置
MENUITEMTEMPLATEHEADER *pHeader = (MENUITEMTEMPLATEHEADER*)LockResource(hGlobal);
BYTE* pMenuItemTemplate = (BYTE*)pHeader + (sizeof(MENUITEMTEMPLATEHEADER) + pHeader->offset);
int j=0;
CMenuExtData* pData = NULL;
WORD dwFlags = 0; //菜单项的标志(Flags)
WORD dwID = 0; //菜单项的ID
UINT uFlags;
wchar_t *szCaption = NULL;
int nLen = 0; //菜单文本串长度
CTypedPtrArray<CPtrArray, CMenuExt*> m_Stack; //弹出菜单堆栈
CArray<BOOL,BOOL> m_StackEnd; //弹出菜单堆栈
m_Stack.Add(this);
m_StackEnd.Add(FALSE);
// 下面的循环在不断的处理每个MENUITEMTEMPLATE
do{
memcpy(&dwFlags, pMenuItemTemplate, sizeof(WORD)); //取得mtOption
pMenuItemTemplate += sizeof(WORD);
if(!(dwFlags & MF_POPUP))
{
memcpy(&dwID, pMenuItemTemplate, sizeof(WORD)); //取得mtID
pMenuItemTemplate += sizeof(WORD);
}
else dwID = 0;
uFlags = (UINT)dwFlags;
/* 屏蔽掉MF_END.因为结束标志放在了单独的一个m_StackEnd,
所以没有必要AppendODMenuW一个带有MF_END标志的菜单项.
可以参照下文的:
if(dwFlags & MF_END) m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
*/
if(uFlags & MF_END) uFlags -= MF_END;
// 获得文本串
nLen = 0;
char *ch = (char*)pMenuItemTemplate;
szCaption = new wchar_t[wcslen((wchar_t *)pMenuItemTemplate)+1];
wcscpy(szCaption,(wchar_t *)pMenuItemTemplate);
pMenuItemTemplate = &pMenuItemTemplate[(wcslen((wchar_t *)pMenuItemTemplate)+1) * sizeof(wchar_t)];
if(dwFlags & MF_POPUP) //弹出菜单
{
if(dwFlags & MF_END)
m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
CMenuExt* pSubMenu = new CMenuExt;
pSubMenu->m_unselectcheck = m_unselectcheck;
pSubMenu->m_selectcheck = m_selectcheck;
pSubMenu->checkmaps = checkmaps;
pSubMenu->checkmapsshare = TRUE;
pSubMenu->CreatePopupMenu();
// 添加到堆栈的顶部
m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption,uFlags,(UINT)pSubMenu->m_hMenu,-1);
m_Stack.Add(pSubMenu);
m_StackEnd.Add(FALSE);
}
else //非弹出菜单
{
m_Stack[m_Stack.GetUpperBound()]->AppendODMenuW(szCaption,uFlags,dwID,-1);
// 菜单结束项需要在m_Stack列表中记录下来
if(dwFlags & MF_END) m_StackEnd.SetAt(m_Stack.GetUpperBound(),TRUE);
j = m_Stack.GetUpperBound();
while(j>=0 && m_StackEnd.GetAt(j))
{
m_Stack[m_Stack.GetUpperBound()]->InsertSpaces();
m_Stack.RemoveAt(j);
m_StackEnd.RemoveAt(j);
--j;
}
}
delete[] szCaption;
} while(m_Stack.GetUpperBound() != -1);
for(int i=0;i<(int)GetMenuItemCount();++i)
{
CString str = m_MenuList[i]->GetString();
if(GetSubMenu(i))
{
m_MenuList[i]->nFlags = MF_POPUP|MF_BYPOSITION;
// 弹出菜单记录的是m_hMenu
ModifyMenu(i,MF_POPUP|MF_BYPOSITION,(UINT)GetSubMenu(i)->m_hMenu,str);
}
else
{
m_MenuList[i]->nFlags = MF_STRING|MF_BYPOSITION;
// 普通菜单项记录的是nID
ModifyMenu(i,MF_STRING|MF_BYPOSITION,m_MenuList[i]->nID,str);
}
}
return TRUE;
}
void CMenuExt::InsertSpaces()
{
int i,j,numitems,maxlength;
CString string,newstring;
CSize textSize;
CFont fontMenu;
LOGFONT logfont;
// 获取系统指定的菜单字体信息
ZeroMemory(&logfont,sizeof(LOGFONT));
NONCLIENTMETRICS nm;
nm.cbSize = sizeof(NONCLIENTMETRICS);
SystemParametersInfo(SPI_GETNONCLIENTMETRICS,nm.cbSize,&nm,0);
logfont = nm.lfMenuFont;
fontMenu.CreateFontIndirect (&logfont);
CWnd *pWnd = AfxGetMainWnd();
CDC *pDC = pWnd->GetDC();
CFont *pFont = pDC->SelectObject(&fontMenu);
numitems = GetMenuItemCount();
maxlength = -1;
for(i=0;i<numitems;++i)
{
string = m_MenuList[i]->GetString();
j = string.Find((char)9); //菜单文本中的"\t"
newstring.Empty();
if(j!=-1) newstring = string.Left(j);
else newstring = string;
newstring += _T(" ");
LPCTSTR lpstrText = (LPCTSTR)newstring;
textSize = pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
if(textSize.cx > maxlength) maxlength = textSize.cx;
}
for(i=0;i<numitems;++i)
{
string = m_MenuList[i]->GetString();
j = string.Find((char)9);
if(j != -1)
{
newstring.Empty();
newstring = string.Left(j);
LPCTSTR lpstrText = (LPCTSTR)(newstring);
textSize = pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
while(textSize.cx < maxlength)
{
newstring += _T(' ');
LPCTSTR lpstrText = (LPCTSTR)(newstring);
textSize = pDC->GetTextExtent(lpstrText,_tcslen(lpstrText));
}
newstring += string.Mid(j);
#ifdef UNICODE
m_MenuList[i]->SetWideString(newstring);
#else
m_MenuList[i]->SetAnsiString(newstring);
#endif
}
}
pDC->SelectObject (pFont);
AfxGetMainWnd()->ReleaseDC(pDC);
fontMenu.DeleteObject();
}
void CMenuExt::LoadCheckmarkBitmap(int unselect, int select)
{
if(unselect>0 && select>0){
m_selectcheck=select;
m_unselectcheck=unselect;
if(checkmaps)checkmaps->DeleteImageList();
else checkmaps=new(CImageList);
checkmaps->Create(m_iconX,m_iconY,ILC_MASK,2,1);
BOOL flag1=AddBitmapToImageList(checkmaps,unselect);
BOOL flag2=AddBitmapToImageList(checkmaps,select);
if(!flag1||!flag2){
checkmaps->DeleteImageList();
delete checkmaps;
checkmaps=NULL;
}
}
}
BOOL CMenuExt::GetMenuText(UINT id, CString& string, UINT nFlags/*= MF_BYPOSITION*/)
{
BOOL returnflag=FALSE;
if(MF_BYPOSITION&nFlags){
UINT numMenuItems = m_MenuList.GetUpperBound();
if(id<=numMenuItems){
string=m_MenuList[id]->GetString();
returnflag=TRUE;
}
}
else{
int uiLoc;
CMenuExt* pMenu = FindMenuOption(id,uiLoc);
if(NULL!=pMenu) returnflag = pMenu->GetMenuText(uiLoc,string);
}
return(returnflag);
}
void CMenuExt::DrawRadioDot(CDC *pDC,int x,int y,COLORREF color)
{
CRect rcDot(x,y,x+6,y+6);
CBrush brush;
CPen pen;
brush.CreateSolidBrush(color);
pen.CreatePen(PS_SOLID,0,color);
CBrush *pOldBrush=pDC->SelectObject(&brush);
CPen *pOldPen=pDC->SelectObject(&pen);
pDC->Ellipse(&rcDot);
pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
pen.DeleteObject();
brush.DeleteObject();
}
void CMenuExt::DrawCheckMark(CDC* pDC,int x,int y,COLORREF color)
{
pDC->SetPixel(x,y+2,color);
pDC->SetPixel(x,y+3,color);
pDC->SetPixel(x,y+4,color);
pDC->SetPixel(x+1,y+3,color);
pDC->SetPixel(x+1,y+4,color);
pDC->SetPixel(x+1,y+5,color);
pDC->SetPixel(x+2,y+4,color);
pDC->SetPixel(x+2,y+5,color);
pDC->SetPixel(x+2,y+6,color);
pDC->SetPixel(x+3,y+3,color);
pDC->SetPixel(x+3,y+4,color);
pDC->SetPixel(x+3,y+5,color);
pDC->SetPixel(x+4,y+2,color);
pDC->SetPixel(x+4,y+3,color);
pDC->SetPixel(x+4,y+4,color);
pDC->SetPixel(x+5,y+1,color);
pDC->SetPixel(x+5,y+2,color);
pDC->SetPixel(x+5,y+3,color);
pDC->SetPixel(x+6,y,color);
pDC->SetPixel(x+6,y+1,color);
pDC->SetPixel(x+6,y+2,color);
}
CMenuExtData *CMenuExt::FindMenuList(UINT nID)
{
for(int i=0;i<=m_MenuList.GetUpperBound();++i)
{
if(m_MenuList[i]->nID==nID && !m_MenuList[i]->syncflag)
{
m_MenuList[i]->syncflag=1;
return m_MenuList[i]; //找到的菜单项列表哦!
}
}
return NULL; //当然是没有找到了!
}
void CMenuExt::InitializeMenuList(int value)
{
for(int i=0;i<=m_MenuList.GetUpperBound();++i)
m_MenuList[i]->syncflag = value;
}
void CMenuExt::DeleteMenuList(void)
{
for(int i=0;i<=m_MenuList.GetUpperBound();++i)
{
if(!m_MenuList[i]->syncflag)
{
delete m_MenuList[i];
}
}
}
void CMenuExt::SynchronizeMenu()
{
CTypedPtrArray<CPtrArray, CMenuExtData*> temp;
CMenuExtData *mdata = NULL;
CString string;
UINT submenu,nID = 0,state,j;
InitializeMenuList(0);
for(j=0;j<GetMenuItemCount();++j)
{
mdata = NULL;
state = GetMenuState(j,MF_BYPOSITION);
if(state&MF_POPUP) //弹出菜单
{
submenu = (UINT)GetSubMenu(j)->m_hMenu;
mdata = FindMenuList(submenu);
GetMenuString(j,string,MF_BYPOSITION);
if(!mdata)
mdata=NewODMenu(j,(state&0xFF)|MF_BYPOSITION|MF_POPUP|MF_OWNERDRAW,submenu,string);
else if(string.GetLength()>0)
#ifdef UNICODE
mdata->SetWideString(string);
#else
mdata->SetAnsiString(string);
#endif
}
else if(state&MF_SEPARATOR)
{
mdata=FindMenuList(0);
if(!mdata)
mdata=NewODMenu(j,state|MF_BYPOSITION|MF_SEPARATOR|MF_OWNERDRAW,0,_T(""));
else
ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
}
else
{
nID = GetMenuItemID(j);
mdata = FindMenuList(nID);
GetMenuString(j,string,MF_BYPOSITION);
if(!mdata)
mdata = NewODMenu(j,state|MF_BYPOSITION|MF_OWNERDRAW,nID,string);
else
{
mdata->nFlags = state|MF_BYPOSITION|MF_OWNERDRAW;
if(string.GetLength()>0)
#ifdef UNICODE
mdata->SetWideString(string);
#else
mdata->SetAnsiString(string);
#endif
ModifyMenu(j,mdata->nFlags,nID,(LPCTSTR)mdata);
}
}
if(mdata) temp.Add(mdata);
}
DeleteMenuList();
m_MenuList.RemoveAll();
m_MenuList.Append(temp);
temp.RemoveAll();
}
void CMenuExt::UpdateMenu(CMenu *pmenu)
{
#ifdef _CPPRTTI
CMenuExt *psubmenu = dynamic_cast<CMenuExt *>(pmenu);
#else
CMenuExt *psubmenu = (CMenuExt *)pmenu;
#endif
if(psubmenu)psubmenu->SynchronizeMenu();
}
LRESULT CMenuExt::FindKeyboardShortcut(UINT nChar, UINT nFlags, CMenu *pMenu)
{
CMenuExt *pMenuExt = (CMenuExt *)pMenu;
if(pMenuExt && nFlags&MF_POPUP)
{
CString key(_T('&'),2); //为了Unicode正确
key.SetAt(1,(TCHAR)nChar);
key.MakeLower();
CString MenuText;
int MenuSize = (int)pMenuExt->GetMenuItemCount();
if(MenuSize != pMenuExt->m_MenuList.GetUpperBound()+1)
pMenuExt->SynchronizeMenu(); //同步菜单项
for(int i=0;i<MenuSize;++i)
{
if(pMenuExt->GetMenuText(i,MenuText))
{
MenuText.MakeLower();
if(MenuText.Find(key) >= 0) return MAKELRESULT(i,2);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -