How To Handle NM_CUSTOMDRAW event to retrieve List items

南楼画角 提交于 2021-02-08 10:30:34

问题


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


回答1:


First, if you need to detect adding of single items, why don't you handle the LVN_INSERTITEM message? I mean, that's what that message is for. Handling NM_CUSTOMDRAW instead is the wrong way, since you won't necessarily get that notification if the control is hidden, your window minimized, ...

In your OnCustomDraw() you always get the same ID: that's because the list control always draws all visible items, so you get the ID of the first visible item. If you set a breakpoint there, then on the next run the control gets refreshed and the drawing starts again from the first visible item.

Note: since you're handling NM_CUSTOMDRAW, you won't get any notification of added items that are not inserted into the visible part of the control! So as I mentioned, you should handle LVN_INSERTITEM instead.




回答2:


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



来源:https://stackoverflow.com/questions/10649836/how-to-handle-nm-customdraw-event-to-retrieve-list-items

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!