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

来源:互联网 发布:php开发实例大全 pdf 编辑:程序博客网 时间:2024/05/18 02:56

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

工具栏效果展现:

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


实现步骤一(创建)

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


// 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

0 0
原创粉丝点击