【问题标题】:How To Handle NM_CUSTOMDRAW event to retrieve List items如何处理 NM_CUSTOMDRAW 事件以检索列表项
【发布时间】:2012-05-18 09:13:41
【问题描述】:

我正在开发一个 win32/MFC 项目。 我有一个自定义 CListCtrl 控件,我必须不时添加一些字符串。 我绝对需要对动态添加到我的 CListCtrl 的项目执行一些操作。

基本上,我需要:

  1. 检测单个元素的添加;
  2. 检索 _single items_ 立即之后(理想情况下,在 InsertItem() 调用之后不久);
  3. 在地图中存储单个项目的值,我将使用它来执行其他操作。

我考虑过覆盖方法 DrawItem()。但 OnDraw 事件 似乎 不适用于我的 CListCtrl。

永远不会生成事件。

重要提示:请注意,MyCustomCListCtrl 的“On Draw Fixed”属性设置为 True,但“View" 属性NOT设置为报告

所以,我决定处理 NW_CUSTOMDRAW 事件,编写我的 CustomDraw 处理程序,如 herehere 所述:

Here你可以查看另一个代码示例。

然后,我需要一种从 CListCtrl 中检索单个 itemID 的方法。
更准确地说,我需要一种方法从 NMHDR 结构中获取单个项目 ID

我该怎么做? 我只能获得我添加的 LAST 项的 ID。 我确定这是一个我找不到的简单错误。

下面的示例代码:

包含CList Ctrl的Dialog的来源:

/* 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!");
}

我的自定义 CList Ctrl 来源:

/* 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;
}

感谢任何帮助!

附: 请不要给我这样的提示:

  1. 将“Own Draw Fixed”属性设置为 True;
  2. 检查您是否插入了“ON_WMDRAWITEM()”行
  3. 将您的 CListCtrl 转换为报告;

我已经尝试了一切... :-)

谢谢大家!

【问题讨论】:

    标签: events mfc ondraw win32gui clistctrl


    【解决方案1】:

    首先,如果您需要检测添加单个项目,为什么不处理LVN_INSERTITEM 消息?我的意思是,这就是该消息的目的。相反,处理 NM_CUSTOMDRAW 是错误的方法,因为如果控件被隐藏、窗口最小化,您不一定会收到该通知,...

    在您的 OnCustomDraw() 中,您始终获得相同的 ID:这是因为列表控件始终绘制所有可见项目,因此您获得第一个可见项目的 ID。如果您在此处设置断点,则在下一次运行时,控件会刷新并且绘图会从第一个可见项重新开始。

    注意:由于您正在处理 NM_CUSTOMDRAW,因此您不会收到任何未插入控件可见部分的添加项目的通知!因此,正如我所提到的,您应该改为处理 LVN_INSERITEM。

    【讨论】:

      【解决方案2】:

      首先...感谢您在这个愚蠢问题上浪费了宝贵的时间。 我从来没有发现任何关于LVN_INSERT 事件的信息。 我编写科学软件(大多数在 Linux 平台上);我不是长期的 Win32 开发人员,所以我不深入了解 Win32 API。 正如你所建议的,我已经修改了MyCustomCListCtrl 类的源文件。 下面的代码似乎是实现我想要的最好(和更快)的方法:

          /* 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;
          }
      

      你能确认一下吗? 从我所看到的,它似乎工作。 :-) 再次感谢!

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-10-21
        • 1970-01-01
        • 2010-11-20
        • 2012-03-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-27
        相关资源
        最近更新 更多