Custom Draw ListView Controls, Part II

The next step is to add a handler for the NM_CUSTOMDRAW notification message. Usually, to add a handler, one can simply right-click on CListCtrlWithCustomDraw in the class view, or use the WizardBar, and "Add windows message handler." However, this time there is a catch. NM_CUSTOMDRAW is nowhere to be seen in the list of available messages.

Well, it looks like the wizard is not going to do the job this time. However, we can get it to help. I find the easiest way to add a handler is to pick a similar message and then edit the resultant code. Even though the Wizard did not know about the message in the first place, it will quite happily work with the modified handler that results. In this case, I used the NM_OUTOFMEMORY. However, in order to reduce the amount of editing needed, I changed the name of the handler function to "OnCustomdraw".

Now you can dive into the generated source code and manually edit the message map in the source file and change:

ON_NOTIFY_REFLECT(NM_OUTOFMEMORY, OnCustomdraw)
to read:
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomdraw)
When you look at the resulting OnCustomdraw function there are two arguments: pNMHDR and pResult. pResult is where we will set the flags that indicate when we want further custom draw messages and whether or not to use the default painting. For a List View control, the pNMHDR is actually a pointer to a NMLVCUSTOMDRAW structure (notification message for ListView custom draw) that tells us about the current drawing stage, what item or subitems we are looking at, and so forth.

We could edit the function declaration so it passes a NMLVCUSTOMDRAW*, but instead we can safely cast the pNMHDR from NMHDR* to NMLVCUSTOMDRAW* to give access to the data, even though these are distinct and separate structures.

As an aside, those from a C++ background may ask why NMLVCUSTOMDRAW does not simply derive from NMHDR in the first place. Well, that sort of thing just does not happen in the Windows SDK API. Because Microsoft designed the SDK API to work with both C and C++, it cannot use any C++ specific language features. That means all the structures in the SDK are PODs (plain old data structures) with no member functions, inheritance, and so on.

But all is not lost.

To get a similar effect to inheritance the SDK uses a C technique; the first member of a 'derived' struct is an instance of the 'base' struct. In this particular case, we have (with simplified declarations):

typedef struct { 
 HWND hwndFrom; 
 UINT idFrom; 
 UINT code; 
} NMHDR;

typedef struct {
 NMHDR  hdr;
 DWORD  dwDrawStage;
} NMCUSTOMDRAW;

typedef struct {
 NMCUSTOMDRAW nmcd;
 COLORREF clrText;
} NMLVCUSTOMDRAW;
Because NMLVCUSTOMDRAW is a POD, a pointer to a NMLVCUSTOMDRAW is also a pointer to its first member (nmcd), in other words a pointer to a NMCUSTOMDRAW. This in turn is a pointer to the first member of NMCUSTOMDRAW (hdr), which is a NMHDR. Therefore, it is quite legitimate to pass a pointer to a NMCUSTOMDRAW structure using a pointer to a NMHDR and cast it as required.

Now, on with the show.

The CListCtrlWithCustomDraw Class

In the OnCustomdraw for CListCtrlWithCustomDraw, I provide a generic handler for custom draw notifications. The bulk of the code is a switch statement on the draw stage we are up to (refer to my previous article). At each of the pre-paint stages, I call virtual functions to get color information, fonts required, and to take over (or augment) the drawing process. I also allow for extra drawing during the post-paint stages.

Let's look at the fleshed out OnCustomdraw function for CListCtrlWithCustomDraw:

void CListCtrlWithCustomDraw::OnCustomdraw(NMHDR* pNMHDR, 
                                           LRESULT* pResult) 
{
 // first, lets extract data from
 // the message for ease of use later
 NMLVCUSTOMDRAW* pNMLVCUSTOMDRAW = (NMLVCUSTOMDRAW*)pNMHDR;

 // we'll copy the device context into hdc 
 // but won't convert it to a pDC* until (and if)
 // we need it as this requires a bit of work
 // internally for MFC to create temporary CDC
 // objects
 HDC hdc = pNMLVCUSTOMDRAW->nmcd.hdc;
 CDC* pDC = NULL;

 // here is the item info
 // note that we don't get the subitem
 // number here, as this may not be
 // valid data except when we are
 // handling a sub item notification
 // so we'll do that separately in
 // the appropriate case statements
 // below.
 int nItem = pNMLVCUSTOMDRAW->nmcd.dwItemSpec;
 UINT nState = pNMLVCUSTOMDRAW->nmcd.uItemState;
 LPARAM lParam = pNMLVCUSTOMDRAW->nmcd.lItemlParam;

 // next we set up flags that will control
 // the return value for *pResult
 bool bNotifyPostPaint = false;
 bool bNotifyItemDraw = false;
 bool bNotifySubItemDraw = false;
 bool bSkipDefault = false;
 bool bNewFont = false;

 // what we do next depends on the
 // drawing stage we are processing
 switch (pNMLVCUSTOMDRAW->nmcd.dwDrawStage) {
  case CDDS_PREPAINT:
  {
   // PrePaint
   m_pOldItemFont = NULL;
   m_pOldSubItemFont = NULL;
   
   bNotifyPostPaint = IsNotifyPostPaint();
   bNotifyItemDraw = IsNotifyItemDraw();
  
   // do we want to draw the control ourselves?
   if (IsDraw()) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
     CRect r(pNMLVCUSTOMDRAW->nmcd.rc);
   
    // do the drawing
    if (OnDraw(pDC,r)) {
     // we drew it all ourselves
     // so don't do default
     bSkipDefault = true;
    }
   }
  }
  break;

  case CDDS_ITEMPREPAINT:
  {
   // Item PrePaint
   m_pOldItemFont = NULL;
  
   bNotifyPostPaint = IsNotifyItemPostPaint(nItem,nState,lParam);
   bNotifySubItemDraw = IsNotifySubItemDraw(nItem,nState,lParam);

   // set up the colors to use
   pNMLVCUSTOMDRAW->clrText = 
    TextColorForItem(nItem,nState,lParam);

   pNMLVCUSTOMDRAW->clrTextBk = 
    BkColorForItem(nItem,nState,lParam);

   // set up a different font to use, if any
   CFont* pNewFont = FontForItem(nItem,nState,lParam);
   if (pNewFont) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
     m_pOldItemFont = pDC->SelectObject(pNewFont);

    bNotifyPostPaint = true; // need to restore font
   }

   // do we want to draw the item ourselves?
   if (IsItemDraw(nItem,nState,lParam)) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
   
    if (OnItemDraw(pDC,nItem,nState,lParam)) {
     // we drew it all ourselves
     // so don't do default
     bSkipDefault = true;
    }
   }
  }
  break;

  case CDDS_ITEMPREPAINT|CDDS_SUBITEM:
  {
   // Sub Item PrePaint
   // set sub item number (data will be valid now)
   int nSubItem = pNMLVCUSTOMDRAW->iSubItem;
  
   m_pOldSubItemFont = NULL;
  
   bNotifyPostPaint = 
    IsNotifySubItemPostPaint(nItem, nSubItem, nState, lParam);

   // set up the colors to use
   pNMLVCUSTOMDRAW->clrText = 
    TextColorForSubItem(nItem,nSubItem,nState,lParam);

   pNMLVCUSTOMDRAW->clrTextBk = 
    BkColorForSubItem(nItem,nSubItem,nState,lParam);

   // set up a different font to use, if any
   CFont* pNewFont = 
    FontForSubItem(nItem, nSubItem, nState, lParam);

   if (pNewFont) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
     m_pOldSubItemFont = pDC->SelectObject(pNewFont);
   
     bNotifyPostPaint = true;    // need to restore font
    }
   
    // do we want to draw the item ourselves?
    if (IsSubItemDraw(nItem,nSubItem,nState,lParam)) {
     if (! pDC) pDC = CDC::FromHandle(hdc);
      if (OnSubItemDraw(pDC,nItem,nSubItem,nState,lParam)) {
    
     // we drew it all ourselves
     // so don't do default
     bSkipDefault = true;
    }
   }
  }
  break;

  case CDDS_ITEMPOSTPAINT|CDDS_SUBITEM:
  {
   // Sub Item PostPaint
   // set sub item number (data will be valid now)
   int nSubItem = pNMLVCUSTOMDRAW->iSubItem;
  
   // restore old font if any
   if (m_pOldSubItemFont) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
     pDC->SelectObject(m_pOldSubItemFont);
  
    m_pOldSubItemFont = NULL;
   }
  
   // do we want to do any extra drawing?
   if (IsSubItemPostDraw()) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
    OnSubItemPostDraw(pDC,nItem,nSubItem,nState,lParam);
   }
  }
  break;

  case CDDS_ITEMPOSTPAINT:
  {
   // Item PostPaint
   // restore old font if any
   if (m_pOldItemFont) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
    pDC->SelectObject(m_pOldItemFont);
    m_pOldItemFont = NULL;
   }
  
   // do we want to do any extra drawing?
   if (IsItemPostDraw()) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
     OnItemPostDraw(pDC,nItem,nState,lParam);
   }
  }
  break;

  case CDDS_POSTPAINT:
  {
   // Item PostPaint
   // do we want to do any extra drawing?
   if (IsPostDraw()) {
    if (! pDC) pDC = CDC::FromHandle(hdc);
     CRect r(pNMLVCUSTOMDRAW->nmcd.rc);

    OnPostDraw(pDC,r);
   }
  }
  break;
 }

 ASSERT(CDRF_DODEFAULT==0);
 *pResult = 0;
 if (bNotifyPostPaint) {
  *pResult |= CDRF_NOTIFYPOSTPAINT;
 }

 if (bNotifyItemDraw) {
  *pResult |= CDRF_NOTIFYITEMDRAW;
 }

 if (bNotifySubItemDraw) {
  *pResult |= CDRF_NOTIFYSUBITEMDRAW;
 }

 if (bNewFont) {
  *pResult |= CDRF_NEWFONT;
 }

 if (bSkipDefault) {
  *pResult |= CDRF_SKIPDEFAULT;
 }

 if (*pResult == 0) {
  // redundant as CDRF_DODEFAULT==0 anyway
  // but shouldn't depend on this in our code
  *pResult = CDRF_DODEFAULT;
 }
}

Phew! That's a fair bit of code. The good news? There's less code left for us to write when we derive from CListCtrlWithCustomDraw.

To make this work, those virtual functions need to be defined. The defaults for these functions are to do nothing; so using the CListCtrlWithCustomDraw on its own will work the same as a standard list control. It is only when you derive from this class and override some of the virtual functions that the ListView control changes appearance. If you do not override them, then you get the standard behaviour.

To start with, here are the additions to the class declaration for CListCtrlWithCustomDraw:

protected:
 CFont* m_pOldItemFont;
 CFont* m_pOldSubItemFont;

 //
 // Callbacks for whole control
 //
	
 // do we want to do the drawing ourselves?
 virtual bool IsDraw() { return false; }
 
 // if we are doing the drawing ourselves
 // override and put the code in here
 // and return TRUE if we did indeed do
 // all the drawing ourselves
 virtual bool OnDraw(CDC* /*pDC*/, const CRect& /*r*/) 
 { return false; }
 
 // do we want to handle custom draw for
 // individual items
 virtual bool IsNotifyItemDraw() { return false; }
 
 // do we want to be notified when the
 // painting has finished
 virtual bool IsNotifyPostPaint() { return false; }
 
 // do we want to do any drawing after
 // the list control is finished
 virtual bool IsPostDraw() { return false; }
 
 // if we are doing the drawing afterwards ourselves
 // override and put the code in here
 // the return value is not used here
 virtual bool OnPostDraw(CDC* /*pDC*/, const CRect& /*r*/) 
 { return false; }
	
 //
 // Callbacks for each item
 //
	
 // return a pointer to the font to use for this item.
 // return NULL to use default
 virtual CFont* FontForItem(int /*nItem*/, 
                            UINT /*nState*/, 
                            LPARAM /*lParam*/) 
 { return NULL; }
 
 // return the text color to use for this item
 // return CLR_DEFAULT to use default
 virtual COLORREF TextColorForItem(int /*nItem*/, 
                                   UINT /*nState*/, 
                                   LPARAM /*lParam*/) 
 { return CLR_DEFAULT; }
 
 // return the background color to use for this item
 // return CLR_DEFAULT to use default
 virtual COLORREF BkColorForItem(int /*nItem*/, 
                                 UINT /*nState*/, 
                                 LPARAM /*lParam*/) 
 { return CLR_DEFAULT; }
 
 // do we want to do the drawing for this item ourselves?
 virtual bool IsItemDraw(int /*nItem*/, 
                         UINT /*nState*/, 
                         LPARAM /*lParam*/) 
 { return false; }
 
 // if we are doing the drawing ourselves
 // override and put the code in here
 // and return TRUE if we did indeed do
 // all the drawing ourselves
 virtual bool OnItemDraw(CDC* /*pDC*/, 
                         int /*nItem*/, 
                         UINT /*nState*/, 
                         LPARAM /*lParam*/) 
 { return false; }
 
 // do we want to handle custom draw for
 // individual sub items
 virtual bool IsNotifySubItemDraw(int /*nItem*/, 
                                  UINT /*nState*/, 
                                  LPARAM /*lParam*/) 
 { return false; }
 
 // do we want to be notified when the
 // painting has finished
 virtual bool IsNotifyItemPostPaint(int /*nItem*/, 
                                    UINT /*nState*/, 
                                    LPARAM /*lParam*/) 
 { return false; }
 
 // do we want to do any drawing after
 // the list control is finished
 virtual bool IsItemPostDraw() { return false; }
 
 // if we are doing the drawing afterwards ourselves
 // override and put the code in here
 // the return value is not used here
 virtual bool OnItemPostDraw(CDC* /*pDC*/, 
                             int /*nItem*/, 
                             UINT /*nState*/, 
                             LPARAM /*lParam*/) 
 { return false; }

 //
 // Callbacks for each sub item
 //
	
 // return a pointer to the font to use for this sub item.
 // return NULL to use default
 virtual CFont* FontForSubItem(int /*nItem*/, 
                               int /*nSubItem*/, 
                               UINT /*nState*/, 
                               LPARAM /*lParam*/) 
 { return NULL; }
 
 // return the text color to use for this sub item
 // return CLR_DEFAULT to use default
 virtual COLORREF TextColorForSubItem(int /*nItem*/, 
                                      int /*nSubItem*/, 
                                      UINT /*nState*/, 
                                      LPARAM /*lParam*/) 
 { return CLR_DEFAULT; }
 
 // return the background color to use for this sub item
 // return CLR_DEFAULT to use default
 virtual COLORREF BkColorForSubItem(int /*nItem*/, 
                                    int /*nSubItem*/, 
                                    UINT /*nState*/, 
                                    LPARAM /*lParam*/) 
 { return CLR_DEFAULT; }
 
 // do we want to do the drawing for this sub item ourselves?
 virtual bool IsSubItemDraw(int /*nItem*/, 
                            int /*nSubItem*/, 
                            UINT /*nState*/, 
                            LPARAM /*lParam*/) 
 { return false; }
 
 // if we are doing the drawing ourselves
 // override and put the code in here
 // and return TRUE if we did indeed do
 // all the drawing ourselves
 virtual bool OnSubItemDraw(CDC* /*pDC*/, 
                            int /*nItem*/, 
                            int /*nSubItem*/, 
                            UINT /*nState*/, 
                            LPARAM /*lParam*/) 
 { return false; }
 
 // do we want to be notified when the
 // painting has finished
 virtual bool IsNotifySubItemPostPaint(int /*nItem*/, 
                                       int /*nSubItem*/, 
                                       UINT /*nState*/, 
                                       LPARAM /*lParam*/) 
 { return false; }
 
 // do we want to do any drawing after
 // the list control is finished
 virtual bool IsSubItemPostDraw() { return false; }
 
 // if we are doing the drawing afterwards ourselves
 // override and put the code in here
 // the return value is not used here
 virtual bool OnSubItemPostDraw(CDC* /*pDC*/, 
                                int /*nItem*/, 
                                int /*nSubItem*/, 
                                UINT /*nState*/, 
                                LPARAM /*lParam*/) 
 { return false; }
There is quite a bit of code here as well. Again, there is good new. Each of the virtual functions performs a simple and well-defined task. The OnCustomdraw function does all the housework and ties everything together.

Well, that about wraps it up for our CListCtrlWithCustomDraw class. The last step is to derive a class from CListCtrlWithCustomDraw.

Using the CListCtrlWithCustomDraw Class

Again, we can use the WizardBar to create a new class. And as before it can be done with a little hacking. Start off by defining a class call CMyListCtrl, and say that it is an MFC class derived from CListCtrl. Then edit the .h and .cpp files that are generated, change all occurrences of CListCtrl to CListCtrlWithCustomDraw, and finally add a #include "ListCtrlWithCustomDraw.h" line to the .h file, just before the class declaration. Once you have the skeleton CMyListCtrl, we can override some of the virtual functions to change the appearance of the control.

For this example, we will paint the entire control in cyan, and then make the individual cells in the list control alternate in colors to give a checkerboard appearance. OK, it is not very pretty, but it illustrates some of the possibilities.

Here are the virtual functions we will override in CMyListCtrl.

virtual bool IsDraw();

virtual bool OnDraw(CDC* pDC, const CRect& r);

virtual bool IsNotifyItemDraw();

virtual bool IsNotifySubItemDraw(int nItem, 
                                 UINT nState, 
                                 LPARAM lParam);

virtual COLORREF TextColorForSubItem(int nItem, 
                                     int nSubItem, 
                                     UINT nState, 
                                     LPARAM lParam);

virtual COLORREF BkColorForSubItem(int nItem, 
                                   int nSubItem, 
                                   UINT nState, 
                                   LPARAM lParam);
And here are their implementations:
bool CMyListCtrl::IsDraw() {
 return true;
}
bool CMyListCtrl::OnDraw(CDC* pDC, const CRect& r) {
 CBrush brush(RGB(0,255,255));	// cyan
 pDC->FillRect(r,&brush);
 return false; // do default drawing as well
}

bool CMyListCtrl::IsNotifyItemDraw() {
 return true;
}
bool CMyListCtrl::IsNotifySubItemDraw(int /*nItem*/, 
                                      UINT /*nState*/, 
                                      LPARAM /*lParam*/) {
 return true;
}
COLORREF CMyListCtrl::TextColorForSubItem(int nItem, 
                                          int nSubItem, 
                                          UINT /*nState*/, 
                                          LPARAM /*lParam*/) {
 if (0 == (nItem+nSubItem)%2) {
  return RGB(255,255,0);	// yellow
 } else {
  return CLR_DEFAULT;
 }
}
COLORREF CMyListCtrl::BkColorForSubItem(int nItem, 
                                        int nSubItem, 
                                        UINT /*nState*/, 
                                        LPARAM /*lParam*/) {
 if (0 == (nItem+nSubItem)%2) {
  return RGB(255,0,255); // magenta
 } else {
  return CLR_DEFAULT;
 }
}
And remember that overriding IsDraw and OnDraw lets you either draw the entire control yourself or just to do some extra work before the default drawing process. In this case, the OnDraw function fills the control with cyan and then returns false to indicate that we still want the default drawing process to continue

If you want to individually change the colors of each cell, override IsNotifyItemDraw and IsNotifySubItemDraw. If you want the sub-items to be custom drawn by returning true from IsNotifySubItemDraw, then you also need to return true from IsNotifyItemDraw. If IsNotifyItemDraw returns false, then there will be no sub-item custom drawing either.

In the TextColorForSubItem, simply do some arithmetic with the item and sub-item number to select either a different color or the default color for the control.

To test this out, add a list control to the main dialog for this application. In the dialog editor, ctrl+double-click on it to associate it with a CMyListCtrl member called m_listctrl., then edit the list control properties in the dialog and set the style to use report view. Then, add some code to the OnInitDialog to define the columns and fill in some data.

m_listctrl.InsertColumn(0,"label",LVCFMT_LEFT,60,0);
m_listctrl.InsertColumn(1,"first",LVCFMT_LEFT,40,1);
m_listctrl.InsertColumn(2,"second",LVCFMT_LEFT,30,2);
m_listctrl.InsertColumn(3,"third",LVCFMT_LEFT,20,3);

int row;
row = m_listctrl.InsertItem(0,"row1");
m_listctrl.SetItem(row,1,LVIF_TEXT,"aaa",0,0,0,0);
m_listctrl.SetItem(row,2,LVIF_TEXT,"bbb",0,0,0,0);
m_listctrl.SetItem(row,3,LVIF_TEXT,"ccc",0,0,0,0);
row = m_listctrl.InsertItem(1,"row2");
m_listctrl.SetItem(row,1,LVIF_TEXT,"AAA",0,0,0,0);
m_listctrl.SetItem(row,2,LVIF_TEXT,"BBB",0,0,0,0);
m_listctrl.SetItem(row,3,LVIF_TEXT,"CCC",0,0,0,0);
row = m_listctrl.InsertItem(2,"row3");
m_listctrl.SetItem(row,1,LVIF_TEXT,"X",0,0,0,0);
m_listctrl.SetItem(row,2,LVIF_TEXT,"YY",0,0,0,0);
m_listctrl.SetItem(row,3,LVIF_TEXT,"ZZZ",0,0,0,0);
The result is a dialog with the cyan background and checkerboard.

Summary

By deriving from ClistCtrlWithCustomDraw and overriding appropriate virtual functions, you can achieve all sorts of result--everything from simple color or font changes to completely drawing all or part of the list control yourself.


Comments

  • How to change item size and gap between them in custom drown CListCtrl

    Posted by maggus on 10/24/2008 03:28pm

    As far as I know ON_WM_MEASUREITEM does not get called in Custom Drown list control. It is only called if control is Owner Drown. So the question is how do you change items size and spacing between them in Custom Drown control?

    Reply
  • Great article!

    Posted by acjohnson on 07/12/2006 08:58am

    Custom draw has solved my list view problems, big time! The only question that remains is why in the world Microsoft left this great feature undocumented???

    Reply
  • Delete font object?

    Posted by ayousif on 11/16/2004 01:46pm

    Thanks for providing this article.  UI code is difficult for me so it's always nice to learn from the experts.  I made one observation and I could be wrong.
    
    My code shown below adds the following line:
    	pNewFont->DeleteObject();
    
    I added this line in both places that look for a different font.  Am I correct in doing this or can there be problems?  My code is working great, so thank you.
    
    if (pNewFont)
    {
    	if (!pDC)
    		pDC = CDC::FromHandle(hdc);
    
    	m_pOldItemFont = pDC->SelectObject(pNewFont);
    	pNewFont->DeleteObject();
    	bNotifyPostPaint = TRUE;// need to restore font
    }

    Reply
  • Please help with row height

    Posted by Legacy on 01/23/2004 12:00am

    Originally posted by: Oksana Kaushanskaja

    I change font name for each item. But font Tahoma and Arial, for example, look differently. Text height may be greater then height of the item. This is no problem for me to change item height in ListView with OwnerDraw style. But I don't know, how to do this in ListView with CustomDraw style. I tried to do so:

    bool COwnListCtrl::OnItemDraw(CDC *pDC, int nItem, UINT nState, LPARAM lParam)
    {
    int newHeight = 0;
    CFont* pFont = pDC->GetCurrentFont();
    if (pFont) {
    LOGFONT lf;
    pFont->GetLogFont(&lf);
    newHeight = (lf.lfHeight > 0) ? lf.lfHeight : -lf.lfHeight;
    }
    CRect r;
    GetItemRect(nItem, &r, LVIR_BOUNDS);
    r.bottom = r.top + newHeight;
    CString str = GetItemText(nItem, 0);
    pDC->DrawText(str, &r, DT_LEFT);
    return true;
    }

    But this code allows only to show all string but no part, but don't changes height of the item. This looks not beautiful. Please, help me to solve this problem.

    Reply
  • Need author's email address

    Posted by Legacy on 04/30/2003 12:00am

    Originally posted by: Milan Markovic

    Does anybody know Roger's new email address. Seems that address given at the top of the article is not valid anymore.

    If anybody is in contact with Roger, please send me his email address at my personal email - marcony@cg.yu.

    Thanks

    Reply
  • Assertion failed in OnSetFocus()

    Posted by Legacy on 03/29/2002 12:00am

    Originally posted by: BlackRider & JohnnyM

    In several cases pOldWnd in OnSetFocus()and probably pNewWnd in OnKillFocus() can point to non-window object.
    Conditions pOldWnd!=NULL and pNewWnd!=NULL can not protect your code from debug assertion failure in GetParent(). I used the following:
    if (pOldWnd && ::IsWindow(pOldWnd->m_hWnd) && pOldWnd->GetParent() == this)

    and
    if (pNewWnd && ::IsWindow(pNewWnd->m_hWnd) && pNewWnd->GetParent() == this)

    BlackRider

    Reply
  • Problem with clrTextBk & clrText on Win2k

    Posted by Legacy on 03/25/2002 12:00am

    Originally posted by: Jean-Sebastien

    Hi,

    I'm using ListCtrl's CustomDraw notification, and the
    clrText & clrTextBk attributes to change text colors.
    My code works well on Win98/Me but displays only
    really few (only black & white) colors on Win2K,
    whatever i set in theses attributes.

    Do i have to create my ListCtrl with special styles ?

    I've the same problems with TreeCtrl.

    Thanks

    Reply
  • Rotate 90 degrees?

    Posted by Legacy on 11/26/2001 12:00am

    Originally posted by: Joachim Wickman

    Have someone got an example on how to rotate the view 90 degrees? Need it in a PDA.
    
    

    Thx

    Reply
  • How to set mutiple text color in one cell

    Posted by Legacy on 10/23/2001 12:00am

    Originally posted by: stephan

    Good idea,

    but do you know how to use multiple text color in one cell?

    Reply
  • How to edit it's subitem?

    Posted by Legacy on 09/11/2001 12:00am

    Originally posted by: slay

    I want to edit the subItem of a Listctrl,can anybody help me?
    thx a lot!

    Reply
  • Loading, Please Wait ...

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

  • IBM Worklight is a mobile application development platform that lets you extend your business to mobile devices. It is designed to provide an open, comprehensive platform to build, run and manage HTML5, hybrid and native mobile apps.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds