Solved

How do you change the color of individual items in a Tree Control?

Posted on 1997-03-26
2
364 Views
Last Modified: 2013-11-20
This seems to be the question of the hour on both comp.os.ms-windows.mfc and Microsoft's microsoft.public.vc.mfc newsgroups.  How do you change the color of individual items in a Tree Control?

I've been trying for about a week to set the colors of Text items in a CTreeCtrl object.  From a previous post, I found the ActiveX SDK documentation for NM_CUSTOMDRAW.  Also, MSJ Oct '96 goes over this stuff.

I'm not in love with this method -- I'd be thankful for  anything that works.  Specifically, I'm trying to monitor several machines with a CTreeCtrl and provide a graphical system status by color-coding the items in the tree.  I've heard rumors that other people have managed to change colors with =WM_CTRCOLOR and WM_ERASEBKGRND.  I haven't had any success with that approach, either.

With the NM_CUSTOMDRAW approach, I believe the problem I'm having is that I'm not getting the CDDS_ITEMPREPAINT message.  I pasted the code illustrated in the ActiveX docs into my CView::OnNotify() and NM_CUSTOMDRAW with CCDS_PREPAINT are  being received just fine.  After that, however, only 'default' is being hit in my switch().

Here's my OnNotify() in case someone spots something stupid I've done:

BOOL CFooView::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
  TRACE("CFooView::OnNotify()\n");
  LPNMTREEVIEW pnm = (LPNMTREEVIEW)lParam;
  CFont fonti;

  fonti.CreateFont(-200, 0, 0, 0, FW_NORMAL, TRUE, FALSE, FALSE,ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, "Times New Roman");

  switch (pnm->hdr.code)
  {
  case NM_CUSTOMDRAW:
    {
      TRACE("NM_CUSTOMDRAW\n");
      LPNMTVCUSTOMDRAW  lptvcd = (LPNMTVCUSTOMDRAW)lParam;
      /*
      CDDS_PREPAINT is at the beginning of the paint cycle. You
      implement custom draw by returning the proper value. In this
      case, we're requesting item-specific notifications.
      */
      if (lptvcd->nmcd.dwDrawStage == CDDS_PREPAINT)
      {
        TRACE("CDDS_PREPAINT\n");
        PTREEITEMINFO ptreeitem = (PTREEITEMINFO)lParam;
        TRACE("Item = %Xh\n", ptreeitem->pItem);
        // Request pre-paint notifications for each item.
        return CDRF_NOTIFYITEMDRAW;
      }

      /*
      CDDS_ITEMPREPAINT is sent when the control is about to paint an
      item. We're getting this because we returned CDRF_NOTIFYITEMDRAW
      in response to CDDS_PREPAINT before.
      */
      if (lptvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
      {
        TRACE("CDDS_ITEMPREPAINT\n");
        /*  To change the font, select the desired font into the
        provided HDC. We're changing the font for every third item
        in the control, starting with item zero.
        */
        if (!(lptvcd->nmcd.dwItemSpec % 3))
          SelectObject(lptvcd->nmcd.hdc, fonti);
        else
          return(CDRF_DODEFAULT);
        /*  To change the text and background colors in a list view
        control, set the clrText and clrTextBk members of the
        NMLVCUSTOMDRAW structure to the desired color.

        This differs from most other controls that support
        CustomDraw. To change the text and background colors for
        the others, call SetTextColor and SetBkColor on the provided HDC.
        */
        lptvcd->clrText = RGB(150, 75, 150);
        lptvcd->clrTextBk = RGB(255,255,255);
//      SetTextColor(lptvcd->nmcd.hdc, lptvcd->clrText);
//      SetBkColor(lptvcd->nmcd.hdc, lptvcd->clrTextBk);

        /* We changed the font, so we're returning CDRF_NEWFONT. This
        tells the control to recalculate the extent of the text.
        */
        return CDRF_NEWFONT;
      }
    }
  default:
    TRACE("default\n");
    break;
  }

//  return 0;
  return CView::OnNotify(wParam, lParam, pResult);
}

0
Comment
Question by:Theurgist
2 Comments
 
LVL 11

Accepted Solution

by:
mikeblas earned 200 total points
ID: 1300697
The most obvious problem your code has is the way that you're handling your font.

First, you're creating a font every time you receive a notification message.  Creating a font is a pretty expensive operation, so you should only do so when you need to.

Second, you're selecting the font into the DC you're provided and then you're destroying the font.  That's no good: is surprising your application doesn't get very sick: since you've destroyed the font, there's no way the control can draw with it.

If you create your font as a member of your view (in response to WM_CREATE, for example) and then destroy your font when the view's destructor is called, you'll solve both problems.

Fixing your font management problem will be a huge step in the right direction.  But it's hard to provide you anything more specific because lots of information is missing from your question.  If your problem persists after fixing your mismangement of your CFont, you should tell us:

+ Which version of Windows and MFC you're using.
+ How you're creating your tree control, including which styles it has.
+ telling us what the version stamp on your COMCTL32.DLL is. Unfortunately, MSJ is irresponsible in not pointing out that you need a particular version of the library, and you may or may not have it installed.

.B ekiM

0
 

Expert Comment

by:gturner
ID: 1300698
The reason why the NM_CUSTOMDRAW case is not being hit is that you should be returning the value CDRF_NOTIFYITEMDRAW by placing this value in pResult:

        if(lptvcd->nmcd.dwDrawStage == CDDS_ITEMPREPAINT)
        {
.......
            *pResult = CDRF_NOTIFYITEMDRAW;
            return TRUE;  // TRUE since we handled the WM_NOTIFY message - See OnNotify in online help.
        }

0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

Suggested Solutions

Introduction: Load and Save to file, Document-View interaction inside the SDI. Continuing from the second article about sudoku.   Open the project in visual studio. From the class view select CSudokuDoc and double click to open the header …
Introduction: Hints for the grid button.  Nested classes, templated collections.  Squash that darned bug! Continuing from the sixth article about sudoku.   Open the project in visual studio. First we will finish with the SUD_SETVALUE messa…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…

746 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now