Solved

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

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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

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

Suggested Solutions

Introduction: Ownerdraw of the grid button.  A singleton class implentation and usage. Continuing from the fifth article about sudoku.   Open the project in visual studio. Go to the class view – CGridButton should be visible as a class.  R…
Have you tried to learn about Unicode, UTF-8, and multibyte text encoding and all the articles are just too "academic" or too technical? This article aims to make the whole topic easy for just about anyone to understand.
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.
You have products, that come in variants and want to set different prices for them? Watch this micro tutorial that describes how to configure prices for Magento super attributes. Assigning simple products to configurable: We assigned simple products…

932 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

10 Experts available now in Live!

Get 1:1 Help Now