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

📄 headerbar.cpp

📁 实现类似wince系统自带顶部工具条
💻 CPP
字号:
// HeaderBarCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "resource.h"
#include "HeaderBar.h"

#include <afxpriv.h>

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

IMPLEMENT_DYNAMIC(CHeaderBarCtrl, CWnd)

#define CMD_SEPERATOR_COMMANDID		0

// helper function to get the number of buttons in the toolbar
static int GetButtonCount(HWND hwnd)
{
	ASSERT(IsWindow(hwnd));
	return SendMessage(hwnd, TB_BUTTONCOUNT,0,0);
}

// helper function to get the command id at the specified index.
static int CmdAtIndex(HWND hwnd, const int iIndex)
{
	ASSERT(IsWindow(hwnd));
	ASSERT(iIndex >= 0 && iIndex < GetButtonCount(hwnd));

	TBBUTTON tbb;
	VERIFY(SendMessage(hwnd, TB_GETBUTTON, (WPARAM)iIndex, (LPARAM)&tbb));

	return tbb.idCommand;
}

// Helper function to get the width of the button at the specified
// index.
static int GetButtonWidthAtIndex(HWND hwnd, const int iIndex)
{
	ASSERT(IsWindow(hwnd));
	
	CRect rc;
	VERIFY(SendMessage(hwnd, TB_GETITEMRECT, iIndex, (LPARAM)&rc));

	return rc.Width();
}

static void FillInBtnStruct(TBBUTTON* pBtn, const int iBmpIndex, const int iStrIndex, const int iIdCmd, const int iStyle, const DWORD dwData)
{
	ZeroMemory(pBtn, sizeof(TBBUTTON));

	pBtn->iBitmap = iBmpIndex;
	pBtn->iString = iStrIndex;
	pBtn->idCommand = iIdCmd;
	pBtn->fsState = TBSTATE_ENABLED;
	pBtn->fsStyle = iStyle;
	pBtn->dwData = dwData;
}

/////////////////////////////////////////////////////////////////////////////
// CHeaderBarCtrl

CHeaderBarCtrl::CHeaderBarCtrl()
{
}

CHeaderBarCtrl::~CHeaderBarCtrl()
{
	DestroyWindow();
}

// helper function to calculate the width
// of the seperator button and then set it
// so the left and right buttons are correctly 
// aligned to the left and right of the client
// window
void CHeaderBarCtrl::AdjustSeperatorButtonSize()
{
	const int iSeperatorIndex = CmdAtIndex(m_hWnd, 0) == CMD_SEPERATOR_COMMANDID ? 0 : 1;

// just some logic checking to show any problems
#ifdef _DEBUG
	// we have two or three buttons only
	// seperator and left or right dropdown
	// or seperator and left and right dropdown
	ASSERT(GetButtonCount(m_hWnd) == 2 || GetButtonCount(m_hWnd) == 3);
	switch (iSeperatorIndex)
	{
		case 0: 
		{
			// we know we have two buttons and know we second one must be the seperator, there is no third one
			// that is to say there is no left dropdown, only a right dropdown
			ASSERT(CmdAtIndex(m_hWnd, 1) != -1);
		}
		break;
		case 1: 
		{
			// we know we have two or three buttons and definatly a left button.
			// that is to say there is a left dropdown and possibly a right dropdown, though its not guaranteed
			ASSERT(CmdAtIndex(m_hWnd, 0) != -1);
		}
		break;
		default:
		{
			ASSERT(FALSE); // the seperator button is neither on the left nor the middle so problem
		}
	}
#endif

	// if the seperator button is the second button (at index 1) then get the width of the first button
	// otherwise the left button is missing so make it zero
	const int iLeftWidth = (iSeperatorIndex == 1) ? GetButtonWidthAtIndex(m_hWnd,0) : 0;

	// if the seperator button is the first button then the left button is missing so get the width of
	// the second dropdown (which is the right button),
	// so if we have three buttons we know we have a left and right, otherwise we must have
	// two buttons, in which case the second button is a drop down
	const int iRightWidth = (GetButtonCount(m_hWnd) == 3) ? GetButtonWidthAtIndex(m_hWnd, 2) : GetButtonWidthAtIndex(m_hWnd, 1);

	CRect rc;
	GetClientRect(&rc);

	const int iSeparatorWidth = rc.Width() - iLeftWidth - iRightWidth;

	// Set its size to be the width of the bar less the width of the left and right buttons
	TBBUTTONINFO tbiMiddle;
	tbiMiddle.cbSize = sizeof(TBBUTTONINFO);
	tbiMiddle.dwMask = TBIF_SIZE;
	tbiMiddle.cx = iSeparatorWidth;
	VERIFY(SendMessage(TB_SETBUTTONINFO, (WPARAM)CMD_SEPERATOR_COMMANDID, (LPARAM)&tbiMiddle));
}

// Adds a toolbar button to the left of the toolbar main window
BOOL CHeaderBarCtrl::AddLeftButton(const TBBUTTON& button)
{
	ASSERT(::IsWindow(m_hWnd));
	ASSERT(button.idCommand != CMD_SEPERATOR_COMMANDID);

	// There should be no buttons added or if there
	// is a button added it must be the right button
	// so implicitly the button at index 0 is the seperator button
	ASSERT(GetButtonCount(m_hWnd) == 1 || (GetButtonCount(m_hWnd) == 2 && CmdAtIndex(m_hWnd, 0) == CMD_SEPERATOR_COMMANDID));

	const BOOL bRet = SendMessage(TB_INSERTBUTTON, 0, (LPARAM)&button);

	if (bRet)
		AdjustSeperatorButtonSize();
	else
		ASSERT(FALSE); // failed to insert button so assert

	return bRet;
}

// Adds a toolbar button to the right of the toolbar main window
BOOL CHeaderBarCtrl::AddRightButton(const TBBUTTON& button)
{
	ASSERT(::IsWindow(m_hWnd));
	ASSERT(button.idCommand != CMD_SEPERATOR_COMMANDID);

	// There should be no buttons added or if there
	// is a button added it must be the left button
	// so implicitly the button at index 1 is the seperator button
	ASSERT(GetButtonCount(m_hWnd) == 1 || (GetButtonCount(m_hWnd) == 2 && CmdAtIndex(m_hWnd, 1) == CMD_SEPERATOR_COMMANDID));

	const BOOL bRet = SendMessage(TB_INSERTBUTTON, CmdAtIndex(m_hWnd, 0) == 0 ? 1 : 2, (LPARAM)&button);
	
	if (bRet)
		AdjustSeperatorButtonSize();
	else
		ASSERT(FALSE);

	return bRet;
}

// Adds a button to the left of the main toolbar window but the user specifies
// all the fields in the parameters
BOOL CHeaderBarCtrl::AddLeftButton(const int iBmpIndex, const int iStrIndex, const int iIdCmd, const int iStyle, const DWORD dwData)
{
	ASSERT(::IsWindow(m_hWnd));

	TBBUTTON btn;
	FillInBtnStruct(&btn, iBmpIndex, iStrIndex, iIdCmd, iStyle, dwData);
	return AddLeftButton(btn);
}

// Adds a button to the right of the main toolbar window but the user specifies
// all the fields in the parameters
BOOL CHeaderBarCtrl::AddRightButton(const int iBmpIndex, const int iStrIndex, const int iIdCmd, const int iStyle, const DWORD dwData)
{
	ASSERT(::IsWindow(m_hWnd));

	TBBUTTON btn;
	FillInBtnStruct(&btn, iBmpIndex, iStrIndex, iIdCmd, iStyle, dwData);
	return AddRightButton(btn);

}



BEGIN_MESSAGE_MAP(CHeaderBarCtrl, CWnd)
	//{{AFX_MSG_MAP(CHeaderBarCtrl)
	ON_WM_CREATE()
	ON_MESSAGE(WM_SIZEPARENT, OnSizeParent)
	ON_NOTIFY_REFLECT(TBN_DROPDOWN, OnDropDown)
	ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


void CHeaderBarCtrl::OnDropDown( NMHDR * pNotifyStruct, LRESULT* result )
{
	LPNMTOOLBAR lpnmtb = (LPNMTOOLBAR)pNotifyStruct;
	GetParent()->PostMessage(WM_COMMAND, MAKEWPARAM(lpnmtb->iItem,0), 0);
	
	*result = 0;
}

void CHeaderBarCtrl::OnCustomDraw( NMHDR * pNotifyStruct, LRESULT* result )
{
	// The most useful command, this removes the divider line
	// in the dropdowns.
	LPNMCUSTOMDRAW  lplvcd = (LPNMCUSTOMDRAW)pNotifyStruct;
	
	switch(lplvcd->dwDrawStage) 
	{
	case CDDS_PREPAINT :
		{
		(*result) = CDRF_NOTIFYITEMDRAW;
		return;
		}
	case CDDS_ITEMPREPAINT:
		{
		(*result) = CDRF_NOVERTBAR;
		return;
		}
	}
	
	*result = TRUE;
}

// Function to create the new toolb
BOOL CHeaderBarCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
	// The style must be set to custom erase and no top divider space,
	// anthing else is optional.
	dwStyle |= (CCS_NODIVIDER | TBSTYLE_CUSTOMERASE);
	// initialize common controls
	CWnd* pWnd = this;
	return pWnd->Create(TOOLBARCLASSNAME, _T("Header Bar Control"), dwStyle, rect, pParentWnd, nID);
}

// This helper function is called whenever windows needs to layuout
// windows in the main frame that are not part of the view.
// it uses this to reserve space for the control and tell
// the frame how much space is left for the view.
// This also moves the window if neccessary
LRESULT CHeaderBarCtrl::OnSizeParent(WPARAM, LPARAM lParam)
{
    AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;

	 // get the size of our header bar control
	 CRect rc;
	 GetClientRect(&rc);

	 // shrink the size of the main view to accomodate the
	 // header bar control.
	 lpLayout->rect.top += rc.Height();
	 lpLayout->rect.right = rc.Width();

	 lpLayout->sizeTotal.cy += rc.Height();
	 lpLayout->sizeTotal.cx = rc.Width();
	 lpLayout->bStretch = FALSE;

	 // If we are laying out the window
	 // then we move the header bar window
	 // to its new position. This is actually done
	 // in a defer window pos call so the changes are done
	 // once only when all the child windows have been 
	 // laid out.
    if (lpLayout->hDWP != NULL)
	 {
        AfxRepositionWindow(lpLayout, m_hWnd, &rc);
	 }

	 return 0;
}

// function to add a bitmap to the toolbar.
// note that this also calculates the size of the bitmap assuming
// the the width of the bitmap divided by the number of buttons
// is the width. Note that GetBitmpSize does not work
// on CE, so we need to call GetObject to get the actual size
// of the bitmap.
int CHeaderBarCtrl::AddBitmap(int nNumButtons, CBitmap* pBitmap)
{
	ASSERT(::IsWindow(m_hWnd));
	ASSERT(nNumButtons > 0);

	TBADDBITMAP tbab;
	tbab.hInst = NULL;
	tbab.nID = (UINT)pBitmap->GetSafeHandle();
	int ret = (int) ::SendMessage(m_hWnd, TB_ADDBITMAP, (WPARAM)nNumButtons, (LPARAM)&tbab);

	ASSERT(ret != -1);

	// once we have added the bitmap, set the bitmap dimensions
	BITMAP bmp;
	VERIFY(pBitmap->GetObject(sizeof(bmp), &bmp));
	const CSize sizeBmp(bmp.bmWidth / nNumButtons, bmp.bmHeight);

	VERIFY(SetBitmapSize(sizeBmp));

	return ret;
}

// The remaining functions are copies of the toolbar
// control functions from MFC and are just provided for
// completeness.
int CHeaderBarCtrl::AddBitmap(int nNumButtons, UINT nBitmapID)
{
	ASSERT(::IsWindow(m_hWnd));

	CBitmap bmp;
	VERIFY(bmp.LoadBitmap(nBitmapID));

	const int ret = AddBitmap(nNumButtons, &bmp);

	bmp.Detach();

	return ret;
}

int CHeaderBarCtrl::AddString(UINT nStringID)
{
	ASSERT(::IsWindow(m_hWnd));
	HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE((nStringID>>4)+1),
		RT_STRING);
	ASSERT(hInst != NULL);
	return (int)::SendMessage(m_hWnd, TB_ADDSTRING, (WPARAM)hInst, nStringID);
}

int CHeaderBarCtrl::OnCreate(LPCREATESTRUCT lpcs)
{
	if (CWnd::OnCreate(lpcs) == -1)
		return -1;

	SendMessage(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON),0);

	TBBUTTON btnEmpty = { -1 /*bitmap*/,CMD_SEPERATOR_COMMANDID /*command*/,TBSTATE_INDETERMINATE, TBSTYLE_AUTOSIZE, {0,0} /*reserved*/, 0 /*data*/,-1 /*string*/};
	VERIFY(SendMessage(TB_ADDBUTTONS, 1, (LPARAM)&btnEmpty));
	
	return 0;
}

BOOL CHeaderBarCtrl::EnableButton(int nID, BOOL bEnable)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_ENABLEBUTTON, nID, MAKELPARAM(bEnable, 0)); 
}

BOOL CHeaderBarCtrl::PressButton(int nID, BOOL bPress)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_PRESSBUTTON, nID, MAKELPARAM(bPress, 0)); 
}

BOOL CHeaderBarCtrl::HideButton(int nID, BOOL bHide)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_HIDEBUTTON, nID, MAKELPARAM(bHide, 0)); 
}

BOOL CHeaderBarCtrl::IsButtonEnabled(int nID) const
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONENABLED, nID, 0); 
}

BOOL CHeaderBarCtrl::IsButtonPressed(int nID) const
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONPRESSED, nID, 0); 
}

BOOL CHeaderBarCtrl::IsButtonHidden(int nID) const
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_ISBUTTONHIDDEN, nID, 0); 
}

BOOL CHeaderBarCtrl::SetState(int nID, UINT nState)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_SETSTATE, nID, MAKELPARAM(nState, 0)); 
}

int CHeaderBarCtrl::GetState(int nID) const
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (int) ::SendMessage(m_hWnd, TB_GETSTATE, nID, 0L); 
}


// lpszStrings are separated by zeroes, last one is marked by two zeroes
int CHeaderBarCtrl::AddStrings(LPCTSTR lpszStrings)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (int) ::SendMessage(m_hWnd, TB_ADDSTRING, 0, (LPARAM)lpszStrings); 
}

BOOL CHeaderBarCtrl::SetButtonSize(CSize size)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_SETBUTTONSIZE, 0, MAKELPARAM(size.cx, size.cy)); 
}

BOOL CHeaderBarCtrl::SetBitmapSize(CSize size)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (BOOL) ::SendMessage(m_hWnd, TB_SETBITMAPSIZE, 0, MAKELPARAM(size.cx, size.cy)); 
}

void CHeaderBarCtrl::SetOwner(CWnd* pWnd)
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	::SendMessage(m_hWnd, TB_SETPARENT, (WPARAM)pWnd->GetSafeHwnd(), 0L); 
}

UINT CHeaderBarCtrl::GetBitmapFlags() const
{ 
	ASSERT(::IsWindow(m_hWnd)); 
	return (UINT) ::SendMessage(m_hWnd, TB_GETBITMAPFLAGS, 0, 0L); 
}

⌨️ 快捷键说明

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