flatpopupmenu.cpp
来自「《突破Visual C++.NET编程实例五十讲+源文件,初学者学习的好东东!」· C++ 代码 · 共 917 行 · 第 1/2 页
CPP
917 行
#include "stdafx.h"
#include "FlatPopupMenu.h"
// 初始化静态成员
bool CFlatPopupMenu::m_bClassRegistered=false;
// stub window 程序
static LRESULT CALLBACK stubWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
//构造函数
CFlatPopupMenu::CFlatPopupMenu()
{
// 缺省颜色
m_Colors[colorBorder]=GetSysColor(COLOR_MENUTEXT);
m_Colors[colorBackground]=GetSysColor(COLOR_MENU);
m_Colors[colorText]=GetSysColor(COLOR_MENUTEXT);
m_Colors[colorGrayedText]=GetSysColor(COLOR_GRAYTEXT);
m_Colors[colorHighlight]=GetSysColor(COLOR_HIGHLIGHT);
m_Colors[colorHighlightText]=GetSysColor(COLOR_HIGHLIGHTTEXT);
m_Colors[colorIconTransparent]=RGB(255,0,255); // 粉红色
m_Colors[colorLightShadow]=GetSysColor(COLOR_3DHILIGHT);
m_Colors[colorDarkShadow]=GetSysColor(COLOR_3DSHADOW);
// 缺省字体及大小
m_strFont="楷体_GB2312";//MS Sans Serif
m_FontSize=10;
// 弹出式子菜单延迟时间缺省为400ms
m_PopupDelay=400;
// 设置GDI对象
m_hFont=NULL;
m_hBoldFont=NULL;
m_hBorderPen=NULL;
m_hBackBrush=NULL;
m_hLightShadowPen=NULL;
m_hDarkShadowPen=NULL;
m_hBackPen=NULL;
m_hSelectedBrush=NULL;
m_hTextPen=NULL;
m_hSelectedTextPen=NULL;
m_hBitmap=NULL;
// 其他内部变量
m_bChild=false;
m_pPrevious=NULL;
m_State=stateInactive;
m_hWnd=NULL;
}
//析构函数
CFlatPopupMenu::~CFlatPopupMenu()
{
// 若正选择菜单,则释放
if(m_State==stateTrack)
ReleaseCapture();
//清除窗口
if(m_hWnd)
DestroyWindow(m_hWnd);
//清除GDI对象
Cleanup();
}
//清除GDI对象
void CFlatPopupMenu::Cleanup(void)
{
if(m_hFont)
{
DeleteObject(m_hFont);
DeleteObject(m_hBoldFont);
DeleteObject(m_hBorderPen);
DeleteObject(m_hBackBrush);
DeleteObject(m_hLightShadowPen);
DeleteObject(m_hDarkShadowPen);
DeleteObject(m_hBackPen);
DeleteObject(m_hSelectedBrush);
DeleteObject(m_hTextPen);
DeleteObject(m_hSelectedTextPen);
DeleteObject(m_hBitmap);
m_hFont=NULL;
m_hBoldFont=NULL;
m_hBorderPen=NULL;
m_hBackBrush=NULL;
m_hLightShadowPen=NULL;
m_hDarkShadowPen=NULL;
m_hBackPen=NULL;
m_hSelectedBrush=NULL;
m_hTextPen=NULL;
m_hSelectedTextPen=NULL;
m_hBitmap=NULL;
}
}
//创建GDI对象
void CFlatPopupMenu::CreateObjects(void)
{
LOGFONT lf;
HDC hDC;
HGDIOBJ hOldFont;
TEXTMETRIC tm;
Cleanup();
// 创建菜单字体
ZeroMemory(&lf,sizeof(lf));
hDC=CreateIC("DISPLAY",NULL,NULL,NULL);
lf.lfHeight=-MulDiv(m_FontSize,GetDeviceCaps(hDC,LOGPIXELSY),72);
lf.lfWeight=FW_NORMAL;
lf.lfCharSet=ANSI_CHARSET;
lf.lfOutPrecision=OUT_DEFAULT_PRECIS;
lf.lfClipPrecision=CLIP_DEFAULT_PRECIS;
lf.lfQuality=DEFAULT_QUALITY;
lf.lfPitchAndFamily=FF_DONTCARE | DEFAULT_PITCH;
lstrcpyn(lf.lfFaceName,m_strFont.c_str(),sizeof(lf.lfFaceName)/sizeof(TCHAR));
m_hFont=::CreateFontIndirect(&lf);
// 创建粗体菜单字体
lf.lfWeight=FW_BOLD;
m_hBoldFont=::CreateFontIndirect(&lf);
// 获取字体高度
hOldFont=SelectObject(hDC,m_hFont);
GetTextMetrics(hDC,&tm);
m_FontHeight=tm.tmHeight;
SelectObject(hDC,m_hBoldFont);
GetTextMetrics(hDC,&tm);
m_BoldFontHeight=tm.tmHeight;
SelectObject(hDC,hOldFont);
DeleteDC(hDC);
// 创建画笔、画刷
m_hBorderPen=CreatePen(PS_SOLID,1,m_Colors[colorBorder]);
m_hBackBrush=CreateSolidBrush(m_Colors[colorBackground]);
m_hSelectedBrush=CreateSolidBrush(m_Colors[colorHighlight]);
m_hLightShadowPen=CreatePen(PS_SOLID,1,m_Colors[colorLightShadow]);
m_hDarkShadowPen=CreatePen(PS_SOLID,1,m_Colors[colorDarkShadow]);
m_hBackPen=CreatePen(PS_SOLID,1,m_Colors[colorBackground]);
m_hTextPen=CreatePen(PS_SOLID,1,m_Colors[colorText]);
m_hSelectedTextPen=CreatePen(PS_SOLID,1,m_Colors[colorHighlightText]);
// 创建位图
if(m_BitmapID!=(UINT)-1)
m_hBitmap=LoadBitmap(m_hInstance,MAKEINTRESOURCE(m_BitmapID));
}
bool CFlatPopupMenu::Create(HINSTANCE hInstance,const UINT bitmap_id)
{
// 保存变量
m_hInstance=hInstance;
m_BitmapID=bitmap_id;
// 注册类
if(!m_bClassRegistered)
{
if(!RegisterClass())
return false;
m_bClassRegistered=true;
}
// 清除所有菜单项
m_Items.clear();
// 创建GDI对象
CreateObjects();
return true;
}
// 注册window 类
bool CFlatPopupMenu::RegisterClass(void)
{
WNDCLASS wc;
wc.style=0;
wc.lpfnWndProc=stubWindowProc;
wc.cbClsExtra=0;
wc.cbWndExtra=0;
wc.hInstance=m_hInstance;
wc.hIcon=NULL;
wc.hCursor=LoadCursor(NULL,IDC_ARROW);
wc.hbrBackground=NULL;
wc.lpszMenuName=NULL;
wc.lpszClassName="fpmMenuClass";
return ::RegisterClass(&wc)!=FALSE;
}
//增加菜单项
bool CFlatPopupMenu::AppendItem(const DWORD dwFlags,LPCTSTR pszName,const UINT itemid,const int icon)
{
CItem item;
item.m_dwFlags=dwFlags;
if(pszName)
item.m_strName=pszName;
item.m_ItemID=itemid;
item.m_IconIndex=icon;
item.m_pPopup=NULL;
m_Items.push_back(item);
return true;
}
//增加弹出式菜单
bool CFlatPopupMenu::AppendPopup(const DWORD dwFlags,LPCTSTR pszName,CFlatPopupMenu& popup,const int icon)
{
CItem item;
// 不允许分隔条
if((dwFlags & itemSeparator)!=0)
return false;
//增加菜单项
item.m_dwFlags=dwFlags;
item.m_strName=pszName;
item.m_ItemID=0;
item.m_IconIndex=icon;
item.m_pPopup=&popup;
popup.m_bChild=true;
popup.m_pPrevious=this;
m_Items.push_back(item);
return true;
}
//选择菜单项
UINT CFlatPopupMenu::Track(int x,int y,HWND hWnd,const bool bModal,const bool bPopup)
{
HDC hDC;
std::vector<CItem>::iterator it;
SIZE size;
int maxw,top;
HGDIOBJ hOldFont;
MSG msg;
RECT rcScreen;
hDC=CreateIC("DISPLAY",NULL,NULL,NULL);
// 获取最大菜单项宽度
maxw=0;
top=3;
for(it=m_Items.begin();it!=m_Items.end();it++)
{
it->m_Top=top;
if(!(it->m_dwFlags & itemSeparator))
{
hOldFont=SelectObject(hDC,(it->m_dwFlags & itemBold)==0 ? m_hFont : m_hBoldFont);
GetTextExtentPoint32(hDC,it->m_strName.c_str(),it->m_strName.length(),&size);
maxw=max(size.cx,maxw);
SelectObject(hDC,hOldFont);
top+=17;
it->m_Height=17;
}
else
{
top+=5;
it->m_Height=5;
}
}
DeleteDC(hDC);
// 获取屏幕大小,对x和y作必要的调整
m_Width=1+2+18+2+maxw+18+1;
m_SelectedItem=-1;
m_SelectedID=0;
SystemParametersInfo(SPI_GETWORKAREA,0,&rcScreen,0);
if(x+m_Width>rcScreen.right)
x=max(0,rcScreen.right-m_Width);
if(y+top+2>rcScreen.bottom)
y=max(0,rcScreen.bottom-(top+2));
// 创建窗口
m_hWnd=::CreateWindowEx(WS_EX_TOOLWINDOW, //按钮不能在任务栏上显示
"fpmMenuClass",
"",
WS_POPUP | WS_VISIBLE,
x,
y,
m_Width,
top+2,
NULL,
NULL,
m_hInstance,
(LPVOID)this);
if(m_hWnd==NULL)
return false;
if(bPopup)
{
m_bWaitLeftButton=false;
m_bWaitRightButton=false;
m_State=stateShow;
}
else
{
SetCapture(m_hWnd);
m_State=stateTrack;
m_bWaitLeftButton=(GetKeyState(VK_LBUTTON) & 0x8000)!=0;
m_bWaitRightButton=(GetKeyState(VK_RBUTTON) & 0x8000)!=0;
}
m_bModal=bModal;
m_hWndCommand=hWnd;
if(m_bModal)
{
while(GetMessage(&msg,NULL,0,0)==TRUE && IsWindow(m_hWnd))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return m_SelectedID;
}
return 0;
}
//stub window 程序
static LRESULT CALLBACK stubWindowProc(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam)
{
CFlatPopupMenu *pClass;
switch(uMsg)
{
case WM_CREATE:
SetWindowLong(hWnd,GWL_USERDATA,(LONG)((LPCREATESTRUCT)lParam)->lpCreateParams);
break;
case WM_ERASEBKGND:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnEraseBkgnd(hWnd,(HDC)wParam);
return TRUE;
case WM_LBUTTONDOWN:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnLButtonDown(hWnd,LOWORD(lParam),HIWORD(lParam));
break;
case WM_RBUTTONDOWN:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnLButtonDown(hWnd,LOWORD(lParam),HIWORD(lParam));
break;
case WM_LBUTTONUP:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnLButtonUp(hWnd,LOWORD(lParam),HIWORD(lParam));
break;
case WM_RBUTTONUP:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnRButtonUp(hWnd,LOWORD(lParam),HIWORD(lParam));
break;
case WM_MOUSEMOVE:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnMouseMove(hWnd,LOWORD(lParam),HIWORD(lParam));
break;
case WM_TIMER:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnTimer(hWnd,wParam);
break;
case WM_CHAR:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnChar(hWnd,(char)wParam);
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
BeginPaint(hWnd,&ps);
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnPaint(hWnd,ps.hdc);
EndPaint(hWnd,&ps);
}
break;
case WM_DESTROY:
pClass=reinterpret_cast<CFlatPopupMenu *>(GetWindowLong(hWnd,GWL_USERDATA));
pClass->OnDestroy(hWnd);
break;
}
return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
// WM_CHAR消息处理函数
void CFlatPopupMenu::OnChar(HWND hWnd,TCHAR c)
{
std::vector<CItem>::const_iterator it;
std::string::size_type pos;
// 转换成小写
c=(TCHAR)CharLower((LPTSTR)c);
// 查找菜单项
for(it=m_Items.begin();it!=m_Items.end();it++)
{
if((it->m_dwFlags & (itemSeparator | itemGrayed | itemNotSelectable))==0)
{
if((pos=it->m_strName.find('&'))!=std::string::npos && it->m_strName.length()>pos+1 && c==(TCHAR)CharLower((LPTSTR)it->m_strName[pos+1]))
{
// 设置返回值
SetReturn(it->m_ItemID);
return;
}
}
}
}
// WM_TIMER 消息处理函数
void CFlatPopupMenu::OnTimer(HWND hWnd,unsigned short timerid)
{
POINT p;
KillTimer(hWnd,timerid);
//显示弹出式菜单
if(m_SelectedItem!=-1 && m_Items[m_SelectedItem].m_pPopup)
{
// 获取显示位置
p.x=m_Width-5;
p.y=m_Items[m_SelectedItem].m_Top-3;
ClientToScreen(hWnd,&p);
// 跟踪选择
if(m_Items[m_SelectedItem].m_pPopup->Track(p.x,p.y,NULL,true,true))
DestroyAll();
}
}
//画菜单项
void CFlatPopupMenu::DrawItem(HWND hWnd,HDC hDC,const int index,const CItem& item)
{
bool bSelected=index==m_SelectedItem;
HGDIOBJ hOldPen,hOldBrush,hOldFont;
POINT p[3];
int i,x,y,h,nColor;
RECT rect;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?