应用:m_1.LoadBitmaps(IDB_LOGIN,5, 5, 5, 5, 4 );
按钮的五种状态:
Normal状态,就是按钮一开始显示时的样子。
Over状态,鼠标指针移动到按钮上面时按钮显示的样子。
Down状态,按下按钮时显示的样子。
Focus状态,按钮按下后松开的样子,例如标准按钮按下松开之后会看到按钮内部有一个虚线框。
Disable状态,当然就是按钮被设置成无效的时候的样子啦。
(
UINT id, int count ,
int TopHeight, int BottomHeight, int LeftWidth, int RightWidth
)
{
m_TopHeight = TopHeight;
m_BottomHeight = BottomHeight;
m_LeftWidth = LeftWidth;
m_RightWidth = RightWidth;
m_RcId = id; // Resource ID
m_NumofPics = count;
CBitmap bmp;
if( !bmp.LoadBitmap(id) ) return false;
if( !InitBitmap( bmp, NormalBitmap, 0, count ) ) return false;
if( !InitBitmap( bmp, SelectBitmap, 1, count ) ) return false;
if( !InitBitmap( bmp, DisableBitmap,2, count ) ) return false;
if( !InitBitmap( bmp, FocusBitmap, 3, count ) ) return false;
bmp.DeleteObject();
return true;
}
bool CWBButton::InitBitmap( CBitmap & src, CBitmap & dist, int index, int count ) //其中src是bmp为已知,dist为未知,index=0,1、2、3 count=5
{
CDC * pDC = GetDC(); //得到该button的DC指针
CDC memDC;
memDC.CreateCompatibleDC(pDC); //将内存DC memDC与pDC相关联
CDC srcDC;
srcDC.CreateCompatibleDC(pDC); //将内存DC srcDC与pDC相关联
CBitmap* pOldBitmap1;
pOldBitmap1 = srcDC.SelectObject(&src); //srcDC选择 src bmp位图
BITMAP bmpinfo;
src.GetBitmap(&bmpinfo); //获得src bmp位图的大小
int bmpWidth = bmpinfo.bmWidth / count; //得到按钮一种状态的位图的宽
int bmpHeight = bmpinfo.bmHeight; //得到按钮一种状态的位图的高
int orix = bmpWidth * index;
CRect rc;
GetClientRect(rc); //得到该按钮的客户尺寸{top=0 bottom=21 left=0 right=75}
CBitmap* pOldBitmap2;
dist.DeleteObject();
dist.CreateCompatibleBitmap(pDC,rc.Width(),rc.Height()); //将未知的dist位图与pDC相关联 这是对未知位图绘图的一种方法
pOldBitmap2 = memDC.SelectObject(&dist);
// lefttop,leftbottom,righttop,rightbottom
if( !memDC.BitBlt(0,0,m_LeftWidth, m_TopHeight, &srcDC,orix,0,SRCCOPY) ) return false; //先画左上角5*5大小目的区域
if( !memDC.BitBlt(0,rc.bottom - m_BottomHeight,m_LeftWidth, m_BottomHeight,
&srcDC,orix,bmpHeight - m_BottomHeight,SRCCOPY) ) return false; //再画左下角5*5大小目的区域
if( !memDC.BitBlt(rc.right - m_RightWidth, 0 ,m_RightWidth, m_TopHeight,
&srcDC,orix + bmpWidth - m_RightWidth,0,SRCCOPY) ) return false; //再画右上角4*5大小目的区域
if( !memDC.BitBlt(rc.right - m_RightWidth,rc.bottom - m_BottomHeight,m_RightWidth,m_BottomHeight,
&srcDC,orix + bmpWidth - m_RightWidth,bmpHeight - m_BottomHeight,SRCCOPY) ) return false; //再画右下角4*5大小目的区域
// entireimage
memDC.StretchBlt(m_LeftWidth,
m_TopHeight,
rc.Width() - ( m_LeftWidth + m_RightWidth ) ,
rc.Height() - ( m_TopHeight + m_BottomHeight) ,
&srcDC,
orix + m_LeftWidth,
m_TopHeight,
bmpWidth - ( m_LeftWidth + m_RightWidth ) ,
bmpHeight - ( m_TopHeight + m_BottomHeight ) ,SRCCOPY); //再拉伸画中间区域
// topbar,bottombar( Stretch )
memDC.StretchBlt(m_LeftWidth,0, rc.Width() - (m_LeftWidth + m_RightWidth), m_TopHeight,
&srcDC,orix + m_LeftWidth, 0, bmpWidth - ( m_LeftWidth + m_RightWidth) , m_TopHeight,SRCCOPY); //再拉伸画中间区域的上部
memDC.StretchBlt(m_LeftWidth, rc.bottom - m_BottomHeight, rc.Width() - ( m_LeftWidth + m_RightWidth), m_BottomHeight,
&srcDC,orix + m_LeftWidth,bmpHeight - m_BottomHeight,bmpWidth - ( m_LeftWidth + m_RightWidth) , m_BottomHeight,SRCCOPY ); //再拉伸画中间区域的下部
// sidebar ( STretch? )
memDC.StretchBlt(0,m_TopHeight,m_LeftWidth,rc.bottom - m_TopHeight - m_BottomHeight ,
&srcDC, orix,m_TopHeight, m_LeftWidth, bmpHeight - ( m_TopHeight + m_BottomHeight ) ,SRCCOPY); //在拉伸画两边
memDC.StretchBlt(rc.right - m_RightWidth ,m_TopHeight,m_RightWidth,rc.bottom - m_TopHeight - m_BottomHeight ,
&srcDC, orix + bmpWidth - m_RightWidth,m_TopHeight, m_RightWidth, bmpHeight - m_TopHeight - m_BottomHeight ,SRCCOPY);
srcDC.SelectObject(pOldBitmap1);
memDC.SelectObject(pOldBitmap2);
ReleaseDC(pDC);
ReleaseDC(&srcDC);
ReleaseDC(&memDC);
m_State = FileLoaded;
return true;
} //该函数的整个过程相当于将src位图拉伸到dist中,通过两个内存DC完成;
在主对话框初始化时将按钮图片加载完后,主对话框完成初始化后响应WM_PAINT消息调用OnPaint()函数,主对话框在绘图时发现按钮为自绘,便调用:
void CWBButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
CDC *xdc = CDC::FromHandle(lpDrawItemStruct->hDC); //得到按钮控件的dc指针
// xdc.Attach( lpDrawItemStruct->hDC );
CRect rc;
GetClientRect(rc);
CMemDC dc(xdc,rc); //一个用户自己定义的类 派生于CDC 相当于一个有填充的内存dc
UINT state = lpDrawItemStruct->itemState ;
bool IsDisable = false;
if (state & ODS_FOCUS)
{
DrawBitmap( &dc, focus );
if (state & ODS_SELECTED)
{
DrawBitmap( &dc, select );
rc.left += 5;
}
}
else if (state & ODS_DISABLED)
{
IsDisable = true;
DrawBitmap( &dc, disable );
}else{
DrawBitmap( &dc, normal );
}
int imode = dc.SetBkMode(TRANSPARENT);
CFont *pOldFnt = dc.SelectObject(m_pFnt);
COLORREF oldColor;
if(IsDisable)
oldColor = dc.SetTextColor( GetSysColor(COLOR_GRAYTEXT) );
else
oldColor = dc.SetTextColor( m_pFnt->GetFontColor() );
CString txt;
GetWindowText(txt);
dc.DrawText(txt,rc,DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dc.SetTextColor( oldColor );
dc.SelectObject(pOldFnt);
dc.SetBkMode(imode );
}
typedef struct tagDRAWITEMSTRUCT { UINT CtlType; 自绘控件类型 UINT CtlID; 控件ID(不适用于菜单控件) UINT itemID; UINT itemAction; UINT itemState; HWND hwndItem; HDC hDC; RECT rcItem; DWORD itemData; } DRAWITEMSTRUCT;
在WBButton.h中
class CMemDC : public CDC {
private:
CBitmap* m_bitmap;
CBitmap* m_oldBitmap;
CDC* m_pDC;
CRect m_rcBounds;
public:
CMemDC(CDC* pDC, const CRect& rcBounds) : CDC()
{
CreateCompatibleDC(pDC);
m_bitmap = new CBitmap;
m_bitmap->CreateCompatibleBitmap(pDC, rcBounds.Width(), rcBounds.Height());
m_oldBitmap = SelectObject(m_bitmap);
m_pDC = pDC;
m_rcBounds = rcBounds;
//For some reason the background color is not correct,
//so we use the button face color.
DWORD color = ::GetSysColor( COLOR_BTNFACE );
CBrush bkg(color);
FillRect(rcBounds, &bkg);
}
~CMemDC()
{
m_pDC->BitBlt(m_rcBounds.left, m_rcBounds.top, m_rcBounds.Width(), m_rcBounds.Height(),
this, m_rcBounds.left, m_rcBounds.top, SRCCOPY);
SelectObject(m_oldBitmap);
if (m_bitmap != NULL)
{
delete m_bitmap;
}
DeleteObject(m_bitmap);
}
CMemDC* operator->() {
return this;
}
};
#endif
void CWBButton::DrawBitmap( CDC * pDC, int mode )
{
if( m_State < FileLoaded ) return;
CRect rc;
GetClientRect(rc);
COLORREF crOldBack = pDC->SetBkColor(RGB(255,255,255));
COLORREF crOldText = pDC->SetTextColor(RGB(0,0,0));
CDC dcImage, dcTrans;
// Create two memory dcs for the image and the mask
dcImage.CreateCompatibleDC(pDC);
dcTrans.CreateCompatibleDC(pDC);
// Select the image into the appropriate dc
CBitmap* pOldBitmapImage;
switch(mode)
{
case normal:
pOldBitmapImage = dcImage.SelectObject(&NormalBitmap);
break;
case select:
pOldBitmapImage = dcImage.SelectObject(&SelectBitmap);
break;
case focus:
pOldBitmapImage = dcImage.SelectObject(&FocusBitmap);
break;
case disable:
pOldBitmapImage = dcImage.SelectObject(&DisableBitmap);
break;
default:
return;
}
// Create the mask bitmap
CBitmap bitmapTrans;
int nWidth = rc.Width();
int nHeight = rc.Height();
bitmapTrans.CreateBitmap(nWidth, nHeight, 1, 1, NULL);
// Select the mask bitmap into the appropriate dc
CBitmap* pOldBitmapTrans = dcTrans.SelectObject(&bitmapTrans);
// Build mask based on transparent colour
dcImage.SetBkColor(m_BkColor);
dcTrans.BitBlt(0, 0, nWidth, nHeight, &dcImage, 0, 0, SRCCOPY);
// Do the work - True Mask method - cool if not actual display
pDC->BitBlt(0, 0, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
pDC->BitBlt(0, 0, nWidth, nHeight, &dcTrans, 0, 0, SRCAND);
pDC->BitBlt(0, 0, nWidth, nHeight, &dcImage, 0, 0, SRCINVERT);
// Restore settings
dcImage.SelectObject(pOldBitmapImage);
dcTrans.SelectObject(pOldBitmapTrans);
pDC->SetBkColor(crOldBack);
pDC->SetTextColor(crOldText);
}