[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 426
  • Last Modified:

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

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
Theurgist
Asked:
Theurgist
1 Solution
 
mikeblasCommented:
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
 
gturnerCommented:
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: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

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.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now