📄 menubar.cpp
字号:
// MenuBar.cpp : implementation file
//
#include "stdafx.h"
#include "ExplorerFavorateMenu.h"
#include "MenuBar.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
#define MB_POPUPMENU WM_USER + 100
#define ID_FIRSTMENU WM_USER + 200
#define TPM_VERPOSANIMATION 0x1000L
#define PriMenuButtonIDIncresement 100
#define FOLDERICONINDEX -1
#define NOICONFOUND -2
// CMenuBar
CMenuBar::CMenuBar()
{
m_bTrack = FALSE;
m_hMenu = NULL;
m_nPressed = -1;
m_nPriMenuItemCount = 0;
}
CMenuBar::~CMenuBar()
{
FreeMenuResource(m_hMenu);
DestroyIcon(m_hIeIcon);
DestroyIcon(m_hFolderIcon);
}
BEGIN_MESSAGE_MAP(CMenuBar, CToolBar)
//{{AFX_MSG_MAP(CMenuBar)
ON_WM_LBUTTONDOWN()
ON_MESSAGE(MB_POPUPMENU, OnPopupMenu)
ON_WM_DRAWITEM()
ON_WM_MEASUREITEM()
ON_MESSAGE(WM_MENUCOMMAND, OnMenuCommand)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMenuBar message handlers
////////////////////////////////////////////////////////////////////////////////
CMenuBar* pMenuBar = NULL;
HHOOK g_hMsgHook = NULL;
////////////////////////////////////////////////////////////////////////////////
LRESULT CMenuBar::MenuInputFilter(int nCode, WPARAM wParam, LPARAM lParam)
{
MSG* pMsg = (MSG*)lParam;
//因为TrackPopupMenuEx调用后线程等待用户输入,此时
//就不能处理其他消息,所以采用钩子.
if(!pMenuBar || nCode != MSGF_MENU)//只处理菜单消息
return CallNextHookEx(g_hMsgHook,nCode,wParam,lParam);
if(pMenuBar->OnMenuInput(pMsg))
return TRUE;
else
return CallNextHookEx(g_hMsgHook,nCode,wParam,lParam);
}
HWND CMenuBar::Create(HWND ParentWnd)
{
CWnd TmpParamWnd;
TmpParamWnd.Attach (ParentWnd);
if(!CToolBar::CreateEx (&TmpParamWnd, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT))
{
TmpParamWnd.Detach ();
return NULL;
}
TmpParamWnd.Detach ();
if(!InitMenuBar())
return NULL;
m_hIeIcon = (HICON)LoadImage(_Module.m_hInstResource, MAKEINTRESOURCE(IDI_IEICON), IMAGE_ICON, 0, 0, 0);
m_hFolderIcon = (HICON)LoadImage(_Module.m_hInstResource, MAKEINTRESOURCE(IDI_FOLDERICON), IMAGE_ICON, 0, 0, 0);
return m_hWnd;
}
BOOL CMenuBar::InitMenuBar()
{
if(!CreateFavorateMenu())
return FALSE;
//用工具栏模拟菜单
//主菜单ID从ID_FIRSTMENU起
CToolBarCtrl& tbc = GetToolBarCtrl();
tbc.SetBitmapSize (CSize(0,0));//没有图标, 置图标尺寸为0.
m_nPriMenuItemCount = GetMenuItemCount(m_hMenu);
int nStrIndex; TCHAR MenuText[64];
TBBUTTON MenuBtn; RECT rect;
TBBUTTONINFO tif; tif.cbSize = sizeof(tif);
HDC hOwnerDC = ::GetDC(m_hWnd);//选用标准字体来测定文字所占空间
HGDIOBJ hOldFnt = SelectObject(hOwnerDC, GetStockObject(DEFAULT_GUI_FONT));
for(int i = 0;i < m_nPriMenuItemCount;i++)
{
//设置Toolbar上的按钮,仅文字,故似菜单.
GetMenuString(m_hMenu, i, MenuText, 64, MF_BYPOSITION);
nStrIndex = AddString(MenuText);
MenuBtn.iBitmap = NULL;
MenuBtn.dwData = 0;
MenuBtn.fsState = TBSTATE_ENABLED;
MenuBtn.fsStyle = TBSTYLE_BUTTON;
MenuBtn.idCommand = ID_FIRSTMENU + i*PriMenuButtonIDIncresement;
MenuBtn.iString = nStrIndex;
tbc.InsertButton (-1, &MenuBtn);
tif.dwMask = TBIF_SIZE;
DrawText(hOwnerDC, MenuText, lstrlen(MenuText), &rect, DT_LEFT|DT_CALCRECT|DT_SINGLELINE);
tif.cx = rect.right - rect.left + 12;
tbc.SetButtonInfo (MenuBtn.idCommand, &tif);
}
SelectObject(hOwnerDC, hOldFnt);
::ReleaseDC(m_hWnd, hOwnerDC);
return TRUE;
}
int CMenuBar::AddString(LPCTSTR lpszString)
{
//虽然MSDN说必须以两个\0结尾,但仅一个字符串时,可以直接以普通单个\0结尾
TCHAR TmpStr[66];
lstrcpy(TmpStr, lpszString);
TmpStr[lstrlen(lpszString)+1] = '\0';
return SendMessage(TB_ADDSTRING, (WPARAM)NULL, (LPARAM)TmpStr);
}
void CMenuBar::PressButton(int nIndex, BOOL bPress)
{
//显示下压状态
CToolBarCtrl& tbc = GetToolBarCtrl();
tbc.PressButton (ID_FIRSTMENU + nIndex*100, bPress);
}
void CMenuBar::OnLButtonDown(UINT nFlags, CPoint point)
{
//菜单所有相关操作从这开始
m_ptMouse.x = point.x;
m_ptMouse.y = point.y;
//nTest是所按下主菜单项的Index
int nTest = SendMessage(TB_HITTEST, 0, (LPARAM)&m_ptMouse);
if(nTest < 0 || nTest >= m_nPriMenuItemCount)
return;
m_nPressed = nTest;//记录所按下菜单项
TrackPopup();//弹出菜单
}
//////////////////////////////////////////////////////////////////////////
//跟踪弹出子菜单
/////////////////////////////////////////////////////////////////////////
void CMenuBar::TrackPopup()
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());//Init MFC
//MFC与API混合编程,Cool! MenuBar包装并抽象了m_hMenu,使之表现为一个Window Bar.
HMENU hSubMenu = GetSubMenu(m_hMenu, m_nPressed);//得到子菜单句柄
if(hSubMenu == NULL)
return;
m_bTrack = TRUE;//开始跟踪
PressButton(m_nPressed, TRUE);//压下按钮
RECT rc;
GetItemRect(m_nPressed,&rc);
ClientToScreen(&rc);
TPMPARAMS tpm;
tpm.cbSize = sizeof(tpm);
tpm.rcExclude = rc;
//设置钩子函数
pMenuBar = this;
g_hMsgHook = SetWindowsHookEx(WH_MSGFILTER, MenuInputFilter, NULL, GetCurrentThreadId());
//跟踪菜单弹出,线程转入钩子函数的运作.
TrackPopupMenuEx(hSubMenu, TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL|TPM_VERPOSANIMATION, rc.left, rc.bottom, m_hWnd, NULL);
PressButton(m_nPressed, FALSE);
UnhookWindowsHookEx(g_hMsgHook);//解除钩子函数
g_hMsgHook = NULL;
pMenuBar = NULL;
}
/////////////////////////////////////////////////////////////////////////////////
BOOL CMenuBar::OnMenuInput(MSG* pMsg)
{
BOOL bResult = FALSE;
//处理在PopMenu后主线程等待时的其他消息。
switch(pMsg->message)
{
case WM_MOUSEMOVE:
{
POINT pt;
pt.x = LOWORD(pMsg->lParam);
pt.y = HIWORD(pMsg->lParam);
ScreenToClient(&pt);
if(m_ptMouse.x == pt.x && m_ptMouse.y == pt.y)
return TRUE;
m_ptMouse.x = pt.x;
m_ptMouse.y = pt.y;
int nTest = SendMessage(TB_HITTEST, 0, (LPARAM)&pt);
//鼠标移动到非当前项
if(nTest >= 0 && nTest< m_nPriMenuItemCount && nTest != m_nPressed)
{
PressButton(m_nPressed, FALSE);//回复原下压菜单
//撤销弹出菜单, TrackPopMenuEx后的语句开始执行。
//注意, 此时两个线程开始同时运行。
PostMessage(WM_CANCELMODE, 0, 0);
//下压后移项,弹出菜单
m_nPressed = nTest;
PostMessage(MB_POPUPMENU,0,0);
bResult = TRUE;
}
}
break;
case WM_LBUTTONDOWN:
{
POINT pt;
pt.x = LOWORD(pMsg->lParam);
pt.y = HIWORD(pMsg->lParam);
ScreenToClient(&pt);
int nTest = SendMessage(TB_HITTEST, 0, (LPARAM)&pt);
if(nTest<0)
m_bTrack = FALSE;
else if(nTest == m_nPressed)
{
m_bTrack = FALSE;
PostMessage(WM_CANCELMODE, 0, 0);
bResult = TRUE;
}
}
break;
case WM_KEYDOWN:
{
TCHAR vkey = pMsg->wParam;
if(vkey == VK_LEFT)
{
PressButton(m_nPressed,FALSE);
m_nPressed --;
PostMessage(WM_CANCELMODE,0,0);
PostMessage(MB_POPUPMENU,0,0);
bResult = TRUE;
}
else if(vkey == VK_RIGHT)
{
PressButton(m_nPressed, FALSE);
m_nPressed++;
PostMessage(WM_CANCELMODE,0,0);
PostMessage(MB_POPUPMENU,0,0);
bResult = TRUE;
}
else if (vkey == VK_ESCAPE)
{
PostMessage(WM_CANCELMODE, 0, 0);
m_bTrack = FALSE;
bResult = TRUE;
}
}
break;
default:
break;
}
return bResult;
}
////////////////////////////////////////////////////////////////////////////
LRESULT CMenuBar::OnPopupMenu(WPARAM wParam, LPARAM lParam)
{
//左右轮循
if(m_nPressed < 0)
m_nPressed = m_nPriMenuItemCount - 1;
if(m_nPressed >= m_nPriMenuItemCount)
m_nPressed = 0;
TrackPopup();
return 0;
}
BOOL CMenuBar::CreateFavorateMenu()
{
//太复杂了,说不出!
AFX_MANAGE_STATE(AfxGetStaticModuleState());
WIN32_FIND_DATA fd;
TCHAR FavoritesPath[MAX_PATH];//保持的收藏夹目录
TCHAR lpszChildFolder[MAX_PATH];
m_URLStringArray.RemoveAll ();
m_uMenuIDOrder = ID_FIRSTMENU;
if(!SHGetSpecialFolderPath(m_hWnd, FavoritesPath, CSIDL_FAVORITES, FALSE))
return FALSE;
lstrcpy(lpszChildFolder, FavoritesPath);
lstrcat(lpszChildFolder, "\\*.*");
HANDLE hFindFile = FindFirstFile(lpszChildFolder, &fd);
if(hFindFile == INVALID_HANDLE_VALUE)//没找到任何文件夹,一般不可能发生.
{
FindClose(hFindFile);
return FALSE;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -