VC++界面编程之--实现工具栏自定义皮肤

工具栏的工作原理就是:首先在父窗口上创建一个子窗口,然后在一个子窗口上创建不同ID的按钮,当用户点击某个按钮时,就会以一个命令的方式通知父窗口:我被点击了。所以我沿着这个思路,制作了一个自定义皮肤的工具栏。

工具栏效果展现:

该工具栏包含了:①自定义背景图片、②自定义按钮图片、③自定义ToolTips、④动态增加按钮,等几个主要功能。当鼠标移动到某个工具栏按钮上上时,会动态切换按钮状态,并出现自定义的ToolTips。

VC++界面编程之--实现工具栏自定义皮肤

实现步骤一(创建)

创建一个名为CCustomCommandBar的子窗口,指定窗口类型为:WS_CHILD | WS_VISIBLE即可。

class CCustomCommandBar	: public CWindowImpl<CCustomCommandBar>
创建函数:

// Create command bar.
	HWND Create(const HWND wndParent, const UINT nID)
	{
		if (::IsWindow(wndParent) && nID > 0)
		{
			m_wndParent = wndParent;
			CRect rc(0, 0, 1, 1);
			return CWindowImpl<CCustomCommandBar>::Create(wndParent, rc, _T(""), WS_CHILD | WS_VISIBLE, 0, nID);
		}

		ATLASSERT(FALSE);
		return NULL;
	}

实现步骤二(设置工具栏背景)

找一张PNG图片,然后用其来做工具栏的背景,我没有刻意的去指定背景图片尺寸,一定要精确的与预定的工具栏吻合。而是找了一张较大的图,进行部分裁切。这样既可以保证动态增加一些按钮后,图像不失真。

VC++界面编程之--实现工具栏自定义皮肤

	// Load background image.
	BOOL LoadBackgroundImage(const UINT nImageID)
	{
		m_Lock.Lock();

		m_imgBack.Load_Image(nImageID, _T("PNG"));
		if (m_imgBack.m_pImage != NULL)
		{
			m_Lock.Unlock();
			return TRUE;
		}

		m_Lock.Unlock();
		ATLASSERT(FALSE);
		return FALSE;
	}
工具栏进行重绘只是进行简单的贴图,而工具栏尺寸,将由按钮的数量决定。

	// Draw background image when got WM_PAINT message.
	void DoPaint(Graphics& g)
	{
		m_Lock.Lock();
		if (m_imgBack.m_pImage != NULL)
		{
			g.DrawImage(m_imgBack.m_pImage, 0, 0);
		}
		m_Lock.Unlock();
	}
实现步骤三(添加按钮)

由于按钮是由工具栏动态创建的,所以只需传进按钮的ID、图片的ID并记录好创建的按钮顺序即可。当创建好按钮后,就重新计算每个按钮的位置,并重置工具栏的大小。

	// Insert button.
	BOOL InsertButton(const UINT nButtonID, const UINT nImageID, const int nImageNum, 
		const BUTTONIMAGEINDEX BtnImgIndex, const CString& strToolTip)
	{
		if (IsWindow() && nButtonID > 0 && nImageID > 0 && nImageNum > 0)
		{
			// First, create button.
			CCustomButton* pButton	= new CCustomButton();
			HWND wndButton			= pButton->Create(m_hWnd, nButtonID);
			ATLASSERT(::IsWindow(wndButton));
			pButton->LoadBitmap(nImageID, nImageNum);
			pButton->SetImages(BtnImgIndex.nNormal, BtnImgIndex.nSelected, BtnImgIndex.nHot, BtnImgIndex.nDisable);
			pButton->SetToolTipText(strToolTip);

			// Second, record created button info.
			BUTTONINFO* pBtnInfo	= (BUTTONINFO*)malloc( sizeof(BUTTONINFO) );
			pBtnInfo->nID			= nButtonID;
			pBtnInfo->pButton		= pButton;
			m_szButtons.Add(pBtnInfo);

			// Lastly, move button and record button position.
			MoveButtons();
			return TRUE;
		}

		ATLASSERT(FALSE);
		return FALSE;
	}
实现步骤四(计算工具栏尺寸并移动按钮)
根据每个按钮的间隔计图片宽度,计算工具栏的长度。然后根据按钮图片的高度,来计算工具栏的高度。计算完成后,先重置工具栏的尺寸,然后再依次移动按钮。

重置工具栏尺寸:

	// Move and record all buttons to specified position.
	void MoveButtons()
	{
		// First, Calculate all buttons position.
		for (int nIndex = 0; nIndex < m_szButtons.GetSize(); ++nIndex)
		{
			CRect rcPos;
			m_szButtons[nIndex]->pButton->GetClientRect(&rcPos);

			int X = 0;
			int Y = m_nVerSpace;
			
			// calculate first button.
			if (0 == nIndex)
			{
				X = m_nHorSpace;
			}
			// calculate left button X position via previous button.
			else
			{
				X = m_szButtons[nIndex - 1]->rcPos.right + m_nBtnSpace;
			}

			rcPos.MoveToXY(X, Y);
			m_szButtons[nIndex]->rcPos = rcPos;
		}

		// Second, resize command bar window via all buttons position.
		ResizeCommandBar();

		// Lastly, move buttons.
		for (int nIndex = 0; nIndex < m_szButtons.GetSize(); ++nIndex)
		{
			m_szButtons[nIndex]->pButton->MoveWindow(m_szButtons[nIndex]->rcPos, FALSE);
		}
	}
移动按钮:

	// Resize command bar via buttons‘ position.
	BOOL ResizeCommandBar()
	{
		int nHeight = m_nVerSpace * 2 + m_szButtons[0]->rcPos.Height();
		// Calculate width via last button‘s position.
		int nWidth	= m_szButtons[m_szButtons.GetSize() - 1]->rcPos.right + m_nHorSpace;

		if (nHeight > 0 && nWidth > 0)
		{
			ResizeClient(nWidth, nHeight);
			return TRUE;
		}

		ATLASSERT(FALSE);
		return FALSE;
	}
实现步骤五(为父窗口设置点击消息反馈)

我们可以使用WM_COMMAND来通知父窗口:工具栏某个按钮被点击了。

	BEGIN_MSG_MAP(CCustomCommandBar)
		MESSAGE_HANDLER(WM_COMMAND, OnCommand)
		REFLECT_NOTIFICATIONS()
	END_MSG_MAP()

	LRESULT OnCommand(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
	{
		if( lParam != 0 && ::GetParent((HWND) lParam) == m_hWnd ) 
		{
			::SendMessage(GetParent(), uMsg, wParam, lParam);
		}
		return 0;
	}
小结:

类似工具栏这些控件,比如CReBar,都可以用子窗口的形式进行制作。这样做的好处就是:相对比较简单,不需要大费周章的去控制CToolBar原有的一些自绘方法。并且可以增加一些自定义元素在里面。

下载链接:

http://download.csdn.net/detail/renstarone/6973195

VC++界面编程之--实现工具栏自定义皮肤,布布扣,bubuko.com

VC++界面编程之--实现工具栏自定义皮肤

上一篇:lua继承c++类


下一篇:计算最少钱币数C++程序代码。