flatpopupmenu.cpp
来自「《突破Visual C++.NET编程实例五十讲+源文件,初学者学习的好东东!」· C++ 代码 · 共 917 行 · 第 1/2 页
CPP
917 行
//是分隔条?
if((item.m_dwFlags & itemSeparator)!=0)
{
DrawSeparator(hDC,item.m_Top);
return;
}
// 获取菜单项左上角
x=3;
y=item.m_Top;
// 是图标?
if(item.m_IconIndex!=-1)
{
p[0].x=p[1].x=x;
p[0].y=y+16;
p[1].y=p[2].y=item.m_Top;
p[2].x=x+17;
hOldPen=SelectObject(hDC,bSelected ? m_hLightShadowPen : m_hBackPen);
Polyline(hDC,p,3);
p[0].x=p[1].x=x+17;
p[0].y=item.m_Top;
p[1].y=p[2].y=y+16;
p[2].x=x;
SelectObject(hDC,bSelected ? m_hDarkShadowPen : m_hBackPen);
Polyline(hDC,p,3);
SelectObject(hDC,hOldPen);
// 画位图
DrawTransparentBitmap(hDC,item.m_IconIndex*16,x+1,item.m_Top+1);
x+=18;
}
// 绘制/清除选择区域矩形
hOldBrush=SelectObject(hDC,bSelected ? m_hSelectedBrush : m_hBackBrush);
hOldPen=SelectObject(hDC,GetStockObject(NULL_PEN));
Rectangle(hDC,x,item.m_Top,m_Width-2,item.m_Top+18);
SelectObject(hDC,hOldPen);
SelectObject(hDC,hOldBrush);
// 绘制菜单项文本
if((item.m_dwFlags & itemBold)!=0)
{
h=m_BoldFontHeight;
hOldFont=SelectObject(hDC,m_hBoldFont);
}
else
{
h=m_FontHeight;
hOldFont=SelectObject(hDC,m_hFont);
}
SetBkMode(hDC,TRANSPARENT);
if(bSelected)
nColor=colorHighlightText;
else
{
if((item.m_dwFlags & itemGrayed)!=0)
nColor=colorGrayedText;
else
nColor=colorText;
}
rect.left=1+2+18+2;
rect.top=item.m_Top+((17-h)/2);
rect.bottom=rect.top+1000;
rect.right=rect.left+1000;
SetTextColor(hDC,m_Colors[nColor]);
DrawText(hDC,item.m_strName.c_str(),item.m_strName.length(),&rect,DT_LEFT | DT_TOP | DT_NOCLIP);
SelectObject(hDC,hOldFont);
// 绘制指向子菜单的箭头
if(item.m_pPopup)
{
hOldPen=SelectObject(hDC,bSelected ? m_hSelectedTextPen : m_hTextPen);
p[0].x=p[1].x=m_Width-7;
p[0].y=item.m_Top+8;
p[1].y=item.m_Top+9;
for(i=0;i<4;i++)
{
Polyline(hDC,p,2);
p[0].x--;
p[1].x--;
p[0].y--;
p[1].y++;
}
SelectObject(hDC,hOldPen);
}
}
//绘制分隔条
void CFlatPopupMenu::DrawSeparator(HDC hDC,int top)
{
POINT p[2];
HGDIOBJ hOldPen;
p[0].x=0;
p[1].x=m_Width;
p[0].y=p[1].y=top+2;
hOldPen=SelectObject(hDC,m_hBorderPen);
Polyline(hDC,p,2);
SelectObject(hDC,hOldPen);
}
// WM_DESTROY消息处理函数
void CFlatPopupMenu::OnDestroy(HWND hWnd)
{
std::vector<CItem>::const_iterator it;
for(it=m_Items.begin();it!=m_Items.end();it++)
if(it->m_pPopup && it->m_pPopup->m_State!=stateInactive)
DestroyWindow(it->m_pPopup->m_hWnd);
if(m_State==stateTrack)
ReleaseCapture();
m_State=stateInactive;
m_hWnd=NULL;
if(!m_bModal && m_SelectedID && !m_bChild)
PostMessage(m_hWndCommand,WM_COMMAND,m_SelectedID,0);
}
// WM_MOUSEMOVE 消息处理函数
void CFlatPopupMenu::OnMouseMove(HWND hWnd,short x,short y)
{
RECT rect;
HDC hDC;
HWND hPointWnd;
int item,newitem;
POINT p;
TCHAR szClass[100];
CFlatPopupMenu *pClass;
// 获取DC和窗口矩形
GetClientRect(hWnd,&rect);
hDC=GetDC(hWnd);
p.x=x;
p.y=y;
ClientToScreen(hWnd,&p);
if((hPointWnd=WindowFromPoint(p))!=NULL && GetClassName(hPointWnd,szClass,sizeof(szClass)/sizeof(TCHAR)) && !lstrcmp(szClass,"fpmMenuClass"))
{
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hPointWnd,GWL_USERDATA));
if(pClass!=this)
{
ReleaseCapture();
m_State=stateShow;
SetCapture(pClass->m_hWnd);
pClass->m_State=stateTrack;
return;
}
}
// 获取最新选择
newitem=GetItem(x,y,rect);
// 清除以前选择?
if(m_SelectedItem!=-1 && newitem!=m_SelectedItem)
{
KillTimer(m_hWnd,1);
if(m_Items[m_SelectedItem].m_pPopup && m_Items[m_SelectedItem].m_pPopup->m_State!=stateInactive)
DestroyWindow(m_Items[m_SelectedItem].m_pPopup->m_hWnd);
item=m_SelectedItem;
m_SelectedItem=-1;
DrawItem(hWnd,hDC,item,m_Items[item]);
}
// 最新选择
if(newitem!=-1 && m_SelectedItem!=newitem)
{
// 绘制新菜单项
m_SelectedItem=newitem;
DrawItem(hWnd,hDC,m_SelectedItem,m_Items[m_SelectedItem]);
// 若为弹出式菜单
if(m_Items[m_SelectedItem].m_pPopup)
SetTimer(m_hWnd,1,m_PopupDelay,NULL);
}
}
//获取菜单项位置
int CFlatPopupMenu::GetItem(short x,short y,const RECT& rect)
{
int newitem;
std::vector<CItem>::size_type i;
if(x<=2 || y<=2 || x>rect.right || y>rect.bottom)
newitem=-1;
else
{
for(i=0;i<m_Items.size();i++)
if(y>m_Items[i].m_Top && y<m_Items[i].m_Top+m_Items[i].m_Height)
break;
newitem=i==m_Items.size() ? -1 : i;
if(newitem!=-1 && (m_Items[newitem].m_dwFlags & itemNotSelectable)!=0)
newitem=-1;
}
return newitem;
}
void CFlatPopupMenu::ButtonDown(HWND hWnd,short x,short y,const bool bLeft)
{
RECT rect;
GetClientRect(hWnd,&rect);
if(CheckOutsideMenu(hWnd,rect,x,y))
return;
if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_pPopup && m_Items[m_SelectedItem].m_pPopup->m_State==stateInactive)
OnTimer(hWnd,1);
}
// WM_LBUTTONUP消息处理函数
void CFlatPopupMenu::OnLButtonUp(HWND hWnd,short x,short y)
{
RECT rect;
if(m_bWaitLeftButton)
{
m_bWaitLeftButton=false;
return;
}
GetClientRect(hWnd,&rect);
if(CheckOutsideMenu(hWnd,rect,x,y))
return;
if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_ItemID)
SetReturn(m_Items[m_SelectedItem].m_ItemID);
}
// WM_RBUTTONUP消息处理函数
void CFlatPopupMenu::OnRButtonUp(HWND hWnd,short x,short y)
{
RECT rect;
if(m_bWaitRightButton)
{
m_bWaitRightButton=false;
return;
}
GetClientRect(hWnd,&rect);
if(CheckOutsideMenu(hWnd,rect,x,y))
return;
if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_ItemID)
SetReturn(m_Items[m_SelectedItem].m_ItemID);
}
//设置返回值
void CFlatPopupMenu::SetReturn(const UINT id)
{
CFlatPopupMenu *pMenu;
for(pMenu=this;pMenu->m_pPrevious;pMenu=pMenu->m_pPrevious);
pMenu->m_SelectedID=id;
DestroyAll();
}
//检查是否在菜单外
bool CFlatPopupMenu::CheckOutsideMenu(HWND hWnd,const RECT& rect,short x,short y)
{
if(x<=2 || y<=2 || x>rect.right || y>rect.bottom)
{
// 在窗口外单击
m_SelectedItem=-1;
m_SelectedID=0;
DestroyAll();
return true;
}
return false;
}
// WM_ERASEBKGND 消息处理函数
void CFlatPopupMenu::OnEraseBkgnd(HWND hWnd,HDC hDC)
{
RECT rect;
HGDIOBJ hOldBrush,hOldPen;
GetClientRect(hWnd,&rect);
hOldBrush=SelectObject(hDC,m_hBackBrush);
hOldPen=SelectObject(hDC,m_hBorderPen);
Rectangle(hDC,rect.left,rect.top,rect.right,rect.bottom);
SelectObject(hDC,hOldBrush);
SelectObject(hDC,hOldPen);
}
// 赋值
void CFlatPopupMenu::CItem::Assign(const CItem& src)
{
m_dwFlags=src.m_dwFlags;
m_strName=src.m_strName;
m_ItemID=src.m_ItemID;
m_IconIndex=src.m_IconIndex;
m_Top=src.m_Top;
m_Height=src.m_Height;
m_pPopup=src.m_pPopup;
}
//绘制透明位图
void CFlatPopupMenu::DrawTransparentBitmap(HDC hdc,const int xSrcOffset,const int xStart,const int yStart)
{
BITMAP bm;
COLORREF cColor;
HBITMAP bmAndBack,bmAndObject,bmAndMem,bmSave;
HBITMAP bmBackOld,bmObjectOld,bmMemOld,bmSaveOld;
HDC hdcMem,hdcBack,hdcObject,hdcTemp,hdcSave;
POINT ptSize;
hdcTemp=CreateCompatibleDC(hdc);
SelectObject(hdcTemp,m_hBitmap);
GetObject(m_hBitmap,sizeof(BITMAP),(LPSTR)&bm);
ptSize.x=bm.bmWidth;
ptSize.y=bm.bmHeight;
DPtoLP(hdcTemp,&ptSize,1);
hdcBack=CreateCompatibleDC(hdc);
hdcObject=CreateCompatibleDC(hdc);
hdcMem=CreateCompatibleDC(hdc);
hdcSave=CreateCompatibleDC(hdc);
bmAndBack=CreateBitmap(ptSize.x,ptSize.y,1,1,NULL);
bmAndObject=CreateBitmap(ptSize.x,ptSize.y,1,1,NULL);
bmAndMem=CreateCompatibleBitmap(hdc,ptSize.x,ptSize.y);
bmSave=CreateCompatibleBitmap(hdc,ptSize.x,ptSize.y);
bmBackOld=(HBITMAP)SelectObject(hdcBack,bmAndBack);
bmObjectOld=(HBITMAP)SelectObject(hdcObject,bmAndObject);
bmMemOld=(HBITMAP)SelectObject(hdcMem,bmAndMem);
bmSaveOld=(HBITMAP)SelectObject(hdcSave,bmSave);
SetMapMode(hdcTemp,GetMapMode(hdc));
BitBlt(hdcSave,0,0,ptSize.x,ptSize.y,hdcTemp,0,0,SRCCOPY);
cColor=SetBkColor(hdcTemp,m_Colors[colorIconTransparent]);
BitBlt(hdcObject,0,0,ptSize.x,ptSize.y,hdcTemp,0,0,SRCCOPY);
SetBkColor(hdcTemp,cColor);
BitBlt(hdcBack,0,0,ptSize.x,ptSize.y,hdcObject,0,0,NOTSRCCOPY);
BitBlt(hdcMem,xSrcOffset,0,16,15,hdc,xStart,yStart,SRCCOPY);
BitBlt(hdcMem,0,0,ptSize.x,ptSize.y,hdcObject,0,0,SRCAND);
BitBlt(hdcTemp,0,0,ptSize.x,ptSize.y,hdcBack,0,0,SRCAND);
BitBlt(hdcMem,0,0,ptSize.x,ptSize.y,hdcTemp,0,0,SRCPAINT);
BitBlt(hdc,xStart,yStart,16,15,hdcMem,xSrcOffset,0,SRCCOPY);
BitBlt(hdcTemp,0,0,ptSize.x,ptSize.y,hdcSave,0,0,SRCCOPY);
DeleteObject(SelectObject(hdcBack,bmBackOld));
DeleteObject(SelectObject(hdcObject,bmObjectOld));
DeleteObject(SelectObject(hdcMem,bmMemOld));
DeleteObject(SelectObject(hdcSave,bmSaveOld));
DeleteDC(hdcMem);
DeleteDC(hdcBack);
DeleteDC(hdcObject);
DeleteDC(hdcSave);
DeleteDC(hdcTemp);
}
//修改菜单文本
bool CFlatPopupMenu::SetMenuItemText(const UINT itemid,LPCTSTR pszName,const bool bByPosition)
{
CItem *pItem;
if((pItem=GetItem(itemid,bByPosition))==NULL)
return false;
pItem->m_strName=pszName;
return true;
}
//修改菜单标志
bool CFlatPopupMenu::SetMenuItemFlags(const UINT itemid,const DWORD dwFlags,const bool bByPosition)
{
CItem *pItem;
if((pItem=GetItem(itemid,bByPosition))==NULL)
return false;
pItem->m_dwFlags=dwFlags;
return true;
}
//获取菜单项文本
bool CFlatPopupMenu::GetString(const UINT itemid,LPTSTR pszText,const UINT cchText,const bool bByPosition)
{
CItem *pItem;
if((pItem=GetItem(itemid,bByPosition))==NULL)
return false;
if(pItem->m_strName.length()+1>cchText)
return false;
lstrcpy(pszText,pItem->m_strName.c_str());
return true;
}
//修改菜单标志
bool CFlatPopupMenu::SetMenuItemIcon(const UINT itemid,const int icon,const bool bByPosition)
{
CItem *pItem;
if((pItem=GetItem(itemid,bByPosition))==NULL)
return false;
pItem->m_IconIndex=icon;
return true;
}
//查找菜单项
CFlatPopupMenu::CItem *CFlatPopupMenu::GetItem(const UINT itemid,const bool bByPosition)
{
std::vector<CItem>::iterator it;
if(bByPosition)
{
if(itemid>=m_Items.size())
return false;
return &m_Items[itemid];
}
else
{
for(it=m_Items.begin();it!=m_Items.end();it++)
if(it->m_ItemID==itemid)
return &(*it);
return NULL;
}
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?