?? cbmpmenu.cpp
字號:
//////////////////////////////////////////////////////////////
//類名:CBmpMenu
//功能:左側帶位圖或漸變色菜單效果的自繪式菜單顯示
//修改人:徐景周(jingzhou_xu@163.net)
//組織:未來工作室(Future Studio)
//日期:2000.10
///////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "CBmpMenu.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CBmpMenu
// constructor
CBmpMenu::CBmpMenu(int nBitmapW, BOOL bShowBmp4SubMenu, HBITMAP hBitmap, BOOL bStretchBmp)
{
//check if hbitmap is a valid handle
BITMAP bitmap;
if(GetObject(hBitmap, sizeof(bitmap), &bitmap))
{
m_hBitmap = hBitmap;
}
else
{
m_hBitmap = NULL;
}
//initialize internal data
m_bShowBmpAll = bShowBmp4SubMenu;
m_pOwnerWnd = m_pToolbar = 0;
m_bSubMenu = FALSE;
m_pSubMenuWnd = 0;
m_bStretchBmp = bStretchBmp;
m_nTBOffSet = nBitmapW; //條狀位圖或漸變色寬度
}
CBmpMenu::~CBmpMenu()
{
}
IMPLEMENT_DYNAMIC( CBmpMenu, CWnd )
BEGIN_MESSAGE_MAP(CBmpMenu, CWnd)
//{{AFX_MSG_MAP(CBmpMenu)
ON_WM_PAINT()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CBmpMenu message handlers
BOOL
CBmpMenu :: Attach( HMENU hMenu )
{
return CMenu::Attach(hMenu);
}
HMENU
CBmpMenu :: Detach()
{
return CMenu::Detach();
}
BOOL CBmpMenu::DestroyWindow()
{
//Send WM_EXITMENULOOP to the owner window
m_pOwnerWnd->SendMessage(WM_EXITMENULOOP, FALSE);
//destroy the current window and set focus to parent if parent is of the same class
if(::IsWindow(GetParent()->GetSafeHwnd()) &&
GetParent()->IsKindOf(RUNTIME_CLASS(CBmpMenu)))
{
GetParent()->SetFocus();
}
return CWnd::DestroyWindow();
}
BOOL
CBmpMenu :: TrackPopupMenu( UINT nFlags, int x, int y, CWnd* pParentWnd, CRect* pItemRect)
{
//if this is a main menu, then parent window is same as owner window
if(!m_bSubMenu)
{
m_pOwnerWnd = pParentWnd;
}
//Send menu messages to owner window
if(m_pOwnerWnd && IsWindow(m_pOwnerWnd->m_hWnd))
m_pOwnerWnd->SendMessage(m_bSubMenu?WM_INITMENUPOPUP:WM_INITMENU, (WPARAM)m_hMenu, 0);
else
return FALSE;
//create the main window...child of this will be a toolbar which acts as a kind of menu
if(!CreateEx(WS_EX_DLGMODALFRAME|WS_EX_PALETTEWINDOW|WS_EX_CONTROLPARENT
, 0, 0, WS_POPUP|WS_CLIPSIBLINGS|WS_CLIPCHILDREN|WS_BORDER|WS_CHILD,
CRect(0,0,0,0), pParentWnd, 0))
return FALSE;
//set the data of parent popup menu
if(m_bSubMenu)
{
((CBmpMenu*)GetParent())->m_pSubMenuWnd = this;
}
//create toolbar
m_pToolbar = new MenuToolBar;
//We add a custom draw toolbar which will act as a menu
m_pToolbar->CreateEx(this, TBSTYLE_FLAT|TBSTYLE_LIST|TBSTYLE_CUSTOMERASE|TBSTYLE_WRAPABLE,
WS_CLIPCHILDREN|CCS_NODIVIDER|CCS_NORESIZE|CCS_NOPARENTALIGN|CBRS_TOOLTIPS);
//Initialize toolbar data and place the menu window on screen
InitToolBarData(m_pToolbar, CPoint(x,y), pItemRect);
//show the menu window without activating it....before that make the owner window as foreground window
if(!m_bSubMenu)
{
m_pOwnerWnd->SetForegroundWindow();
}
ShowWindow(SW_SHOWNA);
//capture keyboard input
SetFocus();
//if this is a submenu and user had opened it by pressing right arrow key
if(m_bSubMenu & MENU_SELECTFIRSTITEM)
{
m_pToolbar->SendMessage(TB_SETHOTITEM, 0, 0);
}
m_bSubMenu &= ~MENU_SELECTFIRSTITEM;
//send a notification message to owner
if(m_pOwnerWnd && IsWindow(m_pOwnerWnd->m_hWnd))
m_pOwnerWnd->SendMessage(WM_ENTERMENULOOP, (WPARAM)m_hMenu, (LPARAM)m_hWnd);
//run the modal loop so that the menu window acts as a kind of dialog
RunModalLoop();
//delete allocated memory and cleanup other stuff
Cleanup();
return TRUE;
}
//wp gives a point on which left mouse button was clicked for the parent menu
void CBmpMenu::PopupSubMenu(WPARAM wp, BOOL bSelectFirstItem)
{
CPoint point(LOWORD(wp), HIWORD(wp));
//Get the button on which left mouse button was clicked
int nBtnIndex = (m_pToolbar->GetToolBarCtrl()).HitTest(&point);
TBBUTTON tbb;
(m_pToolbar->GetToolBarCtrl()).GetButton(nBtnIndex, &tbb);
/*
//得到漸變條顯示文字
MENUITEMINFO *pMIData = (MENUITEMINFO *)tbb.dwData;
char *pStr = pMIData->dwTypeData;
CString strTitle;
while (*pStr) {
const char c = pStr[0];
if (c != '&')
strTitle += c;
pStr++;
};
*/
//Get window rectangle of this button
CRect rect;
(m_pToolbar->GetToolBarCtrl()).GetItemRect(nBtnIndex, &rect);
(m_pToolbar->GetToolBarCtrl()).ClientToScreen(&rect);
//Construct popup menu
CBmpMenu oSubMenu(m_bShowBmpAll?m_nTBOffSet:0, m_bShowBmpAll, m_bShowBmpAll?m_hBitmap:0, m_bStretchBmp);
//可在此設置漸變色條
// oSubMenu.SetGradientColors(m_Color1, m_Color2, m_ColorText);
// oSubMenu.SetTitle(strTitle);
//intialize data of popup menu
oSubMenu.m_pOwnerWnd = m_pOwnerWnd;
//When user created an instance of CBmpMenu, automatically a handle was associated with root menu
//when he called loadMenu or CreatePopupMenu. But we are not doing any of it for submenus..so just attach
//the menu handle of the submenu to this submenu window
oSubMenu.Attach(((MENUITEMINFO*)(tbb.dwData))->hSubMenu);
//Set data to indicate whther first item should be set as a hot item
oSubMenu.m_bSubMenu = TRUE | bSelectFirstItem;
//Add the blank space with to get bounds rect of this button in root menu
rect.left -= m_nTBOffSet;
//Show the submenu window
oSubMenu.TrackPopupMenu(0, 0, 0, this, &rect);
//detach the menu handle
oSubMenu.Detach();
}
void CBmpMenu::InitToolBarData(CToolBar *pToolBar, CPoint pt, CRect* pItemRect)
{
//enable tooltips
pToolBar->EnableToolTips(TRUE);
//set toolbar buutons bitmap size first. This should be equal to checkmark dimensions
//button size will be automatically calculated by toolbar
pToolBar->SendMessage(TB_SETBITMAPSIZE, 0, MAKELPARAM(GetSystemMetrics(SM_CXMENUCHECK), GetSystemMetrics(SM_CYMENUCHECK)));
//for each menu item...add corrsponding buttons to the toolbar
for(int i=0; i<(int)GetMenuItemCount(); i++)
{
MENUITEMINFO menuInfo, *pMenuInfo;
TBBUTTON buttonInfo;
char *pszBuffer;
//initialize
menuInfo.cbSize = sizeof(menuInfo);
menuInfo.fMask = MIIM_CHECKMARKS|MIIM_DATA|MIIM_ID|MIIM_STATE|MIIM_SUBMENU|MIIM_TYPE;
pszBuffer = new char[MAX_PATH]; //buffer for button text
menuInfo.cch = MAX_PATH;
menuInfo.dwTypeData = pszBuffer;
ZeroMemory(&buttonInfo, sizeof(buttonInfo));
GetMenuItemInfo(i, &menuInfo, TRUE);
if(menuInfo.dwTypeData == 0)
delete pszBuffer;
//store the app defined data pointer
pMenuInfo = new MENUITEMINFO;
*pMenuInfo = menuInfo;
buttonInfo.dwData = (ULONG)pMenuInfo;
//set button info from menuInfo...default state is enabled
buttonInfo.fsState = TBSTATE_ENABLED|TBSTATE_WRAP;
//check if its a separator
if(menuInfo.fType & MFT_SEPARATOR)
{
buttonInfo.fsStyle = TBSTYLE_SEP;
}
//check if the menu item is disabled or grayed
if((menuInfo.fState & MF_GRAYED) || (MF_DISABLED & menuInfo.fState))
buttonInfo.fsState = 0;
//set button command id
buttonInfo.idCommand = menuInfo.wID;
//add the button
(pToolBar->GetToolBarCtrl()).AddButtons(1, &buttonInfo);
//Set button text
if(menuInfo.dwTypeData)
{
pToolBar->SetButtonText(i, pszBuffer);
}
}
//Get the button width and add width of arrow mark to be drawn for popup menus
int nWidth = LOWORD(pToolBar->GetToolBarCtrl().GetButtonSize());
nWidth += GetSystemMetrics(SM_CXMENUCHECK);
//add width for showing arrows for submenus
pToolBar->GetToolBarCtrl().SetButtonWidth(nWidth, nWidth);
//set the toolbar button size
CRect rect1, rect2;
(pToolBar->GetToolBarCtrl()).GetItemRect(0, &rect1);
//if all the buttons have dropdown arrow...the toolbar returns extra height equal to one row
(pToolBar->GetToolBarCtrl()).GetItemRect(GetMenuItemCount()-1, &rect2);
//set the total toolbar size
//offset of 3 pixels to either side of the toolbar
//If another control(bitmap or slider) is to be placed by the side of toolbar then we have to take
//into account the width of that control=m_nTBOffSet
//Also we need to check that this window rect lies in the screen rect
PositionMenuWindow(pt, pItemRect, CRect(0, 0, rect1.Width()+6+m_nTBOffSet, rect2.bottom-rect1.top+6));
//place the toolbar window in the menu window
pToolBar->MoveWindow(m_nTBOffSet, 0, rect1.Width()+6, rect2.bottom-rect1.top+6);
//Show the toolbar window without activating it
pToolBar->ShowWindow(SW_SHOWNOACTIVATE);
}
LRESULT CBmpMenu::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
// TODO: Add your specialized code here and/or call the base class
CWnd* pWnd = 0;
BOOL bFlag = FALSE;
switch(message)
{
case WM_ACTIVATE:
{
//Close all menu windows, if another window is being activated because of a mouse click outside menu window
CWnd oWnd;
if(lParam && IsWindow(HWND(lParam)) && (LOWORD(wParam) == WA_INACTIVE))
if(!oWnd.FromHandle(HWND(lParam))->IsKindOf(RUNTIME_CLASS(CBmpMenu)))
DestroyRootMenu();
if(!lParam)
DestroyRootMenu();
return 0L;
}
break;
case WM_SYSKEYDOWN:
//destroy root menu when alt or any syskey is pressed
DestroyRootMenu();
break;
case WM_KEYDOWN:
//pass the keydown event to toolbar
//If a submenu is being shown for this menu, then key down should be handled by submenu window
//else pass it to toolbar
if(m_pSubMenuWnd)
m_pSubMenuWnd->SendMessage(WM_KEYDOWN, wParam, lParam);
else
m_pToolbar->SendMessage(WM_KEYDOWN, wParam, lParam);
return 0L;
case WM_RESETDATA:
//User defined message to be sent to toolbar to reinitialize internal data
m_pToolbar->SendMessage(WM_RESETDATA, 0, 0);
return 0L;
case WM_COMMAND:
//pass on control specific messages(if any) to owner window
m_pOwnerWnd->PostMessage(WM_COMMAND, wParam, lParam);
return 0L;
case WM_POPUPSUBMENU:
//popup the submenu
PopupSubMenu(wParam, lParam);
return 0L;
}
return CWnd::DefWindowProc(message, wParam, lParam);
}
//destroys all menu window
void CBmpMenu::DestroyRootMenu()
{
if(m_hWnd && IsWindow(m_hWnd))
{
CWnd *pParent = GetParent();
if(pParent && IsWindow(pParent->m_hWnd))
{
if(pParent->IsKindOf(RUNTIME_CLASS(CBmpMenu)))
((CBmpMenu*)pParent)->DestroyRootMenu();
}
if(m_hWnd && IsWindow(m_hWnd))
{
DestroySubMenus();
//end the modal loop started using RunModalLoop in TrackPopupMenu function
EndModalLoop(0);
m_pSubMenuWnd = 0;
}
}
}
//destroy all the submenu window associated with this menu
void CBmpMenu::DestroySubMenus()
{
if(m_pSubMenuWnd)
{
m_pSubMenuWnd->DestroySubMenus();
//end the modal loop started using RunModalLoop in TrackPopupMenu function
m_pSubMenuWnd->EndModalLoop(0);
m_pSubMenuWnd = 0;
}
}
void CBmpMenu::Cleanup()
{
//remove all allocated memory
if(m_pToolbar && IsWindow(m_pToolbar->m_hWnd))
{
for(int i = 0; i<(m_pToolbar->GetToolBarCtrl()).GetButtonCount(); i++)
{
TBBUTTON tbb;
(m_pToolbar->GetToolBarCtrl()).GetButton(i, &tbb);
if(tbb.dwData)
{
if(((MENUITEMINFO*)(tbb.dwData))->dwTypeData)
delete (char*)(((MENUITEMINFO*)(tbb.dwData))->dwTypeData);
delete (MENUITEMINFO*)(tbb.dwData);
tbb.dwData = 0;
}
}
//destroy our windows
m_pToolbar->DestroyWindow();
delete m_pToolbar;
m_pToolbar = 0;
}
if(IsWindow(m_hWnd))
DestroyWindow();
}
BOOL CBmpMenu::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Add your specialized code here and/or call the base class
BOOL bRet = CWnd::PreCreateWindow(cs);
WNDCLASS wc;
::GetClassInfo(AfxGetInstanceHandle(), cs.lpszClass, &wc);
//register new class with same info but different class
wc.lpszClassName = cs.lpszClass = "BitmapMenu";
AfxRegisterClass(&wc);
return bRet;
}
void CBmpMenu::OnPaint()
{
CPaintDC dc(this); // device context for painting
CRect rect;
GetClientRect(&rect);
/*
//可在在此處畫漸變條
CRect rect2 = rect;
rect2.right = m_nTBOffSet;
PaintGradiantRect(&dc, rect2, m_Color1, m_Color2, false, true);
// Initialize fonts:
LOGFONT lf;
memset (&lf, 0, sizeof (LOGFONT));
// Text will be rotated counter-clockwise 90 degrees.
lf.lfOrientation = lf.lfEscapement = 900;
// We need a TrueType font to get rotated text. MS Sans //Serif won't cut it!
lstrcpy ( lf.lfFaceName, _T("Arial") );
lf.lfHeight = 14;
lf.lfWeight = FW_DEMIBOLD;
lf.lfItalic = TRUE;
// Create a font with the tweaked attributes.
CFont font;
font.CreateFontIndirect ( &lf );
CFont * OldFont = dc.SelectObject ( &font );
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -