一、CBitmapButton存在的問題
在MFC中,要使用圖形按鈕,一般會選擇CBitmapButton類,使用CBitmapButton類可以設置按鈕的Normal、Selected、Focused和Disabled四種狀態的bmp圖像,這四副狀態圖像要求同尺寸大小,其中normal狀態圖片是必需提供的。常見調用代碼示例:
CBitmapButton m_bmpBtn;
m_bmpBtn.SubclassDlgItem(IDC_BUTTON1,this);//關聯控件
//CBitmapButton對象m_bmpBtn的LoadBitmaps函數加載程序內bmp資源。
m_bmpBtn.LoadBitmaps(IDB_BITMAP1,IDB_BITMAP2,IDB_BITMAP3,IDB_BITMAP4);
m_bmpBtn.SizeToContent();
遺憾的是:上述代碼中LoadBitmaps函數只可以加載程序內部bmp資源文件,不可以加載磁盤圖像文件,但有時我們又急需更改CBitmapButton 對象的按鈕狀態圖,比如界面皮膚動態切換時,就有可能碰到這種情況。如何才能讓CBitmapButton 對象動態加載狀態圖像呢?這裡給出一個解決方案。
二、解決思路分析
通過分析CBitmapButton發現,其四種狀態圖保存在四個CBitmap類型的成員變量中,其定義如下:
class CBitmapButton : public CButton
由於CBitmapButton的protected屬性成員變量普通外部函數無法直接訪問,因此我們定義一個其public繼承類CGetBitmaps,從而可以訪問這四個成員變量,CGetBitmaps類定義如下:
{
....
protected:
// all bitmaps must be the same size
CBitmap m_bitmap; // normal image (REQUIRED)
CBitmap m_bitmapSel; // selected image (OPTIONAL)
CBitmap m_bitmapFocus; // focused but not selected (OPTIONAL)
CBitmap m_bitmapDisabled; // disabled bitmap (OPTIONAL)
...
}
class CGetBitmaps : public CBitmapButton
{
CBitmapButton *btn;
public:
CGetBitmaps(CBitmapButton *button)
{
btn=button;
}
inline CBitmap * Nor(){ //normal image (REQUIRED)
return (CBitmap *)(PCHAR(btn)+(ULONG)(PCHAR (&m_bitmap)-PCHAR(this)));//not PTCHAR, butPCHAR
}
inline CBitmap * Sel(){ // selected image (OPTIONAL)
return (CBitmap *)(PCHAR(btn)+(ULONG)(PCHAR (&m_bitmapSel)-PCHAR(this)));//not PTCHAR, butPCHAR
}
inline CBitmap * Foc(){ // focused but not selected (OPTIONAL)
return (CBitmap *)(PCHAR(btn)+(ULONG)(PCHAR (&m_bitmapFocus)-PCHAR(this)));//not PTCHAR, butPCHAR
}
inline CBitmap * Dis(){ // disabled bitmap (OPTIONAL)
return (CBitmap *)(PCHAR(btn)+(ULONG)(PCHAR (&m_bitmapDisabled)-PCHAR(this)));//not PTCHAR, butPCHAR
}
};
增加了四個inline函數用來得到四副狀態圖對應的保存地址。在保持原CBitmapButton對象的不變情況下,我提供一個普通函數BOOL ChangeBitmapBtnImages(CBitmapButton &button,LPCTSTR lpszFilename)來更改CBitmapButton對象的按鈕狀態圖,該函數接受一個CBitmapButton引用對象和一個四狀態組合的bmp磁盤文件路徑名,如果成功設置返回TRUE,否則FALSE,該函數定義的核心代碼如下(詳細請看示例源代碼中changeBmp.cpp文件):
BOOL ChangeBitmapBtnImages(CBitmapButton &button,LPCTSTR lpszFilename)//
{
...
HBITMAP hbm = (HBITMAP) ::LoadImage (NULL, lpszFilename, IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE|LR_CREATEDIBSECTION);//動態加載磁盤bmp文件
if (hbm == NULL)
{
return FALSE;
}
src.Attach(hbm);
...
CGetBitmaps gbitmap(&button);//這裡調用我們的定義類
CBitmap * pbitmap[4];
...
BOOL Rz=TRUE;
for(int i=0;i<4;i++) //分割四副狀態圖
{
pbitmap[i]->CreateCompatibleBitmap(&srcDC,bmpWidth,bmpHeight);
memDC.SelectObject(pbitmap[i]);
if( !memDC.BitBlt(0,0,bmpWidth, bmpHeight, &srcDC,bmpWidth*i,0,SRCCOPY) )
{
Rz=FALSE;
break;
}
}
...
return Rz;
}
三、代碼示例
為了更好的理解,本文提供示例源代碼程序,運行界面如“圖一”。程序開始時,界面中的圖形按鈕加載了程序內部資源中的四副bmp狀態圖,可以點擊下面的“動態加載bmp文件”按鈕來選擇磁盤上一個四副狀態組合的bmp圖,加載成功以後圖形按鈕的按鈕狀態圖將被更改,再單擊圖形按鈕將看到狀態圖已經更改的效果。
圖一 示例程序運行效果圖
四、結束語
對於ChangeBitmapBtnImages函數,這裡把它當成一個獨立普通函數使用,當然也可以把它稍加修改放到CGetBitmaps中當成員函數使用,另外這裡的ChangeBitmapBtnImages加載的bmp磁盤文件是四種狀態組合的單個bmp文件,在此程序的基礎上讀者可以很容易的把它修改成加載四副單獨按鈕狀態的程序。
本文配套源碼