主  题:  CTreeCtrl 如何用SetItemData使Item保持额外数据?  
作  者:  huyoo (空格键)  
   
还是先看看下面我写的代码吧~~
定义了两个数据类型
一个枚举类型,ITEM_TYPE
typedef enum tagITEM_TYPE
{
  //数据类型
  TYPE_TYPE_FOLDER=1,TYPE_FILE
}ITEM_TYPE;一个数据结构,用来定义额外数据
struct Extra_DATA
{
//Extra 数据
ITEM_TYPE type;
LPCTSTR url;
};想问一下,我下面的操作,为什么不能使使Item保持额外数据?
难道Item自己没有空间保持额外数据吗?非得要给那些数据分配一些内存?// ExtraTreeView.cpp : implementation of the CExtraTreeView class
//#include "stdafx.h"
#include "Extratest.h"#include "ExtratestDoc.h"
#include "ExtraTreeView.h"
#include "MainFrm.h"#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif/////////////////////////////////////////////////////////////////////////////
// CExtraTreeView
typedef enum tagITEM_TYPE
{
  //数据类型
  TYPE_TYPE_FOLDER=1,TYPE_FILE
}ITEM_TYPE;struct Extra_DATA
{
//Extra 数据
ITEM_TYPE type;
LPCTSTR link;
};
extern CExtratestApp theApp;IMPLEMENT_DYNCREATE(CExtraTreeView, CTreeView)BEGIN_MESSAGE_MAP(CExtraTreeView, CTreeView)
  //{{AFX_MSG_MAP(CExtraTreeView)
  ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
  //}}AFX_MSG_MAP
  // Standard printing commands
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CExtraTreeView construction/destructionCExtraTreeView::CExtraTreeView()
{}
CExtraTreeView::~CExtraTreeView()
{}void CExtraTreeView::OnInitialUpdate()
{
  CTreeView::OnInitialUpdate();  // TODO: You may populate your TreeView with items by directly accessing
  //  its tree control through a call to GetTreeCtrl().
  BuildExtraTreeView(this->m_hWnd);
}
/////////////////////////////////////////////////////////////////////////////
// CExtraTreeView message handlers
BOOL CExtraTreeView::BuildExtraTreeView(HWND hWnd)
{
 HTREEITEM ht;
//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm 
 Extra_DATA *node = new Extra_DATA();
 node->type=TYPE_FOLDER;
 node->url=TEXT("");
 ht=this->GetTreeCtrl().InsertItem(TEXT("我的Extra数据"),0,0,TVI_ROOT,TVI_LAST);    
 this->GetTreeCtrl().SetItemData(ht,(DWORD)node);
 delete node;
 //wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
 
//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm 
node = new Extra_DATA(); node->type=HTTPLINK;
 node->url=TEXT("http://blog.csdn.net/huyoo");
HTREEITEM TempItem1=this->GetTreeCtrl().InsertItem("url11111111111",  ht, TVI_LAST);
this->GetTreeCtrl().SetItemData(TempItem1,(DWORD)node);
delete node;
//wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
node = new Extra_DATA(); node->type=HTTPLINK;
 node->url=TEXT("http://blog.csdn.net");
HTREEITEM TempItem2=this->GetTreeCtrl().InsertItem("url22222222222222",  ht, TVI_LAST);
this->GetTreeCtrl().SetItemData(TempItem2,(DWORD)node);
delete node;
//wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
//url="http://blog.csdn.net/huyoo";
 node->type=HTTPLINK;
 node->url=TEXT("http://www.csdn.net");
HTREEITEM TempItem3=this->GetTreeCtrl().InsertItem("url333333333333333",  ht, TVI_LAST);
this->GetTreeCtrl().SetItemData(TempItem3,(DWORD)node);
//wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
return TRUE;}void CExtraTreeView::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
{
  CString aurl;
  HTREEITEM Item = this->GetTreeCtrl().GetSelectedItem();
   if (!Item)
      return;
      
   Extra_DATA *node = (Extra_DATA *) this->GetTreeCtrl().GetItemData(Item);
//  if(node->type == TYPE_FOLDER)
//  {
//    return;
//  }
//  else
  {
     aurl = LPCTSTR(node->url); //这里取不到TreeCtrl中的额外数据!!!!!
  }
  
  CMainFrame * pmain=(CMainFrame*)AfxGetMainWnd();
  pmain->SetWindowText(aurl);
  *pResult = 0;}

解决方案 »

  1.   

    delete node;这一句不要,因为你放到树节点的data是这个指针而不是这个指针的指向的结构,所有如果delete掉了,data装的指针也就不能访问了。所有分配的内存应该在程序退出时统一delete
      

  2.   

    m_treeCtrl.InsertItem(TVIF_TEXT| TVIF_PARAM,    "TREENAME"
        0,
                          0,
        0,
                          0,   Data,
    TVI_ROOT,          TVI_LAST);
    楼主你写插入节点的时候,第一个参数“TVIF_PARAM”必须带上才能用setdata存入数据,要不然是写不进数据的!
      

  3.   

    同意1楼,去除所有delete node;在程序退出的时候, 清除treectrl结点的所有node
      

  4.   

    老大们啊,最后删除node的时候,三个节点保持的数据是一样的!!
    就是最后那个节点的数据!
      

  5.   

    你应该在处理TVN_DELETEITEM时delete node
      

  6.   

    你可以先不用你自己定义的数据结构来存放额外的数据,用简单类型比如只是用数字代替,看看到底是楼上诸位说的delete node造成的问题,还是其他问题。
    good luck
      

  7.   

    SetItemData只能存储一个32位的数,这个数由你定义,可以是int,long,甚至指针.
    这和windows的消息机制很象. MSG不也有一个lParam吗,道理是一样的.
    至于为什么只提供32位的存储空间,关键是控件本身不知道你要存储的数据空间
    有多大, 数据的结构是什么, 所以控件没法预制分配器,
    这些都是控件用户自己最了解和知道应该怎么分配数据和解读数据,通过GetItemData的
    32位的数据(可能是指针,如果要存储的数据比较大).
      

  8.   

    // ExtraTreeView.cpp : implementation of the CExtraTreeView class
    //#include "stdafx.h"
    #include "Extra.h"#include "ExtraDoc.h"
    #include "ExtraTreeView.h"
    #include "MainFrm.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif/////////////////////////////////////////////////////////////////////////////
    // CExtraTreeView
    typedef enum tagITEM_TYPE
    {
      //数据类型
      TYPE_FOLDER=1,TYPE_FILE
    }ITEM_TYPE;struct Extra_DATA
    {
    //Extra 数据
    ITEM_TYPE type;
    LPCTSTR url;
    };
    extern CExtraApp theApp;IMPLEMENT_DYNCREATE(CExtraTreeView, CTreeView)BEGIN_MESSAGE_MAP(CExtraTreeView, CTreeView)
      //{{AFX_MSG_MAP(CExtraTreeView)
      ON_NOTIFY_REFLECT(NM_CLICK, OnClick)
      //}}AFX_MSG_MAP
      // Standard printing commands
      ON_COMMAND(ID_FILE_PRINT, CTreeView::OnFilePrint)
      ON_COMMAND(ID_FILE_PRINT_DIRECT, CTreeView::OnFilePrint)
      ON_COMMAND(ID_FILE_PRINT_PREVIEW, CTreeView::OnFilePrintPreview)
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CExtraTreeView construction/destructionCExtraTreeView::CExtraTreeView()
    {
      // TODO: add construction code here}CExtraTreeView::~CExtraTreeView()
    {
    }BOOL CExtraTreeView::PreCreateWindow(CREATESTRUCT& cs)
    {
      // TODO: Modify the Window class or styles here by modifying
      //  the CREATESTRUCT cs  return CTreeView::PreCreateWindow(cs);
    }/////////////////////////////////////////////////////////////////////////////
    // CExtraTreeView drawingvoid CExtraTreeView::OnDraw(CDC* pDC)
    {
      CExtraDoc* pDoc = GetDocument();
      ASSERT_VALID(pDoc);
      // TODO: add draw code for native data here
    }void CExtraTreeView::OnInitialUpdate()
    {
      CTreeView::OnInitialUpdate();
      // TODO: You may populate your TreeView with items by directly accessing
      //  its tree control through a call to GetTreeCtrl().
      BuildExtraTreeView(this->m_hWnd);}/////////////////////////////////////////////////////////////////////////////
    // CExtraTreeView printingBOOL CExtraTreeView::OnPreparePrinting(CPrintInfo* pInfo)
    {
      // default preparation
      return DoPreparePrinting(pInfo);
    }void CExtraTreeView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
      // TODO: add extra initialization before printing
    }void CExtraTreeView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
      // TODO: add cleanup after printing
    }/////////////////////////////////////////////////////////////////////////////
    // CExtraTreeView diagnostics#ifdef _DEBUG
    void CExtraTreeView::AssertValid() const
    {
      CTreeView::AssertValid();
    }void CExtraTreeView::Dump(CDumpContext& dc) const
    {
      CTreeView::Dump(dc);
    }CExtraDoc* CExtraTreeView::GetDocument() // non-debug version is inline
    {
      ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CExtraDoc)));
      return (CExtraDoc*)m_pDocument;
    }
    #endif //_DEBUG/////////////////////////////////////////////////////////////////////////////
    // CExtraTreeView message handlers
    BOOL CExtraTreeView::BuildExtraTreeView(HWND hWnd)
    {
     HTREEITEM ht;
    //mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm 
     Extra_DATA *node = new Extra_DATA();
     node->type=TYPE_FOLDER;
     node->url=TEXT("");
     ht=this->GetTreeCtrl().InsertItem(TEXT("我的Extra数据"),0,0,TVI_ROOT,TVI_LAST);    
     this->GetTreeCtrl().SetItemData(ht,(DWORD)node);
     delete node;
     //wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
     
    //mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm 
    node = new Extra_DATA(); node->type=TYPE_FILE;
     node->url=TEXT("http://blog.csdn.net/huyoo");
    HTREEITEM TempItem1=this->GetTreeCtrl().InsertItem("url11111111111",  ht, TVI_LAST);
    this->GetTreeCtrl().SetItemData(TempItem1,(DWORD)node);
    delete node;
    //wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
    node = new Extra_DATA(); node->type=TYPE_FILE;
     node->url=TEXT("http://blog.csdn.net");
    HTREEITEM TempItem2=this->GetTreeCtrl().InsertItem("url22222222222222",  ht, TVI_LAST);
    this->GetTreeCtrl().SetItemData(TempItem2,(DWORD)node);
    delete node;
    //wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww//mmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
    //url="http://blog.csdn.net/huyoo";
     node->type=TYPE_FILE;
     node->url=TEXT("http://www.csdn.net");
    HTREEITEM TempItem3=this->GetTreeCtrl().InsertItem("url333333333333333",  ht, TVI_LAST);
    this->GetTreeCtrl().SetItemData(TempItem3,(DWORD)node);
    //wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww
    return TRUE;}void CExtraTreeView::OnClick(NMHDR* pNMHDR, LRESULT* pResult) 
    {
      // TODO: Add your control notification handler code here
        CString aurl;
      HTREEITEM Item = this->GetTreeCtrl().GetSelectedItem();
       if (!Item)
          return;
          
       Extra_DATA *node = (Extra_DATA *) this->GetTreeCtrl().GetItemData(Item);
    //  if(node->type == TYPE_FOLDER)
    //  {
    //    return;
    //  }
    //  else
      {
         aurl = LPCTSTR(node->url); //这里取不到TreeCtrl中的额外数据!!!!!
      }
      
      CMainFrame * pmain=(CMainFrame*)AfxGetMainWnd();
      pmain->SetWindowText(aurl);
      *pResult = 0;
    }
      

  9.   

    改成 这样 也不行,死了
    BOOL CExtraTreeView::BuildExtraTreeView(HWND hWnd)
    {
     HTREEITEM ht; Extra_DATA *node = new Extra_DATA();
     node->type=TYPE_FOLDER;
     node->url=TEXT("");
     ht=this->GetTreeCtrl().InsertItem(TEXT("我的Extra数据"),0,0,TVI_ROOT,TVI_LAST);    
     this->GetTreeCtrl().SetItemData(ht,(DWORD)node);
     //delete node;node = new Extra_DATA(); node->type=TYPE_FILE;
     node->url=TEXT("http://blog.csdn.net/huyoo");
    HTREEITEM TempItem1=this->GetTreeCtrl().InsertItem("url11111111111",  ht, TVI_LAST);
    this->GetTreeCtrl().SetItemData(TempItem1,(DWORD)node);
    //delete node;node = new Extra_DATA(); node->type=TYPE_FILE;
     node->url=TEXT("http://blog.csdn.net");
    HTREEITEM TempItem2=this->GetTreeCtrl().InsertItem("url22222222222222",  ht, TVI_LAST);
    this->GetTreeCtrl().SetItemData(TempItem2,(DWORD)node);
    //delete node;//url="http://blog.csdn.net/huyoo";
     node->type=TYPE_FILE;
     node->url=TEXT("http://www.csdn.net");
    HTREEITEM TempItem3=this->GetTreeCtrl().InsertItem("url333333333333333",  ht, TVI_LAST);
    this->GetTreeCtrl().SetItemData(TempItem3,(DWORD)node);
    delete node;return TRUE;}
      

  10.   

    我本来只是想做一个RSS的树的,没有想到treectrl的item保持个数据都这样麻烦,看来是做不了了
      

  11.   

    搜索到这个帖子。其实可以选用其他的方法。
    建立一个索引。struct tagExData
    {
     int D1;
     int D2;
     int D3;
    };tagExData Index_[100];当你 SetItemData(h, index)的时候,只是把 这个全局Index_ 的 index 存进去了。
    当你 index = GetItemData(h)的时候,得到的是  这个全局Index_ 的 index。当然这个这个全局Index_必须你自己初始化。看看是否有帮助。如果有后来的人看到这个帖子。