Setting a background color

The approach we will take to get a uniform background color is that whenever the control needs painting, we will paint the background, we will let the control draw the items in a memory device context and then paint this image transparently onto the control surface.
Step 1: Add handler function for WM_PAINT
Whenever the control needs to be updated the OnPaint() function gets called. We first create a memory device context that matches the paint DC in terms of the bitmap selected in it and the clip region. We let the default window procedure of the control draw in the memory DC using the system color as the background color.Next we create a mask bitmap using yet another device context. A mask bitmap is a monochrome bitmap in which one color indicates the background color in the source bitmap and the other color indicates all the bits that are not the background color. We need the mask bitmap to copy only the foreground color from the memory DC to the paint DC.
Once we have the mask bitmap, we draw the background color using the paint DC and then draw the image in the memory DC transparently over the paint DC. I had initially used MaskBlt() for drawing the image transparently but found out that it was supported on NT only and not Windows 95. Here's what we do. The image in memDC is the foreground image. When drawing this image we have to somehow make the background color have no effect. We achieve this by setting the background to black using the mask bitmap. When we later use the SRCPAINT raster operation, the black color has no effect on the destination color. Similarly we use the mask bitmap to set the foreground color of the image in the paint DC to black. We finally combine the two images.
Thanks to Matthias Kerkhoff from Germany for pointing out the problem with MaskBlt() and suggesting the new method for drawing the image transparently.
void CTreeCtrlX::OnPaint()
{
CPaintDC dc(this);
// Create a memory DC compatible with the paint DC
CDC memDC;
memDC.CreateCompatibleDC( &dc );
CRect rcClip, rcClient;
dc.GetClipBox( &rcClip );
GetClientRect(&rcClient);
// Select a compatible bitmap into the memory DC
CBitmap bitmap;
bitmap.CreateCompatibleBitmap( &dc, rcClient.Width(), rcClient.Height() );
memDC.SelectObject( &bitmap );
// Set clip region to be same as that in paint DC
CRgn rgn;
rgn.CreateRectRgnIndirect( &rcClip );
memDC.SelectClipRgn(&rgn);
rgn.DeleteObject();
// First let the control do its default drawing.
CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
// Now create a mask
CDC maskDC;
maskDC.CreateCompatibleDC(&dc);
CBitmap maskBitmap;
// Create monochrome bitmap for the mask
maskBitmap.CreateBitmap( rcClip.Width(), rcClip.Height(), 1, 1, NULL );
maskDC.SelectObject( &maskBitmap );
memDC.SetBkColor( ::GetSysColor( COLOR_WINDOW ) );
// Create the mask from the memory DC
maskDC.BitBlt( 0, 0, rcClip.Width(), rcClip.Height(), &memDC,
rcClip.left, rcClip.top, SRCCOPY );
// Fill the background with custom color
// Use a protected member variable to save the color
// rather than hard coding it.
dc.FillRect(rcClip, &CBrush(RGB(255,255,192)) );
// Copy the image in memDC transparently
// MaskBlt works in NT only - so we use another method
// dc.MaskBlt( rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &memDC,
// rcClip.left, rcClip.top, maskBitmap, 0, 0,
// MAKEROP4(SRCAND,SRCCOPY) );
// Set the background in memDC to black. Using SRCPAINT with black and any other
// color results in the other color, thus making black the transparent color
memDC.SetBkColor(RGB(0,0,0));
memDC.SetTextColor(RGB(255,255,255));
memDC.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &maskDC, rcClip.left, rcClip.top, SRCAND);
// Set the foreground to black. See comment above.
dc.SetBkColor(RGB(255,255,255));
dc.SetTextColor(RGB(0,0,0));
dc.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &maskDC, rcClip.left, rcClip.top, SRCAND);
// Combine the foreground with the background
dc.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &memDC,
rcClip.left, rcClip.top,SRCPAINT);
}
Step 2: Add handler for WM_ERASEBKGND
Since we are already drawing the background in the OnPaint() function handling this function and simply returning TRUE ensures that the default window procedure does not erase the background. Adding this handler prevents extra updates to the control's client area and thus reduces flicker.In actual production code, you'd probably check for a non default background color before returning TRUE;
BOOL CTreeCtrlX::OnEraseBkgnd(CDC* pDC)
{
// To prevent flickering when using non default bkcolor
return TRUE;
}

Comments
Is there a way to change the background colour of an idiviual tree item
Posted by Legacy on 08/16/2002 12:00amOriginally posted by: Adam
Hi i am trying to write an explorer like view pair
(a tree view and a list view) when i select an item via programing this works fine however when I added the list view and set it as the active view (which is required to activate the toolbar option [largeIcon, SmallIcon, List and details] the selection on the tree disappears.
Is there a way Ican leave the selection visible in the treeview while having the listview as my active view?
Alternativly is there a way to change the background colour of an individual item ?
Then I could change it in the treeviews on sel changing event ( reseting the colour of the currently selected item before setting the colo of the new selected item).
Any help you can give (or problems you can forsee would be great [with solutions would be briliant])
Thanks in advance for any help you can give
Adam
ReplySetting color in scroll bar of tree control right side.
Posted by Legacy on 01/18/2001 12:00amOriginally posted by: Seokho Lee
I want to set color in scroll Bar of tree control right side .
but, I could not do it.
please help me!
I am poor at English.
Sorry.
ReplyBug correction
Posted by Legacy on 12/28/2000 12:00amOriginally posted by: Sebastien Dubreucq
The window is not properly updated when the updated area doesn't match with the entire client area. So it works only when the entire window has been invalidated with a call to InvalidateRect with the parameter NULL.
2 lines need to be corrected, read comments in the code below:
// Set the background in memDC to black. Using SRCPAINT with black and any other
// color results in the other color, thus making black the transparent color
memDC.SetBkColor(RGB(0,0,0));
memDC.SetTextColor(RGB(255,255,255));
memDC.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &maskDC, 0,0/* Replacement here! old parameter : rcClip.left, rcClip.top*/, SRCAND);
// Set the foreground to black. See comment above.
dc.SetBkColor(RGB(255,255,255));
dc.SetTextColor(RGB(0,0,0));
dc.BitBlt(rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &maskDC, 0,0 /* Replacement here! old parameter : rcClip.left, rcClip.top*/, SRCAND);
(I use Visual C++ 5)
ReplyWhy not SetBkColor(...)
Posted by Legacy on 11/24/2000 12:00amOriginally posted by: Bruno Leclerc
I simply tryed a GetTreeCtrl().SetBkColor(MyColor) in OnInitDialog, i don't see anything wrong ?!
ReplySetBkColor and latest comctrl32.dll
Posted by Legacy on 03/26/1999 12:00amOriginally posted by: Martin Rubas
It looks like problems with SetBkColor has been solved with new common control library. I have installed MSIE5.0 which uses COMCTL32.DLL version 5.80 . It is also marked as part of MS Windows 2000 with product version 5.00.2014.216.
I have called SetBkColor (w/out ModifyStyle trick) before and after I added some items to the tree control and it always worked fine.
ReplyYou had better use such macros as TreeView_SetBkColor,TreeView_SetTextColor
Posted by Legacy on 03/22/1999 12:00amOriginally posted by: J-Shin
comctl32.dll version 4.71 or later is required.
It doesn't seem to dither the required color.
Good Luck!
ReplyThere is a fix from Microsoft
Posted by Legacy on 03/21/1999 12:00amOriginally posted by: l.e.rousseau
See q216140.
You need to turn off the TVS_HASLINES
and back on again.
like this :
Replyl_pTreeCtrl->ModifyStyle( TVS_HASLINES, 0, 0 );
l_pTreeCtrl->ModifyStyle( 0, TVS_HASLINES, 0 );
The only problem I've had is that with
a dark gray background the square
vanishes - possibly a XOR problem.
Problem with MFC-Handling for Tree-chenging
Posted by Legacy on 03/01/1999 12:00amOriginally posted by: Joerg Dettmann
This method has problems when the MFC change the display of the Tree
Replylike collapse, changing focus, ...
SetBkColor(..) works if ...
Posted by Legacy on 01/20/1999 12:00amOriginally posted by: Cathy Yang
Funciton CTreeCtrl::SetBkColor(...) works very well if you call it BEFORE you build the tree, not after.
ReplyIt doesn't seem to work in my computer.
Posted by Legacy on 01/06/1999 12:00amOriginally posted by: Peng Jianrong
I'm sorry,it doesn't seem to work in my computer. I use appwizard to
generate a project with a view derived from CFormView and add a CTreeCtrl control into it. I copy these codes to my program,but when I
add a node into the tree control,the background color was changed to mosaic(Don't laugh at my poor English,I'm from China). I try to use the control's SetBkColor (not CDC 's member function), only change the color of the right of the nodes, but when I use SetBkColor twice, it do work. At last I find only 16 colors can be set as uniform background.
I don't handle the WM_PAINT and other windows message and I do this
by overloading the CFormView's OnInitialUpdate function.
I'm from China (P.R.C)and I use Windows 95(OSR) simply Chinese edition
and VC++ 6.0, I like this site very much, thank you.
Reply