問題:
論壇中有很多人提出:基於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和其它使用圖像清單的控制。趕快試一下吧!
本文示例代碼或素材下載