如果节点文本和节点数据有关的话,建议使用回调节点(callback item)根据节点数据显示文本内容。
插入节点时,每个节点的lParam是一个指向节点数据的指针。
HTREEITEM CCWDeptTree::InsertItem( HTREEITEM hParent, CRecordBase* pRecord)
{
ASSERT(IsWindow(m_hWnd));
TVINSERTSTRUCT InsertStruct;
memset(&InsertStruct,0,sizeof(TVINSERTSTRUCT));
if(hParent==NULL)
InsertStruct.hParent=TVI_ROOT;
else
InsertStruct.hParent=hParent;
InsertStruct.hInsertAfter =TVI_LAST; InsertStruct.item.mask=TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
InsertStruct.item.pszText =LPSTR_TEXTCALLBACK ;
InsertStruct.item.iImage  =I_IMAGECALLBACK ;
InsertStruct.item.iSelectedImage  =I_IMAGECALLBACK ;
InsertStruct.item.lParam=(LPARAM)pRecord;
HTREEITEM hItem=CTreeCtrl::InsertItem(&InsertStruct);
ASSERT(hItem!=NULL);
m_mapItemToRecord.SetAt(hItem,pRecord);
}我这里使用一个HTREEITEM到数据的映射来存储数据,当然你也可以用其他方法,比如
InsertStruct.item.lParam=(LPARAM)new CMyObject;分配一块内存来存储数据。然后截获TVN_GETDISPINFO,来显示信息
void CCWDeptTree::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult) 
{
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
// TODO: Add your control notification handler code here
TVITEM* pItem=&pTVDispInfo ->item;
CRecordBase* pItemRecord=(CRecordBase*)pItem->lParam;
if(pItemRecord->IsKindOf(RUNTIME_CLASS(CCWDeptRecord))){
CCWDeptRecord* pDept=DYNAMIC_DOWNCAST(CCWDeptRecord,pItemRecord);
if(pDept){
if(pItem->mask&TVIF_TEXT){
StrCpyN(pItem->pszText,pDept->m_strName,pItem->cchTextMax);
}
if(pItem->mask&TVIF_IMAGE){
pItem->iImage=IMAGE_DEPT;
}
if(pItem->mask&TVIF_SELECTEDIMAGE){
pItem->iSelectedImage=IMAGE_DEPT;
}
}
}
if(pItemRecord->IsKindOf(RUNTIME_CLASS(CCWCardRecord))){ 
CCWCardRecord* pCard=DYNAMIC_DOWNCAST(CCWCardRecord,pItemRecord);
if(pCard){
if(pItem->mask&TVIF_TEXT){
StrCpyN(pItem->pszText,pCard->Format(),pItem->cchTextMax);
}
if(pItem->mask&TVIF_IMAGE){
pItem->iImage=IMAGE_CARD;
}
if(pItem->mask&TVIF_SELECTEDIMAGE){
pItem->iSelectedImage=IMAGE_CARD;
}
}
}
*pResult = 0;
}
要访问一个HTREEITEM对应的数据就很简单了
CRecordBase* CCWDeptTree::GetRecord(HTREEITEM hItem)
{
if(hItem==NULL)return NULL;
TVITEM tvi;
tvi.mask=TVIF_PARAM|TVIF_HANDLE;
tvi.hItem=hItem;
GetItem(&tvi);
return (CRecordBase*)tvi.lParam;
}
如果你的节点数据是插入时分配的
InsertStruct.item.lParam=(LPARAM)new CMyObject;
那么在退出的时候要手动删除
TVITEM tvi;
tvi.mask=TVIF_PARAM|TVIF_HANDLE;
tvi.hItem=hItem;
GetItem(&tvi);
         delete (CMyObject*)tvi.lParam

解决方案 »

  1.   

    jiangsheng(蒋晟):
    多谢你的帮助,但这里这么多MFC,我很少用MFC的,而且我想知道我上面的处理方法到底错在什么地方,请你帮我看看号么?
      

  2.   

    你在case语句里能这么写吗:
      NMTREEVIEW* lpTree=(LPNMTREEVIEW) lParam;
    编译器不提示出错?!!
    -------------------
    不管错不错,你把 lpTree也设为指向lParam的指针,你的
      NMHDR* pnmh = (LPNMHDR) lParam; 
    也指向lParam,重复引用有什么意思?! 
    是不是要指向wParam而写错了?
      

  3.   

    sclzmbie(梦里红尘)不太了解SDK的通用控件编程,人家这么干基本没有问题。sclzmbie(梦里红尘)应该仔细看看NMTREEVIRE和NMHDR的定义。
    APIer的问题并不复杂。请看:
    switch (pnmh->code)
    {
    case TVN_SELCHANGED:
        NMTREEVIEW* lpTree=(LPNMTREEVIEW) lParam;
        char Buffer[256];
        /*TV_ITEM  tvi;
        ZeroMemory(&tvi,sizeof(TV_ITEM));
        tvi.mask=TVIF_TEXT ¦ TVIF_PARAM;
        tvi.hItem=lpTree->itemNew.hItem;
        TreeView_GetItem(pnmh->hwndFrom,&tvi);*/
        strcpy(Buffer,lpTree->itemNew.pszText);
        J3DINode* pNode=FindJ3DNode(pRoot3DNode,Buffer);
    }
    首先我不赞成这么组织代码,最好写成这样
    switch (pnmh->code)
    {
    case TVN_SELCHANGED:
    {
        NMTREEVIEW* lpTree=(LPNMTREEVIEW) lParam;
        char Buffer[256];
        TV_ITEM  tvi;
        ZeroMemory(&tvi,sizeof(TV_ITEM));
        tvi.mask=TVIF_TEXT ¦ TVIF_PARAM;
        tvi.hItem=lpTree->itemNew.hItem;
        TreeView_GetItem(pnmh->hwndFrom,&tvi);*/
        strcpy(Buffer,lpTree->itemNew.pszText);
        J3DINode* pNode=FindJ3DNode(pRoot3DNode,Buffer);
    }
    }
    下面说一下问题的关键所在。
        tvi.mask=TVIF_TEXT ¦ TVIF_PARAM;
    应该是:
        tvi.mask=TVIF_TEXT ¦ TVIF_HANDLE;
    APIer的用意很明显,就是要文字,就是pszText。把我说的改了,就可以解决问题。SDK编程就是这样。按理说调用TreeView_GetItem宏肯定要填写hItem,但是就是必须在mask里边加上TVIF_HANDLE,要不然不行。
    在顺便说一个事情。
    1,不要用TV_ITEM了。现在应该用TVITEM。如果你的SDK头文件比较新,那么应该用这个结构名。完全和TV_ITEN一样,但是它遵守新的命名约定。
      

  4.   

    对不起,应该是NMTREEVIEW,第一行错了。
      

  5.   

    faint!再贴一遍。
    sclzmbie(梦里红尘)不太了解SDK的通用控件编程,人家这么干基本没有问题。sclzmbie(梦里红尘)应该仔细看看NMTREEVIRE和NMHDR的定义。
    APIer的问题并不复杂。请看:
    switch (pnmh->code)
    {
    case TVN_SELCHANGED:
        NMTREEVIEW* lpTree=(LPNMTREEVIEW) lParam;
        char Buffer[256];
        /*TV_ITEM  tvi;
        ZeroMemory(&tvi,sizeof(TV_ITEM));
        tvi.mask=TVIF_TEXT|TVIF_PARAM;
        tvi.hItem=lpTree->itemNew.hItem;
        TreeView_GetItem(pnmh->hwndFrom,&tvi);*/
        strcpy(Buffer,lpTree->itemNew.pszText);
        J3DINode* pNode=FindJ3DNode(pRoot3DNode,Buffer);
    }
    首先我不赞成这么组织代码,最好写成这样
    switch (pnmh->code)
    {
    case TVN_SELCHANGED:
    {
        NMTREEVIEW* lpTree=(LPNMTREEVIEW) lParam;
        char Buffer[256];
        TV_ITEM  tvi;
        ZeroMemory(&tvi,sizeof(TV_ITEM));
        tvi.mask=TVIF_TEXT|TVIF_PARAM;
        tvi.hItem=lpTree->itemNew.hItem;
        TreeView_GetItem(pnmh->hwndFrom,&tvi);*/
        strcpy(Buffer,lpTree->itemNew.pszText);
        J3DINode* pNode=FindJ3DNode(pRoot3DNode,Buffer);
    }
    }
    下面说一下问题的关键所在。
        tvi.mask=TVIF_TEXT|TVIF_PARAM;
    应该是:
        tvi.mask=TVIF_TEXT|TVIF_HANDLE;
    APIer的用意很明显,就是要文字,就是pszText。把我说的改了,就可以解决问题。SDK编程就是这样。按理说调用TreeView_GetItem宏肯定要填写hItem,但是就是必须在mask里边加上TVIF_HANDLE,要不然不行。
    在顺便说一个事情。
    1,不要用TV_ITEM了。现在应该用TVITEM。如果你的SDK头文件比较新,那么应该用这个结构名。完全和TV_ITEN一样,但是它遵守新的命名约定。 
      

  6.   

    tvi.mask=TVIF_TEXT ¦ TVIF_PARAM;
    tvi.hItem=lpTree->itemNew.hItem;
    TreeView_GetItem(pnmh->hwndFrom,&tvi);在调用 TreeView_GetItem 函数前你是否设置了 TVITEM 中的 pszText 和 cchMaxText 两个成员?从你的代码中看不到这样的语句。它们是用于接收返回数据的。
      

  7.   

    对不起,应该是NMTREEVIEW,第一行错了。
      

  8.   

    tiongkohlang(SDK):
    不愧是sdk:)
    我去看看行不行,总之多谢了!
      

  9.   

    tiongkohlang(SDK) :
    我在mask中使用了tvi.mask=TVIF_TEXT¦TVIF_HANDLE;
    后,仍然发现tvi.pszText是null,真的没有脾气了!这个问题应该不是很难,但是肯定是什么东西有点问题,你能够给我一个能够正常使用的例子代码么?让我对找看看问题的所在,我急着用啊:)
    代码可以送到:[email protected]
      

  10.   

    You must set TVITEM structures pszText, cchTextMax for receive the node text, following is a sample:TVITEM tvi;
    TCHAR szText[MAX_LENGTH];
    memset(&tvi, 0, sizeof(tvi));
    tvi.mask = TVIF_TEXT | TVIF_PARAM;
    tvi.hItem = the item handle;
    tvi.pszText = szText;
    tvi.cchTextMax = sizeof(szText);
    BOOL bSuccess = TreeView_GetItem(hwndTreeView, &tvi);Good Luck!
      

  11.   

    dcz(dcz) :
    你说得很对,刚才我也发现了这个问题,不过还是要多谢你:)