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有一个重载函数:
BOOL LoadBitmaps( 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"