修改树控件特定节点上的字体和颜色

Setting color and font attribute for individual items


Like any other window, you can set the font of the tree view control. This font is applied to all the item labels. Similarly, all the labels are of the same color. Although the next version of the tree view control will allow the ownerdraw style, for now you have to implement it yourself. Since the tree view control does not have any support for individual item color or font, we have to implement this as an after effect. In plain terms, we draw the labels to our liking after the control has already painted the control window.


There are some constraints that have to be adhered to. Since the tree view control computes the height of the items ( all items have the same height ) based on the window font, if we change the font size we can only decrease it so that the text does not overlap with the other labels. Also, the tree view control, automatically manages the horizontal scrollbar, so it is better to maintain the width of the label. 
 

Step 1: Add member variable to track font and color
Since the control has no support for item font or color, we have to track this information within our program. We use a CMap object to associate these properties with the tree items. The map will contain information for only those items that we explicitly change. We define a nested structure that is used with the CMap object, to hold the color and the font information. 
 
 
 
  1. protected:
  2. struct Color_Font
  3. {
  4. COLORREF color;
  5. LOGFONT  logfont;
  6. };
  7. CMap< void*, void*, Color_Font, Color_Font& > m_mapColorFont ;
Step 2: Add helper functions to get/set font and color
Define the helper functions to get or set the item font or color. To set the font, we actually pass the logfont rather than a font handle. Also note that we have defined a pair of functions to get and set the bold attribute. There are two reasons for providing a separate function for the bold attribute although we can use the font function. The first reason is that the tree view control directly supports setting an item to bold. Secondly, using the built in support also maintains the proper setting for the horizontal scrollbar. 
 
 
 
  1. void CTreeCtrlX::SetItemFont(HTREEITEM hItem, LOGFONT& logfont)
  2. {
  3. Color_Font cf;
  4. if( !m_mapColorFont.Lookup( hItem, cf ) )
  5. cf.color = (COLORREF)-1;
  6. cf.logfont = logfont;
  7. m_mapColorFont[hItem] = cf;
  8. }
  9.  
  10. void CTreeCtrlX::SetItemBold(HTREEITEM hItem, BOOL bBold)
  11. {
  12. SetItemState( hItem, bBold ? TVIS_BOLD: 0, TVIS_BOLD );
  13. }
  14.  
  15. void CTreeCtrlX::SetItemColor(HTREEITEM hItem, COLORREF color)
  16. {
  17. Color_Font cf;
  18. if( !m_mapColorFont.Lookup( hItem, cf ) )
  19. cf.logfont.lfFaceName[0] = '\0';
  20. cf.color = color;
  21. m_mapColorFont[hItem] = cf;
  22. }
  23.  
  24. BOOL CTreeCtrlX::GetItemFont(HTREEITEM hItem, LOGFONT * plogfont)
  25. {
  26. Color_Font cf;
  27. if( !m_mapColorFont.Lookup( hItem, cf ) )
  28. return FALSE;
  29. if( cf.logfont.lfFaceName[0] == '\0' ) 
  30. return FALSE;
  31. *plogfont = cf.logfont;
  32. return TRUE;
  33.  
  34. }
  35.  
  36. BOOL CTreeCtrlX::GetItemBold(HTREEITEM hItem)
  37. {
  38. return GetItemState( hItem, TVIS_BOLD ) & TVIS_BOLD;
  39. }
  40.  
  41. COLORREF CTreeCtrlX::GetItemColor(HTREEITEM hItem)
  42. {
  43. // Returns (COLORREF)-1 if color was not set
  44. Color_Font cf;
  45. if( !m_mapColorFont.Lookup( hItem, cf ) )
  46. return (COLORREF)-1;
  47. return cf.color;
  48.  
  49. }
Step 3: Add WM_PAINT handler
In this function we first let the control update a memory device context. We then redraw the visible labels using the user defined attributes. We let the control handle the highlighting of items, so before we update a label we make sure that it is not selected or drophilited. Also, if the items font or color attributes were not changed, we don't need to redraw it. Once all the updates are ready in the memory device context, we blit it to the actual device context.

Enabling a More Natural Future for Your Application User Interfaces
In the first implementation, I let the control directly draw on the screen and then redrew the items that had a different font or color. This caused a visible flicker as the items got updated a second time. To overcome this we use a memory device context for all the updates and finally we copy this to the main device context. After creating a compatible DC, we add a compatible bitmap to the memory DC and set the clip region to be the same as the paint DC.

After the default window procedure for the control has updated the device context, we scan through all the visible items and update the items that have a user defined color or font.

 
 
  1. void CTreeCtrlX::OnPaint()
  2. {
  3. CPaintDC dc(this);
  4.  
  5. // Create a memory DC compatible with the paint DC
  6. CDC memDC;
  7. memDC.CreateCompatibleDC( &dc );
  8.  
  9. CRect rcClip, rcClient;
  10. dc.GetClipBox( &rcClip );
  11. GetClientRect(&rcClient);
  12.  
  13. // Select a compatible bitmap into the memory DC
  14. CBitmap bitmap;
  15. bitmap.CreateCompatibleBitmap( &dc, rcClient.Width(), rcClient.Height() );
  16. memDC.SelectObject( &bitmap );
  17. // Set clip region to be same as that in paint DC
  18. CRgn rgn;
  19. rgn.CreateRectRgnIndirect( &rcClip );
  20. memDC.SelectClipRgn(&rgn);
  21. rgn.DeleteObject();
  22.  
  23.  
  24. // First let the control do its default drawing.
  25. CWnd::DefWindowProc( WM_PAINT, (WPARAM)memDC.m_hDC, 0 );
  26.  
  27.  
  28. HTREEITEM hItem = GetFirstVisibleItem();
  29.  
  30. int n = GetVisibleCount()+1;
  31. while( hItem && n--)
  32. {
  33. CRect rect;
  34.  
  35. // Do not meddle with selected items or drop highlighted items
  36. UINT selflag = TVIS_DROPHILITED | TVIS_SELECTED;
  37. Color_Font cf;
  38. if ( !(GetItemState( hItem, selflag ) & selflag )
  39. && m_mapColorFont.Lookup( hItem, cf ))
  40. {
  41. CFont *pFontDC;
  42. CFont fontDC;
  43. LOGFONT logfont;
  44.  
  45. if( cf.logfont.lfFaceName[0] != '\0' )
  46. {
  47. logfont = cf.logfont;
  48. }
  49. else
  50. {
  51. // No font specified, so use window font
  52. CFont *pFont = GetFont();
  53. pFont->GetLogFont( &logfont );
  54. }
  55.  
  56. if( GetItemBold( hItem ) )
  57. logfont.lfWeight = 700;
  58. fontDC.CreateFontIndirect( &logfont );
  59. pFontDC = memDC.SelectObject( &fontDC );
  60.  
  61. if( cf.color != (COLORREF)-1 )
  62. memDC.SetTextColor( cf.color );
  63.  
  64. CString sItem = GetItemText( hItem );
  65.  
  66. GetItemRect( hItem, &rect, TRUE );
  67. memDC.SetBkColor( GetSysColor( COLOR_WINDOW ) );
  68. memDC.TextOut( rect.left+2, rect.top+1, sItem );
  69. memDC.SelectObject( pFontDC );
  70. }
  71. hItem = GetNextVisibleItem( hItem );
  72. }
  73.  
  74.  
  75. dc.BitBlt( rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(), &memDC,
  76. rcClip.left, rcClip.top, SRCCOPY );
  77. }
  78.  
Step 4: Go ahead and change the item font or color
Here are some examples. 
 
 
 
  1. // Change the item color to red
  2. SetItemColor( hItem, RGB(255,0,0));
  3.  
  4. // Change the item to italicized font and underlined
  5. LOGFONT logfont;
  6. CFont *pFont = GetFont();
  7. pFont->GetLogFont( &logfont );
  8. logfont.lfItalic = TRUE;
  9. logfont.lfUnderline = TRUE;
  10. SetItemFont(hti, logfont );
 



Comments

  • 123
    Posted by sunbaogang on 01/15/2009 03:42am

    thanks

    Reply
  • Here it is!
    Posted by appleiii on 04/12/2007 01:28am

    thanks a lot. this is exactly what I want.

    Reply
  • Correct background color
    Posted by gizmocuz on 11/19/2005 03:24pm

    For correct background color change this line memDC.SetBkColor( GetSysColor( COLOR_WINDOW ) ); to memDC.SetBkColor( GetBkColor() );

    Reply
  • Nice and helpful
    Posted by portugalec on 05/26/2005 10:34am

    I found this code very helpful. Bit tricky, but works fine. Since there is no "SetItemColor" support from MFC for TreeCtrl, this solution with "drawing over item" is quite smart:-) Well done!

    Reply
  • Nice and helpful
    Posted by portugalec on 05/26/2005 10:32am

    I found this code very helpful. Bit tricky, but works fine. Since there is no "SetItemColor" support from MFC for TreeCtrl, this solution with "drawing over item" is quite smart:-) Well done!

    Reply
  • it's perfect
    Posted by xingshi on 08/25/2004 10:11pm

    it's perfect

    Reply
  • we should add DeleteAllItems( ) for correct working
    Posted by Legacy on 09/05/2003 12:00am

    Originally posted by: talai

    BOOL CTreeCtrlX::DeleteAllItems() 

    m_mapColorFont.RemoveAll(); 
    return CTreeCtrl::DeleteAllItems(); 

    Reply
  • Short Circuit Problem?
    Posted by Legacy on 08/18/2003 12:00am

    Originally posted by: Ed

    I found that the if statement:
    
    

    if ( !(GetItemState( hItem, selflag ) & selflag ) && m_mapColorFont.Lookup( hItem, cf ))

    caused some problems if I had an else that relied on the Lookup function as well. So I just switched the two around and that seemed to fix my problem:

    if ( m_mapColorFont.Lookup( hItem, cf ) && !(GetItemState( hItem, selflag ) & selflag ))

    Reply
  • Text v-alignment
    Posted by Legacy on 07/31/2002 12:00am

    Originally posted by: jared007

    Hi, Im pretty stumped here....

    I have a control, just as this example, w/ buttons and custom text fonts. How can I gain reference to the height of the button (+,-) in the control, so I can draw the text the same height as it, and vertically align it with the button.

    Right now, when I change the font, the text often appears vertically aligned above the button. How far it is drawn above the button depends on the font type an weight, but I would guess it ranges from 1 - 3 pixels.

    Reply
  • Better way to change color of item using Custom Draw.
    Posted by Legacy on 06/10/2002 12:00am

    Originally posted by: Rudy Kappert

    NMTVCUSTOMDRAW nvcustom;
    
    

    .. ..

    case WM_NOTIFY: nvcustom=*((NMTVCUSTOMDRAW*)lParam); switch(nvcustom.nmcd.hdr.code) { case NM_CUSTOMDRAW: switch(nvcustom.nmcd.dwDrawStage) { case CDDS_PREPAINT: return CDRF_NOTIFYITEMDRAW; case CDDS_ITEMPREPAINT: switch(nvcustom.iLevel) { case 0: // root item SetTextColor(nvcustom.nmcd.hdc,RGB(0,0,0)); break; case 1: // child of root item SetTextColor(nvcustom.nmcd.hdc,RGB(0,0,0)); break; } return CDRF_NEWFONT; } }

    Reply
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值