控件按鈕應該是使用最頻繁的控件了。我感覺沒有之一。
但是MFC的常規按鈕限制很多,功能基本不能滿足要求。以前使用很廣的CButtonST類倒是個選擇,但那個好像是基於VC6.0弄的,不清楚在VS2010上使用情況怎麼樣。正好,VS2010提供了一個CMFCButton類,比Button做了很多強化。就選擇直接使用。
基本的用法和CButton是一樣的,只是要注意一點,不要在控件工具中拖MFC Button Control到對話框或者什麼其他地方,這裏在編譯的時候好像會出問題。要用Button Control,然後定義控件類型之後,手動去修改類。
在這裏使用CMFCButton主要是爲了實現加載圖片透明化。
CMFCButton的使用,這個例子裏面基本上都有展示。安裝了VS2010的可以在Microsoft Visual Studio 10.0\Samples\2052目錄下找到對應的源碼。當然裏面很多例子,要用的心思慢慢找。或者直接到 去下載也是可以的,我把這個工程摘出來了。
這裏我就細說下圖片透明化的問題。下面是加載圖片的細節,這裏可以看到,CMFCButton是可以直接加載png格式的圖片的,這點很重要,下面會講到。
m_Button.SetImage(IDB_BTN1_32, IDB_BTN1_HOT_32);
void CMFCButton::SetImage(UINT uiBmpResId, UINT uiBmpHotResId, UINT uiBmpDsblResID)
{
SetImageInternal(uiBmpResId, uiBmpHotResId, FALSE /* Not checked */, uiBmpDsblResID);
}
void CMFCButton::SetImageInternal(UINT uiBmpResId, UINT uiBmpHotResId, BOOL bChecked, UINT uiBmpDsblResID)
{
ClearImages(bChecked);
if (uiBmpResId == 0)
{
return;
}
HBITMAP hbmp = ButtonLoadBitmap(uiBmpResId);
HBITMAP hbmpHot = ButtonLoadBitmap(uiBmpHotResId);
HBITMAP hbmpDisabled = ButtonLoadBitmap(uiBmpDsblResID);
SetImageInternal(hbmp, TRUE /* AutoDestroy */, hbmpHot, FALSE, bChecked, hbmpDisabled);
}
static HBITMAP __stdcall ButtonLoadBitmap(UINT uiBmpResId)
{
if (uiBmpResId == 0)
{
return NULL;
}
LPCTSTR lpszResourceName = MAKEINTRESOURCE(uiBmpResId);
ENSURE(lpszResourceName != NULL);
HBITMAP hbmp = NULL;
// Try to load PNG image first:
CPngImage pngImage;
if (pngImage.Load(lpszResourceName))
{
hbmp = (HBITMAP) pngImage.Detach();
}
else
{
HINSTANCE hinstRes = AfxFindResourceHandle(lpszResourceName, RT_BITMAP);
if (hinstRes == NULL)
{
return NULL;
}
UINT uiLoadImageFlags = LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS;
hbmp = (HBITMAP) ::LoadImage(hinstRes, lpszResourceName, IMAGE_BITMAP, 0, 0, uiLoadImageFlags);
}
return hbmp;
}
實際上,你隨意加載圖片基本是沒辦法透明化的,那個白的或者黑的邊框很影響感官的。
void CMFCButton::SetImageInternal(HBITMAP hBitmapCold, BOOL bAutoDestroy, HBITMAP hBitmapHot, BOOL bMap3dColors, BOOL bChecked, HBITMAP hBitmapDisabled)
{
ClearImages(bChecked);
if (hBitmapCold == NULL)
{
return;
}
const int nCount = hBitmapDisabled == NULL ? 2 : 3;
for (int i = 0; i < nCount; i++)
{
HBITMAP hBitmap = (i == 0) ? hBitmapCold :(i == 1) ? hBitmapHot : hBitmapDisabled;
CMFCToolBarImages& image = bChecked ?((i == 0) ? m_ImageChecked :(i == 1) ? m_ImageCheckedHot : m_ImageCheckedDisabled) :
((i == 0) ? m_Image :(i == 1) ? m_ImageHot : m_ImageDisabled);
if (hBitmap == NULL)
{
break;
}
BITMAP bmp;
::GetObject(hBitmap, sizeof(BITMAP), (LPVOID) &bmp);
BOOL bMap3dColorsCurr = bMap3dColors ||(bmp.bmBitsPixel > 8 && bmp.bmBitsPixel < 32);
BOOL bAlpha = !bMap3dColors && bmp.bmBitsPixel == 32 && CMFCToolBarImages::Is32BitTransparencySupported();
if (i == 0)
{
m_sizeImage.cx = bmp.bmWidth;
m_sizeImage.cy = bmp.bmHeight;
}
else
{
// Hot and cold bitmaps should have the same size!
ASSERT(m_sizeImage.cx == bmp.bmWidth);
ASSERT(m_sizeImage.cy == bmp.bmHeight);
}
if (bAlpha)
{
CMFCToolBarImages::PreMultiplyAlpha(hBitmap, TRUE);
}
image.SetImageSize(CSize(bmp.bmWidth, bmp.bmHeight));
image.SetTransparentColor(bMap3dColorsCurr ? RGB(192, 192, 192) : bAlpha ?(COLORREF) -1 : afxGlobalData.clrBtnFace);
image.AddImage(hBitmap, TRUE);
}
if (bAutoDestroy)
{
if (hBitmapHot != NULL)
{
::DeleteObject(hBitmapHot);
}
if (hBitmapCold != NULL)
{
::DeleteObject(hBitmapCold);
}
if (hBitmapDisabled != NULL)
{
::DeleteObject(hBitmapDisabled);
}
}
}
這段代碼裏面可以很清楚的看到那個關於透明化的處理,但是有個要求圖片必須是32位的需求。一般的BMP格式就是24位,是沒辦法滿足要求的,這裏既是png格式圖片施展地方了。因爲png格式好像默認就是32位的。