eventsmfcondrawwin32guiclistctrl

How To Handle NM_CUSTOMDRAW event to retrieve List items


I'm working on a win32/MFC project. I have a custom CListCtrl control that I must to add, from time to time, some strings of characters. I absolutely need to perform some manipulations on items dynamically added to my CListCtrl.

Ultra-Basically, I need to:

  1. Detect adding of single elements;
  2. Retrieve _single items_ IMMEDIATELY AFTER(ideally, shortly after InsertItem() invocation);
  3. Store values of single items in a map, which I will use to perform other manipulations.

I thought about doing this overriding the method DrawItem(). but OnDraw event seems not to be available for my CListCtrl.

Event is never generated.

IMPORTANT: Please note that MyCustomCListCtrl have "On Draw Fixed" property set to True, but "View" property is NOT set as a report.

So, I have decided to handle NW_CUSTOMDRAW event, writing my CustomDraw Handler, as explained here and here:

Here you can view another code example.

Then, I need a way to retrieve single itemIDs from my CListCtrl.
More precisely, I need a way to get single item IDs from NMHDR struct.

How can I do this? I am only able to obtain the ID of the LAST item that I have added. I am sure it's a simple mistake I can't find.

A sample piece of code below:

Source of Dialog that contains CList Ctrl:

/* file MyDlg.cpp */

#include "stdafx.h"
#include "MyDlg.h"

// MyDlg dialog

IMPLEMENT_DYNAMIC(MyDlg, CDialog)

MyDlg::MyDlg(CWnd* pParent)
    : CDialog(MyDlg::IDD, pParent)
{
}

MyDlg::~MyDlg()
{
}

void MyDlg::DoDataExchange(CDataExchange* pDX)
{
    CDialog::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_LIST1, listView); /* listView is a MyCustomCListCtrl object */
}

BEGIN_MESSAGE_MAP(MyDlg, CDialog)
    ON_BN_CLICKED(IDC_BUTTON1, &MyDlg::OnBnClickedButton1) 
END_MESSAGE_MAP()

BOOL MyDlg::OnInitDialog()
{
    CDialog::OnInitDialog();
    return TRUE;
}

/* OnBnClickedButton1 handler add new strings to MyCustomCListCtrl object */

void MyDlg::OnBnClickedButton1()
{
    listView.InsertItem(0, "Hello,");
    listView.InsertItem(1, "World!");
}

My Custom CList Ctrl source:

/* file MyCustomCListCtrl.cpp */

#include "stdafx.h"
#include "MyCustomCListCtrl.h"

MyCustomCListCtrl::MyCustomCListCtrl()
{
}

MyCustomCListCtrl::~MyCustomCListCtrl()
{
}

BEGIN_MESSAGE_MAP(MyCustomCListCtrl, CListCtrl)
    //{{AFX_MSG_MAP(MyCustomCListCtrl)
    //}}AFX_MSG_MAP
    // ON_WM_DRAWITEM()                             /* WM_DRAWITEM NON-AVAILABLE */
    ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
END_MESSAGE_MAP()

// 'Owner Draw Fixed' property is already TRUE
/*  void CTranslatedCListCtrl::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
    bool inside = true; /* Member function removed: I never enter here... */
}  */

void MyCustomCListCtrl::OnCustomDraw(NMHDR* pNMHDR, LRESULT* pResult)
{
    /* Here, I must retrieve single strings added to my MyCustomCListCtrl object */

    LPNMLISTVIEW plvInfo = (LPNMLISTVIEW)pNMHDR;
    LVITEM lvItem;

    lvItem.iItem = plvInfo->iItem;          /* Here I always get _the same_ ID: ID of last element...*/
    lvItem.iSubItem = plvInfo->iSubItem;    // subItem not used, for now...

    int MyID = 0;

    this->GetItem(&lvItem); // There mai be something error here?
    MyID = lvItem.iItem;

    CString str = this->GetItemText(MyID, 0); /* ...due to previous error, here I will always get the last string I have added("World!") */

    // Immediately after obtaining ALL IDS, I can Do My Work

    *pResult = 0;
}

Any help is appreciated!

P.S. Please do not give me tips like:

  1. Set your "Own Draw Fixed" Property to True;
  2. Check you have inserted the line "ON_WMDRAWITEM()"
  3. Convert your CListCtrl as a report;

I have already tried everything... :-)

Thanks to all!

IT


Solution

  • first of all... Thank you wasted your precious time with this stupid question. I never found anything about LVN_INSERT event. I write scientific software(most on Linux platform); I am not a long-time Win32 developer, so I don't know Win32 APIs in depth. I have modified source file of MyCustomCListCtrl class, as you have suggested. Code below seems to be the best( and faster )way to achieve what I want:

        /* file MyCustomCListCtrl.cpp */
    
        #include "stdafx.h"
        #include "MyCustomCListCtrl.h"
    
        MyCustomCListCtrl::MyCustomCListCtrl()
        {
        }
    
        MyCustomCListCtrl::~MyCustomCListCtrl()
        {
        }
    
        BEGIN_MESSAGE_MAP(MyCustomCListCtrl, CListCtrl)
            //{{AFX_MSG_MAP(MyCustomCListCtrl)
            //}}AFX_MSG_MAP
            ON_NOTIFY_REFLECT(LVN_INSERTITEM, OnLvnInsertItem)
        END_MESSAGE_MAP()
    
        ...
    
        afx_msg void CTranslatedListCtrl::OnLvnInsertItem(NMHDR* pNMHDR, LRESULT* pResult)
        {
            LPNMLISTVIEW plvInfo = (LPNMLISTVIEW)pNMHDR;
            CString str = this->GetItemText(plvInfo->iItem, 0);
    
            // Add Some Logic
    
            *pResult = 0;
        }
    

    Can You confirm? From what I can see, it seems to work. :-) Thanks again!

    IT