1. 程式人生 > >CBitmapButton類使用注意事項(主要是AutoLoad)

CBitmapButton類使用注意事項(主要是AutoLoad)

1、MFC有一個位圖按鈕類,即為CBitmapButton,能夠實現簡單的按鈕貼圖美化;但是長久沒有使用,今天就遇到一些問題:主要就是CBitmapButton::AutoLoad這個函式的使用,總是出錯,無法正確的載入圖片;現在將需要注意的問題貼出來,以作備份。

2、首先,說明以下不用AutoLoad的初始化方法,我在VS2010下測試成功,完全可以用類嚮導新增一個CBitmapButton型的控制元件變數(即在DoDataExchange關聯控制元件與變數)而不用手動呼叫SubclassDlgItem函式。只需要將預先匯入的點陣圖載入到按鈕類變數中就行了,具體如下:

(1)在對話方塊上放置一個按鈕,修改其自繪(Owner Draw)屬性

為TRUE;

(2)利用類嚮導為該按鈕關聯一個控制元件變數m_ctlBtn;

(3)在按鈕控制元件所在的對話方塊類的OnInitDialog函式中新增載入圖片的程式碼:

m_ctlBtn.LoadBitmaps(IDB_UP, IDB_DOWN, IDB_FOCUS, IDB_DISABLE);
m_ctlBtn.SizeToContent();// 根據載入的圖片,調整按鈕大小

(4)關於LoadBitmaps函式,只有第一個引數(即按鈕正常狀態下的點陣圖資源ID)是必須的,其它引數可以不設:

BOOL LoadBitmaps( UINT nIDBitmapResource, UINT nIDBitmapResourceSel
= 0, UINT nIDBitmapResourceFocus = 0, UINT nIDBitmapResourceDisabled = 0 );
(5)OK,這樣就行了

3、現在在說用AutoLoad函式載入圖片,以及相應的注意點:

(1)關於AutoLoad函式,可以先看一下它的實現程式碼:

// Autoload will load the bitmap resources based on the text of
//  the button
// Using suffices "U", "D", "F" and "X" for up/down/focus/disabled
BOOL CBitmapButton::AutoLoad(UINT nID, CWnd* pParent)
{
	// first attach the CBitmapButton to the dialog control
	if (!SubclassDlgItem(nID, pParent))
		return FALSE;

	CString buttonName;
	GetWindowText(buttonName);
	ASSERT(!buttonName.IsEmpty());      // must provide a title

	LoadBitmaps(buttonName + _T("U"), buttonName + _T("D"),
	  buttonName + _T("F"), buttonName + _T("X"));

	// we need at least the primary
	if (m_bitmap.m_hObject == NULL)
		return FALSE;

	// size to content
	SizeToContent();
	return TRUE;
}
(2)可以看到,在AutoLoad函式中先呼叫SubclassDlgItem關聯控制元件,所以我們就不能使用類嚮導關聯控制元件了,具體來說就是在對話方塊類的DoDataExchange函式中的DDX_Control(... ...)會與此處的SubclassDlgItem衝突,如果一定要用類嚮導,只要將響應的DDX_Control語句刪除就行了;

(3)接著繼續看AutoLoad的實現程式碼,也就是獲取按鈕文字(Caption),然後呼叫LoadBitmaps函式載入圖片;

即LoadBitmaps的引數是根據按鈕文字加上一個字母來確定的;

(4)按鈕的文字,即為屬性視窗中的Caption內容;按照這樣說來,是不是隻要將資源對話方塊中相應點陣圖的ID改為Caption中的內容加上一個字母就行了呢?答案是不行的。很多人都會犯這個錯誤,我一開始也犯了這個錯誤,糾結了好一會。

(5)原因是AutoLoad函式中呼叫的LoadBitmaps函式並不是前面提到的那個以點陣圖ID為引數的函式,仔細想一想,Caption中設定的是一個字串,然後在這個字串後面加一個字母,依然是一個字串;而控制元件的ID其實只是一個整數。顯然AutoLoad中的LoadBitmaps有一個過載函式:

BOOLLoadBitmaps(LPCTSTR lpszBitmapResource,LPCTSTR lpszBitmapResourceSel =NULL,LPCTSTR lpszBitmapResourceFocus =NULL,LPCTSTR lpszBitmapResourceDisabled =NULL);

(6)接下來看一下這個函式的實現:

// LoadBitmaps will load in one, two, three or all four bitmaps
// returns TRUE if all specified images are loaded
BOOL CBitmapButton::LoadBitmaps(LPCTSTR lpszBitmapResource,
	LPCTSTR lpszBitmapResourceSel, LPCTSTR lpszBitmapResourceFocus,
	LPCTSTR lpszBitmapResourceDisabled)
{
	// delete old bitmaps (if present)
	m_bitmap.DeleteObject();
	m_bitmapSel.DeleteObject();
	m_bitmapFocus.DeleteObject();
	m_bitmapDisabled.DeleteObject();

	if (!m_bitmap.LoadBitmap(lpszBitmapResource))
	{
		TRACE(traceAppMsg, 0, "Failed to load bitmap for normal image.\n");
		return FALSE;   // need this one image
	}
	BOOL bAllLoaded = TRUE;
	if (lpszBitmapResourceSel != NULL)
	{
		if (!m_bitmapSel.LoadBitmap(lpszBitmapResourceSel))
		{
			TRACE(traceAppMsg, 0, "Failed to load bitmap for selected image.\n");
			bAllLoaded = FALSE;
		}
	}
	if (lpszBitmapResourceFocus != NULL)
	{
		if (!m_bitmapFocus.LoadBitmap(lpszBitmapResourceFocus))
			bAllLoaded = FALSE;
	}
	if (lpszBitmapResourceDisabled != NULL)
	{
		if (!m_bitmapDisabled.LoadBitmap(lpszBitmapResourceDisabled))
			bAllLoaded = FALSE;
	}
	return bAllLoaded;
}

(7)可以看到最終呼叫的是CBitmap類的成員函式LoadBitmap載入圖片的,但是CBitmap類下的該函式也有兩個過載:
BOOL LoadBitmap (
LPCTSTR lpszResourceName );

BOOL LoadBitmap (
UINT nIDResource );

(8)到此問題是清楚了,但是關於以LPCTSTR 型資料為引數LoadBitmap函式實際上引數並不是實際的檔案路徑,許多人可能都看到過,說CBitmap::LoadBitmap不能直接載入硬碟上的檔案,譬如這樣是不行的(雖然程式碼並不報錯):

CBitmap oBitmap;
oBitmap.LoadBitmap(_T("D://test.bmp"));

(9)實際上這裡的引數依然是類似ID號的一種資源序號,只不過以字串的形式來表示,但是卻又不是簡單的從ID號轉化而來的,因為本文已經扯得比較遠,而且這個問題事實上還有許多內容,本文就不再深入下去了;下面迴歸主題,述說如何使用AutoLoad載入圖片。

4、使用AutoLoad載入圖片的步驟:

(1)同樣,在對話方塊上新增一個按鈕,更改其自繪屬性;

(2)手動新增一個CBitmapButton型的成員變數m_bmpBtn;

(3)關鍵步驟:點陣圖資源、按鈕ID 和 按鈕Caption的命名,命名規則如下:

按鈕ID:IDC_BTN_TEST_

按鈕Caption:BTN_TETST_

點陣圖ID(注意,包含分號)"TEST_U""TEST_D""TEST_F""TEST_X"

5、注意點:

(1)按鈕Caption是根據按鈕ID設定的:

a、若按鈕ID中有字元”_“,則以按鈕ID中第一個”_“字元後面的所有字串為按鈕Caption;

b、若按鈕ID中無字元”_“,則以ID名為按鈕Caption。

eg1:若按鈕ID為:IDC_BUTTON_UP    則按鈕Caption為:BUTTON_UP

eg2:若按鈕ID為:IDC_BTN_DOWN按鈕Caption為:BTN_DOWN

eg3:若按鈕ID為:BTN_FOCUS則按鈕Caption為:FOCUS

eg4:若按鈕ID為:DISABLE則按鈕Caption為:DISABLE

(2)點陣圖資源ID是根據按鈕Caption設定的:

a、根據點陣圖所表示的按鈕狀態:UP、DOWN、FOCUS和DISABLE,分別在按鈕Caption後面加上一個大寫字母U或D或F或X;

b、然後用雙引號將這串字元引起來;

eg1:若按鈕Caption為:BUTTON_UP 

則按鈕點陣圖資源ID為:"BUTTON_UPU""BUTTON_UPD""BUTTON_UPF""BUTTON_UPX"
eg2:若按鈕Caption為:BTN_DOWN
則按鈕點陣圖資源ID為:"BTN_DOWNU""BTN_DOWND""BTN_DOWNF""BTN_DOWNX"

eg3:若按鈕Caption為:FOCUS
則按鈕點陣圖資源ID為:"FOCUSU""FOCUSD""FOCUSF""FOCUSX"