Programming Tips - How do I get transparent icons in a toolbar?

Date: 2008sep11 Platform: win32 Language: C/C++ Q. How do I get transparent icons in a toolbar? A. There are probably other ways to do it but this works for me. Make the toolbar bitmap with a color to represent transparency (in this case RGB(192,192,192)). When you load the bitmap resource convert that color to the system background color. Then use the bitmap in your toolbar. Here's some code:
static const int iToolbarIconWidth = 32; // Change to your size static const int iToolbarIconHeight = 32; // Change to your size static const int iToolbarBitmapWidth = iToolbarIconWidth * 13; // There are 13 icons. Change to your number. static const int iToolbarBitmapHeight = 100; static const int iGrey = 192; // Bitmap was created with this has the bg color static InitBitmapInfo(BITMAPINFO &bi, const int bytes_per_pixel, const int width, const int height) { ZeroMemory(&bi, sizeof(bi)); bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bi.bmiHeader.biWidth = width; bi.bmiHeader.biHeight = height; bi.bmiHeader.biPlanes = 1; bi.bmiHeader.biBitCount = bytes_per_pixel * 8; int cClrBits = bytes_per_pixel * 8; if (cClrBits < 24) bi.bmiHeader.biClrUsed = (1<<cClrBits); bi.bmiHeader.biCompression = BI_RGB; bi.bmiHeader.biSizeImage = ((bi.bmiHeader.biWidth * cClrBits + 31) & ~31) / 8 * bi.bmiHeader.biHeight; bi.bmiHeader.biClrImportant = 0; } static BOOL GetBmpBits(HBITMAP hBmp, const int bytes_per_pixel, const int width, const int height, LPVOID pBits, const size_t size) { HDC hdc = ::GetDC(NULL); BITMAPINFO bi; BOOL bResult; if (bytes_per_pixel > 4) { Debug("GetBmpBits: bytes_per_pixel is too big. Its bytes not bits, right?"); ::ReleaseDC(NULL, hdc); return FALSE; } InitBitmapInfo(bi, bytes_per_pixel, width, height); if (size < bi.bmiHeader.biSizeImage) { // Supplied buffer is too small ::ReleaseDC(NULL, hdc); return FALSE; } bResult = GetDIBits( hdc, // handle to DC hBmp, // handle to bitmap 0, // first scan line to set height, // number of scan lines to copy. Negative means top-down (ie normal) pBits, // array for bitmap bits &bi, // bitmap data buffer DIB_RGB_COLORS // RGB or palette index ); ::ReleaseDC(NULL, hdc); return bResult; } static BOOL SetBmpBits(HBITMAP hBmp, const int iBytesPerPixel, const int width, const int height, LPVOID pBits, const size_t size) { HDC hdc = ::GetDC(NULL); BITMAPINFO bi; BOOL bResult; InitBitmapInfo(bi, iBytesPerPixel, width, height); if (size < bi.bmiHeader.biSizeImage) { // Supplied buffer is too small ::ReleaseDC(NULL, hdc); return FALSE; } bResult = SetDIBits( hdc, // handle to DC hBmp, // handle to bitmap 0, // first scan line to set height, // number of scan lines to copy pBits, // array for bitmap bits &bi, // bitmap data buffer DIB_RGB_COLORS // RGB or palette index ); ::ReleaseDC(NULL, hdc); return bResult; } static void MakeToolbarBitmapTransparent(CBitmap &b) { COLORREF bg = ::GetSysColor(COLOR_3DFACE); RGBTRIPLE bmp_bits[iToolbarBitmapHeight][iToolbarBitmapWidth]; // Must match the bitmap or we'll crash int x, y; RGBTRIPLE *pRow; RGBTRIPLE *pPixel; RGBTRIPLE Bg; Bg.rgbtRed = GetRValue(bg); Bg.rgbtGreen = GetGValue(bg); Bg.rgbtBlue = GetBValue(bg); GetBmpBits(b, 3, iToolbarBitmapWidth, iToolbarBitmapHeight, bmp_bits, sizeof(bmp_bits)); // Bitmap is bottom-up. We only need to touch the top iToolbarIconHeight lines. for (y = iToolbarBitmapHeight - iToolbarIconHeight; y < iToolbarBitmapHeight; y++) { pRow = (RGBTRIPLE *) &bmp_bits[y]; for (x = 0; x < iToolbarBitmapWidth; x++) { pPixel = &pRow[x]; if (pPixel->rgbtRed == iGrey && pPixel->rgbtGreen == iGrey && pPixel->rgbtBlue == iGrey) { *pPixel = Bg; } } } SetBmpBits(b, 3, iToolbarBitmapWidth, iToolbarBitmapHeight, bmp_bits, sizeof(bmp_bits)); }