Using a bitmap as a background image

The tree view control does not support an owner drawn control - not yet. This makes it somewhat difficult to display an image as a background. However, it can be done and we will discuss how. The basic approach is to let the control draw in a memory device context, draw this transparently over the background image and then draw the final image onto the control client area. Off course, there are a few details involved.

One good use of having an image in the background is to display the company logo. Make sure though that the image is such that it does not make the text difficult to read.

The technique given below uses a 256 color (16 color would also be fine) image that has been added as a bitmap resource. If the image is smaller than the control, then the image is tiled to cover the client area. For faster redraws the image scrolls along with the items.

Step 1: Add bitmap to resource

Add a bitmap that you want to use as the background image to the resource file. Use the import feature of the resource editor to get the image in. A copy-paste operation usually results in the colors of the bitmap getting messed up. You may add more than one bitmap and allow the user to choose one of the images or decide not to use any.

Step 2: Add member variables

It is not efficient to reload the bitmap or recreate the logical palette each time an item needs to be repainted. We therefore add member variables to store the bitmap, the logical palette and the dimensions of the bitmap. Declare these as protected members since we will provide a function to set the background image.
	CPalette m_pal;
	CBitmap m_bitmap;
	int m_cxBitmap, m_cyBitmap;

Step 3: Add member functions to set background image

We add two overloaded member functions to set the background image. These functions should be public member functions. The first function takes the resource ID as an argument and the second takes the resource name as an argument.

These functions can be called to change the image if one has already been specified. The first thing the function does is delete the bitmap and palette gdi object if one has been created. It then loads the bitmap and attaches it to the CBitmap object. We use a call to the global ::LoadImage() rather than to the CBitmap::LoadBitmap(). The reason for this is that we want to be able to access the DIBSECTION of the bitmap and the reason why we want the DIBSECTION is because we want to create a logical palette that matches the colors used by the bitmap. My guess is you already know why we need a logical palette. Without going into too much detail lets just say that if you do not set up and use a logical palette then the image is likely to appear very dull on a 256 color display. You'd be fine if the display supported 64K or more colors. We also save the dimensions of the bitmap for later use.

Once we have the bitmap set, we start working on creating the logical palette. We determine the number of colors used by the bitmap by getting access to the DIBSECTION by calling the Cbitmap::GetObject() function. Note that the documentation for this function does not mention the DIBSECTION, you'd have to look up the documention of the ::GetObject() function in the API section instead. Sometimes the BITMAPINFOHEADER which is part of the DIBSECTION does not specify how many colors it uses. If this is the case we infer the color count from the number of bits it uses for the each pixel. For example, 8 bits can represent 256 different values and therefore indicates 256 colors. Similarly, 16 bits indicates 64K colors.

A bitmap that uses more than 256 colors does not have a color table. In this situation we simply create a halftone palette compatible with the device context. A halftone palette is basically a palette that contains a sampling of all the different colors. This is certainly not the best solution but it is the simplest.

If the bitmap has 256 colors or less, we do create the palette. We allocate enough space to hold the color table of the bitmap and call the function ::GetDIBColorTable() to retrieve it from the bitmap. We also allocate enough memory to create a logical palette and copy the color entries from the bitmap's color table. The palVersion field should be 0x300.

After creating the CPalette object, we deallocate the memory blocks allocated earlier and invalidate the window so that it can be redrawn using the new image.

BOOL CTreeCtrlX::SetBkImage(UINT nIDResource)
	return SetBkImage( (LPCTSTR)nIDResource );

BOOL CTreeCtrlX::SetBkImage(LPCTSTR lpszResourceName)

	// If this is not the first call then Delete GDI objects
	if( m_bitmap.m_hObject != NULL )
	if( m_pal.m_hObject != NULL )
	HBITMAP hBmp = (HBITMAP)::LoadImage( AfxGetInstanceHandle(), 
			lpszResourceName, IMAGE_BITMAP, 0,0, LR_CREATEDIBSECTION );

	if( hBmp == NULL ) 
		return FALSE;

	m_bitmap.Attach( hBmp );
	m_bitmap.GetBitmap( &bm );
	m_cxBitmap = bm.bmWidth;
	m_cyBitmap = bm.bmHeight;

	// Create a logical palette for the bitmap
	BITMAPINFOHEADER &bmInfo = ds.dsBmih;
	m_bitmap.GetObject( sizeof(ds), &ds );

	int nColors = bmInfo.biClrUsed ? bmInfo.biClrUsed : 1 << bmInfo.biBitCount;

	// Create a halftone palette if colors > 256. 
	CClientDC dc(NULL);			// Desktop DC
	if( nColors > 256 )
		m_pal.CreateHalftonePalette( &dc );
		// Create the palette

		RGBQUAD *pRGB = new RGBQUAD[nColors];
		CDC memDC;

		memDC.SelectObject( &m_bitmap );
		::GetDIBColorTable( memDC, 0, nColors, pRGB );

		UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * nColors);

		pLP->palVersion = 0x300;
		pLP->palNumEntries = nColors;

		for( int i=0; i < nColors; i++)
			pLP->palPalEntry[i].peRed = pRGB[i].rgbRed;
			pLP->palPalEntry[i].peGreen = pRGB[i].rgbGreen;
			pLP->palPalEntry[i].peBlue = pRGB[i].rgbBlue;
			pLP->palPalEntry[i].peFlags = 0;

		m_pal.CreatePalette( pLP );

		delete[] pLP;
		delete[] pRGB;

	return TRUE;

Step 4: Add handler for WM_PAINT

The OnPaint() function is where the action is. There are two distinct situation that the OnPaint() function has to handle. No image might have been specified, in which case the control should display in the default manner. The other situation is of course when an image has been specified by calling the SetBkImage() function set out in the previous step. This is where we have to go through extra gyrations to get the task done. It is easier and more efficient to let the default window handle the painting completely when no image has been specified. However, if you want further specialization of the control, such as displaying different items in different colors and font, then it is easier to plug in that code into the one listed below.

One of the first things we do is create a memory device context that is compatible with the paint DC. We let the default window procedure of the control draw in the memory DC. If not image has been specified then we simply copy the content of the memory DC to the paint DC.

If a background image has been specified we create a mask bitmap from the content of the memory device context. We have to use a new device context for the mask bitmap. A mask bitmap is essentially 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 create another device context to hold the image bitmap. We create yet another device context to hold the tiled image of the bitmap. The 'imageDC' should have the proper palette selected into it before the tiled image is drawn on it. Forgetting to do so results in loss of color information on displays with 256 or fewer colors. The palette is also selected into, and realized for the main device context. Since only the invalidated items are repainted, it is important to offset the tiled image properly so that it appears continuous rather than as image strips. This is where the call to GetItemRect() and GetScrollPos() comes in.

The tiled image is drawn onto the 'imageDC', then the image from the memory DC is copied transparently onto the 'imageDC' and finally the result is copied onto the screen.To draw the image transparently 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 image 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.

We could have painted the tiled image directly onto the paint DC, and then drawn the content of the memory DC onto it. The reason for not doing so is because we avoid the excess flickering that this would have caused.

void CTreeCtrlX::OnPaint() 
	// Remove comments from next five lines if you don't need any 
	// specialization beyond adding a background image
//	if( m_bitmap.m_hObject == NULL )
//	{
//		CTreeCtrl::OnPaint();
//		return;
//	}

	CPaintDC dc(this);

	CRect rcClip, rcClient;
	dc.GetClipBox( &rcClip );

	// Create a compatible memory DC 
	CDC memDC;
	memDC.CreateCompatibleDC( &dc );
	// Select a compatible bitmap into the memory DC
	CBitmap bitmap, bmpImage;
	bitmap.CreateCompatibleBitmap( &dc, rcClient.Width(), rcClient.Height() );
	memDC.SelectObject( &bitmap );

	// First let the control do its default drawing.
	CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );

	// Draw bitmap in the background if one has been set
	if( m_bitmap.m_hObject != NULL )
		// Now create a mask
		CDC maskDC;
		CBitmap maskBitmap;

		// Create monochrome bitmap for the mask
		maskBitmap.CreateBitmap( rcClient.Width(), rcClient.Height(), 
						1, 1, NULL );
		maskDC.SelectObject( &maskBitmap );
		memDC.SetBkColor( ::GetSysColor( COLOR_WINDOW ) );

		// Create the mask from the memory DC
		maskDC.BitBlt( 0, 0, rcClient.Width(), rcClient.Height(), &memDC, 
					rcClient.left,, SRCCOPY );

		CDC tempDC;
		tempDC.SelectObject( &m_bitmap );

		CDC imageDC;
		CBitmap bmpImage;
		imageDC.CreateCompatibleDC( &dc );
		bmpImage.CreateCompatibleBitmap( &dc, rcClient.Width(), 
						rcClient.Height() );
		imageDC.SelectObject( &bmpImage );

		if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
			dc.SelectPalette( &m_pal, FALSE );

			imageDC.SelectPalette( &m_pal, FALSE );

		// Get x and y offset
		CRect rcRoot;
		GetItemRect( GetRootItem(), rcRoot, FALSE );
		rcRoot.left = -GetScrollPos( SB_HORZ );

		// Draw bitmap in tiled manner to imageDC
		for( int i = rcRoot.left; i < rcClient.right; i += m_cxBitmap )
			for( int j =; j < rcClient.bottom; j += m_cyBitmap )
				imageDC.BitBlt( i, j, m_cxBitmap, m_cyBitmap, &tempDC, 
							0, 0, 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.BitBlt(rcClip.left,, rcClip.Width(), rcClip.Height(), &maskDC, 
				rcClip.left,, SRCAND);

		// Set the foreground to black. See comment above.
		imageDC.BitBlt(rcClip.left,, rcClip.Width(), rcClip.Height(), &maskDC, 
				rcClip.left,, SRCAND);

		// Combine the foreground with the background
		imageDC.BitBlt(rcClip.left,, rcClip.Width(), rcClip.Height(), 
					&memDC, rcClip.left,,SRCPAINT);

		// Draw the final image to the screen		
		dc.BitBlt( rcClip.left,, rcClip.Width(), rcClip.Height(), 
					&imageDC, rcClip.left,, SRCCOPY );
		dc.BitBlt( rcClip.left,, rcClip.Width(), 
				rcClip.Height(), &memDC, 
				rcClip.left,, SRCCOPY );

Step 5: Handle the scroll messages

The only reason we need to handle the scroll messages is because it helps in reducing the flicker caused by the control update. The default handling the WM_HSCROLL and the WM_VSCROLL messages is that the control is scrolled by the window proc and then the exposed area is invalidated. By calling InvalidateRect() we make sure that the control gets updated only once.
void CTreeCtrlX::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
	if( m_bitmap.m_hObject != NULL )
	CTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);

void CTreeCtrlX::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
	if( m_bitmap.m_hObject != NULL )
	CTreeCtrl::OnHScroll(nSBCode, nPos, pScrollBar);


We handle the TVN_ITEMEXPANDING message for the same reason that we handle the scroll messages.
void CTreeCtrlX::OnItemExpanding(NMHDR* pNMHDR, LRESULT* pResult) 

	if( m_bitmap.m_hObject != NULL )
	*pResult = 0;

Step 7: 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.
BOOL CTreeCtrlX::OnEraseBkgnd(CDC* pDC) 
	if( m_bitmap.m_hObject != NULL )
		return TRUE;
	return CTreeCtrl::OnEraseBkgnd(pDC);


The WM_QUERYNEWPALETTE message is sent to a window when it is about to receive input focus. It gives the window an oppurtunity to realize its logical palette so that it can present itself in the best form. The WM_PALETTECHANGED message is sent to a window whenever that system palette is changed. If we do not handle these messages and another application changes the system palette then the colors in our background image will look terrible. Unfortunately both these messages are sent to top level windows. We will deal with that in the next step.

The OnQueryNewPalette() function first checks whether it needs to reselect the palette. Once it realizes the logical palette it invalidates the window if any of the color were remapped. The OnPaletteChanged() function returns without any further processing if the tree view control itself was responsible for the message because it changed the palette. It then calls OnQueryNewPalette() to rerealize the palette.

BOOL CTreeCtrlX::OnQueryNewPalette() 
	CClientDC dc(this);
	if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE && m_pal.m_hObject != NULL )
		dc.SelectPalette( &m_pal, FALSE );
		BOOL result = dc.RealizePalette();
		if( result )
		return result;
	return CTreeCtrl::OnQueryNewPalette();

void CTreeCtrlX::OnPaletteChanged(CWnd* pFocusWnd) 
	if( pFocusWnd == this )


Step 9: Forward palette messages from top level window

As I've already mentioned in the previous step, the WM_QUERYNEWPALETTE & WM_PALETTECHANGED messages are sent only to top level windows. Since the list view control had changed the palette we have to forward these messages to the list view control. I had used a dialog based application to test this so here's what the handlers look like.
void CTreeViewDlg::OnPaletteChanged(CWnd* pFocusWnd) 
	m_tree.SendMessage( WM_PALETTECHANGED, (WPARAM)pFocusWnd->m_hWnd );	

BOOL CTreeViewDlg::OnQueryNewPalette() 

	return m_tree.SendMessage( WM_QUERYNEWPALETTE );


  • wheloltabotly PumeSonee Phobereurce 4486268

    Posted by TizefaTaNaday on 06/02/2013 08:42pm

    mirlWaiguigue snultyspolley annuapask

  • You crave some tomato basil and mozzarella. In behalf of indoor utilization, these slippers are as be exposed and manueverable as sneakers.

    Posted by Soaceddew on 04/19/2013 12:20pm

    Has just released distinct mod color Subject to Inneva Woven shoes, Nike recently with another technique to regurgitate shoes with distinguishable styling to all [url=]nike air max 90[/url] eyes. This brings faithful issue Free Inneva Woven is a White Label of works in the series, represents shoes Italian made the assurance. Latest Free Inneva Woven swart and pornographic are available in two color schemes, to hand-knit Woven vamp in addition to infiltrated Italy's [url=]nike free run uk[/url] finest crafts, during the interval gives athletes closed to the foot of relieve, the most consequential thing is the end of Unused 5 configuration, barefoot know it resolution bring cannot be ignored. Nike Disburden Inneva Woven SP Milk-white Identify Wedge on Parade 16 at outlets for everyone the [url=]nike free 4.0 v2[/url] trade name on the shelves, and on sale in limited tone, interested friends should recompense fasten attention to Nike announced the news.

  • Prime your commodity to notion the operating confederation and browser requirements restricted characteristic of to your

    Posted by carpitooa on 04/15/2013 11:52pm

    A minuscule Life on Demand Purvey Co:Chris Bossola opened in 1996, [url=]hollister france[/url] selling a solo amassment of choice pieces. As a Richmond based boutique we glue the creditable politeness and 俵an of the illustrious apple into our pain in the neck into bewilder [url=]abercrombie paris[/url] and attitude. Across with the one-time decade our choosing has evolved to adorn roll in of a well-edited hotchpotch of spiffy designers and aloof labels from the U.S. and every place [url=]jordan[/url].Judging finished with the soundtrack of his movies, I would about he has hefty know in music and would allow in him set down a run-out effect skulk a playlist as extensively as something me any time.Before I opened my aggregate, I was a accumulator first. [url=]abercrombie[/url] After I opened my inventory in L.A., I had to shift my [url=]abercrombie france[/url] look at and my criteria instead of retail because 99 percent of my customers are less interested in provenance. I boyfriend reading up on the brands that I come by from so it [url=]air jordan pas cher[/url] was tremendous that the label had piles of info. Unfortunately you can’t categorically comprehend what it says on the ticket here but some of the explanation points less [url=]hollister france[/url] Skunkfunk are that they unashamed alongside sailing-boat, organize natural cotton, wood mush cellulose (Modal and Lyocell) and recycled polyester. In search their packaging they toss off bioplastic [url=]abercrombie[/url] (made from Cornstarch) and advantage as much recycled legal papers as possible. Their clothes are also commonly multi certainty and reversible [url=]doudoune moncler[/url]. The of inquest of similarity between males and females is constantly supervised [url=]air jordan[/url] exploration, undeterred by that men surface to be communistic dated of the fatshion equation altogether. A trawl with the support search engines pro any signs of empowered spear [url=]michael kors outlet[/url] fatshion returned zilch, there’s no ‘curve’ portion, no catwalks, no take-over, why?It’s not a inane of ratios, there are an oversupply of masculine fashion blogs fudging there and they are decent as unmistakable, [url=]hollister[/url] dahling. The to be expected bony swell can look fresh to routine fash blog inspo from the likes of Swanky Lou, The Every hour High street, The Sartorialist and Closet Freaks. It’s benighted to imagine monstrous men be undergoing [url=]louboutin[/url] no prejudicial in fashion, our instinct is they’re panic-stricken, shunned, typecast.

  • Cette sorting doused 2012 n’ambience pas le Nike Praise of zephyr au talon (comme la OG de 89 et la reedition de 99) mais le logo Jumpman Jordan

    Posted by Vetriatszy on 03/15/2013 09:37am

    carry Nutramigen flexibility realistic generate continuing to be vouchers you'd like to exchange folks? has superior baby laundry, equipment, disks or possibly a more actuals on the way to exchange? aid your own day whiter by offering a RAOK? fulfill a few other experienced traders and determine what they've to offer. We can also get the brilliant ~*~ ISO sunday ~*~ bond regarding today's association. we are aware every person await mondays but now they will be good! remember to check back on tues and wait to see find out this here of the seed adjusted for the more suitable! needs to be: our opinions backboard not necessarily be held neither endorsed and also by BaCenter. people who have whatever queries of the actual health or the healthiness of your kid, you need to consult with a physician potentially all other doctor. don't hesitate to evaluate the privacy coupled with terms of Use forward of through this site. your own personal standby and call time site would mean binding agreement to obtain chained by a relation to Use

  • Christian Louboutin from Italy and many Italian brand, was born in the traditional family business Jordan

    Posted by Vetriatszy on 03/14/2013 01:24am

    Abercrombie but fitch perfume presentation Abercrombie and moreover fitch cologne is certainly quite popular adequately these. they provide you with many different types of cologne that you can consider. it should be difficult make up your mind what is a reasonable one you have got to investment. reading an Abercrombie or fitch perfume review may help you select this distinct one you want to buy. Abercrombie so fitch Cologne get this kind diverse aftershaves fragrances. they have personally so far personalized razors to get developed adult males along with styles guided toward most wives. it would adopt you' week or over to examine bit of music many different choices, commonly period. Having the ability to read an Abercrombie and fitch Cologne discussion can save you a'substantial amount'of some time and improve risk at decision remarkably considerably easier each time pruchasing among the their colognes. Abercrombie together with fitch cologne possess disparity for selling prices. the various colognes will be comparatively cheap. there simply are that all other options the ranges is highly costly and topside pub cease to do with charges. building a review will allow you to select generally appliances to consult with which may be within your budget to help you to abercrombie additionally fitch electric outlet opt for a merchandise that you both like fit your wallet. being familiar with just what aftershaves are developing the money narrows more affordable your research as spares you day time if you place an order. heap why to envision product critiques is for getting holistic believe associated with so what on earth many consider a real product. particularly, Do ladies like all the different the perfume how can the odour carry on to keep doing work for a long while maybe a brief time period of time will probably be small easier to dispense the some are her response families of difficulties of the fact that reading an exam help you accessible to to answer and you online more fulfilling much. and are a handful of cool applies to consider an Abercrombie and fitch cologne reviews One place is actually mags. a great many health and beauty magazines promotion perfume and perfume product critiques. Any masters put your hands on try out strip which you'll unblock and in actual fact connect to sniff around the odour that they'll be browsing with output. another excelllent spot for a find product critiques are eZines. EZines were using the net weeklies and they often unveiled in people associated with mailbox. you could become a member of treatment testimonials eZines or maybe perfume or else scent eZines. you can abercrombie fitch uk will most likely go in via your manager on the ezine test an actua styles of investigate in the pocket. want to purchase this program cable, you will carry out chiefly to complete an Abercrombie and fitch perfume assess for your needs and additional market. almost any editors end up being browsing for area of interest strategies and willing to be of assistance. digesting an Abercrombie along with fitch cologne synopsis will enable you to choose is a better your own for is more enjoyable. it will save you in period helping personal alternatives to create seeking out software packages on the internet and also a local market way more fulfilling. regarding any kind conditions approximately your home health or the healthiness of your child, it is recommended to consult with a physician or perhaps even several more physician. certain assess the privacy together with relation to Use previous to with this particular site. an individual's call time site means design become sure among the terms of Use

  • More simply way

    Posted by zeus200x on 11/02/2007 06:27am

    The more simple wayof how to overlap background image and standard tree output is to use a CDC::TransapretnBlt function.
    For example, so:
    // Combine the foreground with the background
    VERIFY(imageDC.TransparentBlt(rcClient.left,, rcClient.Width(), rcClient.Height(),&memDC, 0,0,rcClient.Width(), rcClient.Height(),::GetSysColor( COLOR_WINDOW )));
    In this way it is no necessary to use a mask dc.

  • About: CWnd::DefWindowProc

    Posted by Legacy on 09/30/2003 12:00am

    Originally posted by: xzh_ll

    Nice meet you!

    I want to know how can realize "CWnd::DefWindowProc" using API Function.

    Furthermore,my language don't support Function Pointer,such as PowerBuilder.

    Thank you!!

  • Image Works, but everything else is Black

    Posted by Legacy on 04/12/2003 12:00am

    Originally posted by: IbanTheGreat

    Howdy, I've successfully added this code to my Tree Ctrl, and everything seems to work, except that the rest of the tree ctrl show's black, and i can't figure out why. The image comes in just fine, and i can see the tree just fine on top of everything, but where there is no BMP there is Black...

    Any Suggestions??

  • Can you give me source code ?

    Posted by Legacy on 11/18/2002 12:00am

    Originally posted by: Do Hoang Ha

    I can't make it work well , please show me more detail !!!

  • Can you give me the source code?

    Posted by Legacy on 10/21/2002 12:00am

    Originally posted by: gaoxingmin

    Can you give me the source code?
    Thank you!

  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Entire organizations suffer when their networks can't keep up and new opportunities are put on hold. Waiting on service providers isn't good business. In these examples, learn how to simplify network management so that your organization can better manage costs, adapt quickly to business demands, and seize market opportunities when they arise.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date