您的位置:首页 > 编程语言 > C语言/C++

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

2014-02-28 11:33 477 查看
工具栏的工作原理就是:首先在父窗口上创建一个子窗口,然后在一个子窗口上创建不同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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: