CxSkinButton是开源的换肤按钮控件,用起来也很方便。CxSkinButton提供的皮肤设置接口如下:
void SetSkin(UINT normal,UINT down, UINT over=0, UINT disabled=0, UINT focus=0,UINT mask=0,short drawmode=1,short border=1,short margin=4)
可以看到该接口必须输入一个个的状态位图ID,但是在实际中,美工将按钮的各个状态图放在一张图片中,上述接口就无法使用。针对这个问题, 可以在CxSkinButton的基础上,扩展一个新的类,增加一个新的皮肤设置接口。
继承类定义:
class CDvssButton :
public CxSkinButton
{
public:
CDvssButton(void);
~CDvssButton(void);
public:
//此处接口可以根据美工提供图片适当改变
void SetSkin(UINT nIDRes,UINT nIDMask = 0,short nDrawMode = 1,short nBorder = 1,short nMargin = 4,int nSmallImages = 7);
private:
void CopyBitmap(CBitmap* pDstBitmap,int nDstX,int nDstY,int nWidth,int nHeight,CBitmap* pSrcBitmap,int nSrcX,int nSrcY);
};
继承类实现函数:
void CDvssButton::SetSkin(UINT nIDRes,UINT nIDMask,short nDrawMode,short nBorder,short nMargin,int nSmallImages)
{
m_bNormal.DeleteObject();
m_bDown.DeleteObject();
m_bOver.DeleteObject();
m_bDisabled.DeleteObject();
m_bMask.DeleteObject();
m_bFocus.DeleteObject();
CBitmap bitmap;
bitmap.LoadBitmap(nIDRes);
int nWidth = GetBitmapWidth((HBITMAP)bitmap.m_hObject);
int nHeight = GetBitmapHeight((HBITMAP)bitmap.m_hObject);
//将大图片的各种状态图拷贝到对应的状态位图对象成员中,此处需根据美工提供的图片自己灵活调用
CopyBitmap(&m_bDisabled,0,0,nWidth/nSmallImages,nHeight,&bitmap,0,0);
CopyBitmap(&m_bNormal,0,0,nWidth/nSmallImages,nHeight,&bitmap,nWidth/nSmallImages,0);
CopyBitmap(&m_bDown,0,0,nWidth/nSmallImages,nHeight,&bitmap,nWidth/nSmallImages*2,0);
CopyBitmap(&m_bOver,0,0,nWidth/nSmallImages,nHeight,&bitmap,nWidth/nSmallImages*3,0);
bitmap.DeleteObject();
m_DrawMode=max(0,min(nDrawMode,2));
m_Border=nBorder;
m_FocusRectMargin=max(0,nMargin);
if (nIDMask>0){
m_bMask.LoadBitmap(nIDMask);
if (hClipRgn) DeleteObject(hClipRgn);
hClipRgn = CreateRgnFromBitmap(m_bMask,RGB(255,255,255));
if (hClipRgn){
SetWindowRgn(hClipRgn, TRUE);
CDC *pDC = GetDC();
if (pDC){
SelectClipRgn(pDC->GetSafeHdc(), hClipRgn);
ReleaseDC(pDC);
}
}
if (m_DrawMode==0){
SetWindowPos(NULL,0,0,GetBitmapWidth(m_bMask),
GetBitmapHeight(m_bMask),SWP_NOZORDER|SWP_NOMOVE);
}
}
}
//该函数可以实现将一张图片位图对象的指定位置,指定高,宽拷贝给另一位图对象
void CDvssButton::CopyBitmap(CBitmap* pDstBitmap,int nDstX,int nDstY,int nWidth,int nHeight,CBitmap* pSrcBitmap,int nSrcX,int nSrcY)
{
CDC SrcDC;
CDC DstDC;
SrcDC.CreateCompatibleDC(NULL);
DstDC.CreateCompatibleDC(NULL);
BITMAP bitmap;
pSrcBitmap->GetBitmap(&bitmap);
bitmap.bmWidth = nWidth;
bitmap.bmHeight = nHeight;
pDstBitmap->CreateBitmapIndirect(&bitmap);
//此处不要使用如下这种方法创建兼容位图,否则创建的位图格式只有黑白两色
//pDstBitmap->CreateCompatibleBitmap(&DstDC,nWidth,nHeight);
CBitmap* pOldSrcBitmap = SrcDC.SelectObject(pSrcBitmap);
CBitmap* pOldDstBitmap = DstDC.SelectObject(pDstBitmap);
DstDC.BitBlt(0,0,nWidth,nHeight,&SrcDC,nSrcX,nSrcY,SRCCOPY);
SrcDC.SelectObject(pOldSrcBitmap);
DstDC.SelectObject(pOldDstBitmap);
SrcDC.DeleteDC();
DstDC.DeleteDC();
}
如此一来,该按钮就可以实现对一张含有多种状态图图片的处理,上述代码,测试通过,可以直接使用。这里也可以直接修改CxSkinButton的源码,解决此问题。但CxSkinButton类大量的成员变量,成员函数都是保护成员,提供了扩展的便利,实现起来很快。