問題:
論壇中有很多人提出:基於Windows的程序如資源管理器(Explorer.exe),IE等都能顯示出漂亮的工具欄圖像和圖標。但是,用MFC開發的應用程序一般都只能顯示16色的工具欄圖像和列表視圖(如CListView)圖像,而無法顯示在資源中創建的256色圖標和位圖。這是為什麼?
解答:
工具欄和列表視圖都是把自己的圖像存儲在圖像列表中。這個圖像列表實際上就是一個圖像清單。它是一個由許多小圖像組成的長條型位圖圖像。如圖一所示:
圖一
假設你有7個20x20的圖標,則在圖像清單中會將它們保存為一個140x20的位圖(7x20=140)。你可以根據需要來調整這個位圖的顏色特性;但是必須在創建圖像清單時指出要使用多少種顏色。在缺省情況下是16色。另外,當MFC加載工具欄位圖時使用的一個內部函數,AfxLoadSysColorBitmap,也假設顏色為16色。所以用MFC編程時,為了顯示256色圖像,你必須要對圖像清單進行處理。
我編寫了DEMO程序TBColor來說明如何在工具欄中顯示256色圖像,這個程序是一個極其典型的MFC程序——它有一個漂亮的工具欄。如圖二所示:
圖二
按下工具欄的每一個按鈕都彈出“關於”對話框。具體處理細節全都在CMainFrame::OnCreate函數中實現:
MainFrm.cpp
////////////////////////////////////////////////////////////////
// Set tabsize = 3 in your editor.
//
#include "StdAfx.h"
#include "MainFrm.h"
#include "Resource.h"
BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
ON_WM_CREATE()
END_MESSAGE_MAP()
static UINT indicators[] = {
ID_SEPARATOR, // status line indicator
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
CMainFrame::CMainFrame()
{
}
CMainFrame::~CMainFrame()
{
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
cs.style |= WS_CLIPCHILDREN;
return CFrameWnd::PreCreateWindow(cs);
}
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
VERIFY(CFrameWnd::OnCreate(lpCreateStruct)==0);
//創建並加載工具欄
//
VERIFY(m_wndToolBar.Create(this));
VERIFY(m_wndToolBar.LoadToolBar(IDR_MAINFRAME));
// 加載工具欄位圖 - 必須使用::LoadImage映射顏色
// 將(192,192,192) 映射到 COLOR_3DFACE.
//
HBITMAP hbm = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDR_MAINFRAME),
IMAGE_BITMAP,
0,0, // cx,cy
LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS );
CBitmap bm;
bm.Attach(hbm);
// 創建圖像清單並設置工具欄
// 256色圖像必須使用ILC_COLOR8!
//
m_ilToolBar.Create(20,20, ILC_COLOR8, 4, 4);
m_ilToolBar.Add(&bm,(CBitmap*)NULL);
m_wndToolBar.GetToolBarCtrl().SetImageList(&m_ilToolBar);
VERIFY(m_wndStatusBar.Create(this));
VERIFY(m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)));
VERIFY(m_wndView.Create(_T("Press a button, any button."),
WS_VISIBLE|WS_CHILD|SS_CENTERIMAGE|SS_CENTER,
CRect(0,0,0,0), this, AFX_IDW_PANE_FIRST));
return 0;
}
第一步一定要用::LoadImage加載工具欄位圖。這個函數是個多用途函數,它可以加載光標、圖標和位圖。加載位圖時,這個函數甚至還能將位圖中的某些顏色映射到當前的屏幕顏色。例如,DEMO程序中的工具欄位圖(圖一)使用RGB(192,192,192)為背景;如果恰好系統上有3D顏色,則LR_LOADMAP3DCOLORS標志會讓LoadImage將背景映射到系統實際的3D(GetSysColor(COLOR_3DFACE))顏色。
HBITMAP hbm = (HBITMAP)::LoadImage(AfxGetInstanceHandle(),
MAKEINTRESOURCE(IDR_MAINFRAME),
IMAGE_BITMAP,
0,0, // cx, cy
LR_CREATEDIBSECTION | LR_LOADMAP3DCOLORS );
LoadImage返回一個位圖句柄(HBITMAP),但MFC會更喜歡與CBitmaps打交道,所以接下來就是創建一個CBitmap對象並將它與你的句柄聯系(Attach)起來。
CBitmap bm;
bm.Attach(hbm);
現在有了CBitmap對象,你就可以從它那兒創建新的圖像清單了。
m_ilToolBar.Create(20,20,ILC_COLOR8,4,4);
m_ilToolBar.Add(&bm,(CBitmap*)NULL);
m_ilToolBar是個CMainFrame成員,ILC_COLOR8是個神奇的標志,它創建一個8位顏色的調色板位圖——既256色的位圖。如果你願意,它甚至能創建24位顏色的位圖——但是要記住LR_LOADMAP3DCOLORS只能和調色板位圖一起使用。最後一步是將新創建的圖像清單用於工具欄。這一步很重要,千萬不要忘記!
m_wndToolBar.GetToolBarCtrl().SetImageList(&m_ilToolBar);
在工具欄中使用256色圖像就這麼簡單。這種技術同樣可以用於列表視圖中的圖像以及rebars和其它使用圖像清單的控制。趕快試一下吧!