(continued)
Environment: VC6.0 SP4, Win95/NT3.51 or later
Creating a CToolbar with 16 or 24 bit buttons is easy if you aren't worried about disabled buttons and your buttons don't have any pixels that should be set to the toolbar's background color. Things quickly get more complicated
if you want to correctly handle those other cases. This sample program attaches 24 bit images to the standard
MFC main frame toolbar and handles both disabled and hot buttons as well
as transparent button backgrounds. It can easily be extended to handle
16 bit images or different toolbar configurations.
If your application can be run with the display set to less than 16 bits
per pixel, you should add code to check the display depth and not load
the high color toolbars in those cases, since they won't look good.
Specifying separate bitmaps for the enabled, disabled, and hot buttons isn't too hard--CToolbar::GetToolbarCtrl() gets the toolbar control,
then CToolbarCtrl::SetImageList(), CToolbarCtrl::SetDisabledImageList(),
and CToolbarCtrl::SetHotImageList() are used to assign the bitmaps.
Making the image lists 24 bits deep requires creating the
CImageLists with no images, then loading the images as CBitmaps, and finally copying the
CBitmaps into the CImageLists.
Loading the bitmaps as 24 bits per pixel even when the user's screen is set
to a different bit depth requires extra work, too. CBitmap::LoadBitmap()
converts the bitmap to the screen's bit depth, so the Win32 function
::LoadImage() is used instead to create a 24 bit DIBSECTION, which is
then attached to a CBitmap so it can be passed to CImageList::Add().
When a toolbar is created in the Visual Studio toolbar editor, any pixel
that is light gray (RGB (192, 192, 192)) is replaced with the user's
chosen button color at runtime, making those pixels effectively
transparent. For some reason this doesn't happen to 24 bit CImageLists.
Specifying a mask color when the CImageList is created just ends up
replacing that color with black, not with the system button color. This
code does that color subsitution "manually." Before a bitmap is added
to an image list, the code iterates over the pixels in the bitmap,
replacing each RGB (192, 192, 192) pixel with the system button color
(::GetSysColor (COLOR_BTNFACE)). Since the bitmaps are DIBSECTIONs,
the code can access the pixels directly for maximum efficiency.
Since the Visual Studio graphics editor can't handle 24 bit images, you must edit the images in another program that can, such as GIMP or Adobe Photoshop. Save them as 24 bit .bmp files in the project's "res" folder. You can then import them into the project using the "import" command in the Developer Studio "Resource" tab.
static const int kImageWidth (16);
static const int kImageHeight (15);
static const int kNumImages (8);
static const UINT kToolBarBitDepth (ILC_COLOR24);
static const RGBTRIPLE kBackgroundColor = {192, 192, 192};
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1;
}
AttachToolbarImages (IDB_HICOLOR_TOOLBAR,
IDB_HICOLOR_TOOLBAR_DISABLED,
IDB_HICOLOR_TOOLBAR_HOT);
}
static void ReplaceBackgroundColor (CBitmap& ioBM)
{
BITMAP bmInfo;
VERIFY (ioBM.GetBitmap (&bmInfo));
VERIFY (bmInfo.bmBitsPixel == 24);
VERIFY (bmInfo.bmWidthBytes == (bmInfo.bmWidth * 3));
const UINT numPixels (bmInfo.bmHeight * bmInfo.bmWidth);
DIBSECTION ds;
VERIFY (ioBM.GetObject (sizeof (DIBSECTION), &ds) == sizeof (DIBSECTION));
RGBTRIPLE* pixels = reinterpret_cast<RGBTRIPLE*>(ds.dsBm.bmBits);
VERIFY (pixels != NULL);
const COLORREF buttonColor (::GetSysColor (COLOR_BTNFACE));
const RGBTRIPLE userBackgroundColor = {
GetBValue (buttonColor), GetGValue (buttonColor), GetRValue (buttonColor)};
for (UINT i = 0; i < numPixels; ++i)
{
if (pixels [i].rgbtBlue == kBackgroundColor.rgbtBlue
&& pixels [i].rgbtGreen == kBackgroundColor.rgbtGreen
&& pixels [i].rgbtRed == kBackgroundColor.rgbtRed)
{
pixels [i] = userBackgroundColor;
}
}
}
static void MakeToolbarImageList (UINT inBitmapID,
CImageList& outImageList)
{
CBitmap bm;
VERIFY (bm.Attach (::LoadImage (::AfxFindResourceHandle(
MAKEINTRESOURCE (inBitmapID), RT_BITMAP),
MAKEINTRESOURCE (inBitmapID), IMAGE_BITMAP, 0, 0,
(LR_DEFAULTSIZE | LR_CREATEDIBSECTION))));
::ReplaceBackgroundColor (bm);
VERIFY (outImageList.Create (
kImageWidth, kImageHeight, kToolBarBitDepth, kNumImages, 0));
VERIFY (outImageList.Add (&bm, RGB (0, 0, 0)) != -1);
}
void CMainFrame::AttachToolbarImages (UINT inNormalImageID,
UINT inDisabledImageID,
UINT inHotImageID)
{
::MakeToolbarImageList (inNormalImageID, m_ToolbarImages);
::MakeToolbarImageList (inDisabledImageID, m_ToolbarImagesDisabled);
::MakeToolbarImageList (inHotImageID, m_ToolbarImagesHot);
CToolBarCtrl& barCtrl = m_wndToolBar.GetToolBarCtrl();
barCtrl.SetImageList (&m_ToolbarImages);
barCtrl.SetDisabledImageList (&m_ToolbarImagesDisabled);
barCtrl.SetHotImageList (&m_ToolbarImagesHot);
}
Downloads
Download demo project - 37 Kb