⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 menubar.cpp

📁 对c++类库cj60的简化包装
💻 CPP
📖 第 1 页 / 共 2 页
字号:
////////////////////////////////////////////////////////////////
// Copyright 1998 Paul DiLascia
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
// CMenuBar implements menu bar for MFC. See MenuBar.h for how
// to use, and also the MBTest sample application.
//
#include "StdAfx.h"
#include "MenuBar.h"

const UINT MB_SET_MENU_NULL = WM_USER + 1100;

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// if you want to see extra TRACE diagnostics, set CMenuBar::bTRACE = TRUE
BOOL CMenuBar::bTRACE = FALSE;

#ifdef _DEBUG
#define MBTRACEFN			\
	CTraceFn __fooble;	\
	if (CMenuBar::bTRACE)\
		TRACE
#define MBTRACE			\
	if (CMenuBar::bTRACE)\
		TRACE
#else
#define MBTRACEFN TRACE
#define MBTRACE   TRACE
#endif

IMPLEMENT_DYNAMIC(CMenuBar, CCJToolBar)

BEGIN_MESSAGE_MAP(CMenuBar, CCJToolBar)
	ON_WM_CREATE()
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_SIZE()
	ON_UPDATE_COMMAND_UI_RANGE(0, 256, OnUpdateMenuButton)
	ON_MESSAGE(MB_SET_MENU_NULL, OnSetMenuNull)
END_MESSAGE_MAP()

CMenuBar::CMenuBar()
{
	if (iVerComCtl32 <= 470)
		AfxMessageBox(_T("Warning: This program requires comctl32.dll version 4.71 or greater."));

	m_iTrackingState = TRACK_NONE;		 // initial state: not tracking 
	m_iPopupTracking = m_iNewPopup = -1; // invalid
	m_hmenu = NULL;
	m_bAutoRemoveFrameMenu = TRUE;		 // set frame's menu to NULL
}

CMenuBar::~CMenuBar()
{
}

//////////////////
// Menu bar was created: install hook into owner window
//
int CMenuBar::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CCJToolBar::OnCreate(lpCreateStruct)==-1)
		return -1;
	UpdateFont();
	CWnd* pFrame = GetOwner();
	ASSERT_VALID(pFrame);
	m_frameHook.Install(this, *pFrame);
	return 0; // OK
}

//////////////////
// Set menu bar font from current system menu font
//
void CMenuBar::UpdateFont()
{
	static CFont font;
	NONCLIENTMETRICS info;
	info.cbSize = sizeof(info);
	SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
	if ((HFONT)font)
		font.DeleteObject();
	VERIFY(font.CreateFontIndirect(&info.lfMenuFont));
	SetFont(&font);
}

//////////////////
// The reason for having this is so MFC won't automatically disable
// the menu buttons. Assumes < 256 top-level menu items. The ID of
// the ith menu button is i. IOW, the index and ID are the same.
//
void CMenuBar::OnUpdateMenuButton(CCmdUI* pCmdUI)
{
	ASSERT_VALID(this);
	if (IsValidButton(pCmdUI->m_nID))
		pCmdUI->Enable(TRUE);
}

//////////////////
// Recompute layout of menu bar
//
void CMenuBar::RecomputeMenuLayout()
{
	SetWindowPos(NULL, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOACTIVATE |
		SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER);
}

//////////////////
// Make frame recalculate control bar sizes after menu change
//
void CMenuBar::RecomputeToolbarSize()
{
	// Force toolbar to recompute size
	CFrameWnd* pFrame = (CFrameWnd*)GetOwner();
	ASSERT_VALID(pFrame);
	ASSERT(pFrame->IsFrameWnd());
	pFrame->RecalcLayout();

	// floating frame
	pFrame = GetParentFrame();
	if (pFrame->IsKindOf(RUNTIME_CLASS(CMiniFrameWnd)))
		pFrame->RecalcLayout();	
}

//////////////////
// Set tracking state: none, button, or popup
//
void CMenuBar::SetTrackingState(TRACKINGSTATE iState, int iButton)
{
	ASSERT_VALID(this);
	if (iState != m_iTrackingState) {
		if (iState == TRACK_NONE)
			iButton = -1;

#ifdef _DEBUG
		static LPCTSTR StateName[] = { _T("NONE"), _T("BUTTON"), _T("POPUP") };
		MBTRACE(_T("CMenuBar::SetTrackingState to %s, button=%d\n"),
			StateName[iState], iButton);
#endif

		SetHotItem(iButton);					 // could be none (-1)

		if (iState==TRACK_POPUP) {
			// set related state stuff
			m_bEscapeWasPressed = FALSE;	 // assume Esc key not pressed
			m_bProcessRightArrow =			 // assume left/right arrow..
				m_bProcessLeftArrow = TRUE; // ..will move to prev/next popup
			m_iPopupTracking = iButton;	 // which popup I'm tracking
		}
		m_iTrackingState = iState;
	}
}

//////////////////
// Toggle state from home state to button-tracking and back
//
void CMenuBar::ToggleTrackButtonMode()
{
	ASSERT_VALID(this);
	if (m_iTrackingState == TRACK_NONE || m_iTrackingState == TRACK_BUTTON) {
		SetTrackingState(m_iTrackingState == TRACK_NONE ?
			TRACK_BUTTON : TRACK_NONE, 0);
	}
}

//////////////////
// Get button index before/after a given button
//
int CMenuBar::GetNextOrPrevButton(int iButton, BOOL bPrev)
{
	ASSERT_VALID(this);
	if (bPrev) {
		iButton--;
		if (iButton <0)
			iButton = GetButtonCount() - 1;
	} else {
		iButton++;
		if (iButton >= GetButtonCount())
			iButton = 0;
	}
	return iButton;
}

/////////////////
// This is to correct a bug in the system toolbar control: TB_HITTEST only
// looks at the buttons, not the size of the window. So it returns a button
// hit even if that button is totally outside the size of the window!
//
int CMenuBar::HitTest(CPoint p) const
{
	int iHit = CCJToolBar::HitTest(p);
	if (iHit>0) {
		CRect rc;
		GetClientRect(&rc);
		if (!rc.PtInRect(p)) // if point is outside window
			iHit = -1;			// can't be a hit!
	}
	return iHit;
}

//////////////////
// Load a different menu. The HMENU must not belong to any CMenu,
// and you must free it when you're done. Returns old menu.
//
HMENU CMenuBar::LoadMenu(HMENU hmenu)
{
	MBTRACEFN(_T("CMenuBar::LoadMenu\n"));
	UINT iPrevID=(UINT)-1;
	ASSERT(::IsMenu(hmenu));
	ASSERT_VALID(this);

	if (m_bAutoRemoveFrameMenu) {
		CFrameWnd* pFrame = GetParentFrame();
		if (::GetMenu(*pFrame)!=NULL) {
			// I would like to set the frame's menu to NULL now, but if I do, MFC
			// gets all upset: it calls GetMenu and expects to have a real menu.
			// So Instead, I post a message to myself. Because the message is
			// posted, not sent, I won't process it until MFC is done with all its
			// initialization stuff. (MFC needs to set CFrameWnd::m_hMenuDefault
			// to the menu, which it gets by calling GetMenu.)
			//
			PostMessage(MB_SET_MENU_NULL, (WPARAM)pFrame->GetSafeHwnd());
		}
	}
	HMENU hOldMenu = m_hmenu;
	m_hmenu = hmenu;

	// delete existing buttons
	int nCount = GetButtonCount();
	while (nCount--) {
		VERIFY(DeleteButton(0));
	}

	SetImageList(NULL);
//	SetButtonSize(CSize(0,0)); // This barfs in VC 6.0

	DWORD dwStyle = GetStyle();
	BOOL bModifyStyle = ModifyStyle(0, TBSTYLE_FLAT|TBSTYLE_TRANSPARENT);

	// add text buttons
	UINT nMenuItems = hmenu ? ::GetMenuItemCount(hmenu) : 0;

	for (UINT i=0; i < nMenuItems; i++) {
		TCHAR name[64];
		memset(name, 0, sizeof(name)); // guarantees double-0 at end
		if (::GetMenuString(hmenu, i, name, countof(name)-1, MF_BYPOSITION)) {
			TBBUTTON tbb;
			memset(&tbb, 0, sizeof(tbb));
			tbb.idCommand = ::GetMenuItemID(hmenu, i);

			// Because the toolbar is too brain-damaged to know if it already has
			// a string, and is also too brain-dead to even let you delete strings,
			// I have to determine if each string has been added already. Otherwise
			// in a MDI app, as the menus are repeatedly switched between doc and
			// no-doc menus, I will keep adding strings until somebody runs out of
			// memory. Sheesh!
			// 
			int iString = -1;
			for (int j=0; j<m_arStrings.GetSize(); j++) {
				if (m_arStrings[j] == name) {
					iString = j; // found it
					break;
				}
			}
			if (iString <0) {
				// string not found: add it
				iString = AddStrings(name);
				m_arStrings.SetAtGrow(iString, name);
			}

			tbb.iString = iString;
			tbb.fsState = TBSTATE_ENABLED;
			tbb.fsStyle = TBSTYLE_AUTOSIZE;
			tbb.iBitmap = -1;
			tbb.idCommand = i;
			VERIFY(AddButtons(1, &tbb));
		}
	}

	if (bModifyStyle)
		SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
	
	if (hmenu) {
		AutoSize();								 // size buttons
		RecomputeToolbarSize();				 // and menubar itself
	}
	return hOldMenu;
}

//////////////////
// Load menu from resource
//
HMENU CMenuBar::LoadMenu(LPCSTR lpszMenuName)
{
	return LoadMenu(::LoadMenu(AfxGetResourceHandle(), lpszMenuName));
}

//////////////////
// Set the frame's menu to NULL. WPARAM is HWND of frame.
//
LRESULT CMenuBar::OnSetMenuNull(WPARAM wp, LPARAM lp)
{
	HWND hwnd = (HWND)wp;
	ASSERT(::IsWindow(hwnd));
	::SetMenu(hwnd, NULL);
	return 0;
}

//////////////////
// Handle mouse click: if clicked on button, press it
// and go into main menu loop.
//
void CMenuBar::OnLButtonDown(UINT nFlags, CPoint pt)
{
	MBTRACEFN(_T("CMenuBar::OnLButtonDown\n"));
	ASSERT_VALID(this);
	int iButton = HitTest(pt);
	if (iButton >= 0 && iButton<GetButtonCount()) // if mouse is over a button:
		TrackPopup(iButton);								 //   track it
	else														 // otherwise:
		CCJToolBar::OnLButtonDown(nFlags, pt);	 //   pass it on...
}

//////////////////
// Handle mouse movement
//
void CMenuBar::OnMouseMove(UINT nFlags, CPoint pt)
{
	ASSERT_VALID(this);

	if (m_iTrackingState==TRACK_BUTTON) {

		// In button-tracking state, ignore mouse-over to non-button area.
		// Normally, the toolbar would de-select the hot item in this case.
		// 
		// Only change the hot item if the mouse has actually moved.
		// This is necessary to avoid a bug where the user moves to a different
		// button from the one the mouse is over, and presses arrow-down to get
		// the menu, then Esc to cancel it. Without this code, the button will
		// jump to wherever the mouse is--not right.

		int iHot = HitTest(pt);
		if (IsValidButton(iHot) && pt != m_ptMouse)
			SetHotItem(iHot);
		return;			 // don't let toolbar get it
	}
	m_ptMouse = pt; // remember point
	CCJToolBar::OnMouseMove(nFlags, pt);
}

//////////////////
// Window was resized: need to recompute layout
//
void CMenuBar::OnSize(UINT nType, int cx, int cy)
{
	CCJToolBar::OnSize(nType, cx, cy);
	RecomputeMenuLayout();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -