Solved

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

Posted on 1997-03-26
2
382 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

Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Folder Comparison 12 54
ODBC Connection Logging, ADO.NET 6 69
ShiftLeft challenge 21 85
how to use laptop or pad camera in vb.net windows application 2 85
Introduction: Dynamic window placements and drawing on a form, simple usage of windows registry as a storage place for information. Continuing from the first article about sudoku.  There we have designed the application and put a lot of user int…
Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
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.
Email security requires an ever evolving service that stays up to date with counter-evolving threats. The Email Laundry perform Research and Development to ensure their email security service evolves faster than cyber criminals. We apply our Threat…

809 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