如果节点文本和节点数据有关的话,建议使用回调节点(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
插入节点时,每个节点的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
解决方案 »
- vs2010 MFC的问题
- VC实现word转pdf
- 如何得到全部TRUEFONT字体名称,为何我这么做,有不好重复的啊?
- 简单问题!
- vs2005编译错误?error C2040
- 如何实现在树形控件上选中某一项后,点鼠标右键单出快捷菜单呢?
- 哪里有Iphlpapi.h文件?
- 谁能给出"hello world" SDK的源代码?
- 在MFC中对多个类怎样存储?
- vc可以处理excel表格么?
- 用VC建立数据库工程时,为什么会出现"visual database tools is not configered properly,please reinstall"的错误提示?如何解决?
- 怎样显示多个扩展名的文件?
多谢你的帮助,但这里这么多MFC,我很少用MFC的,而且我想知道我上面的处理方法到底错在什么地方,请你帮我看看号么?
NMTREEVIEW* lpTree=(LPNMTREEVIEW) lParam;
编译器不提示出错?!!
-------------------
不管错不错,你把 lpTree也设为指向lParam的指针,你的
NMHDR* pnmh = (LPNMHDR) lParam;
也指向lParam,重复引用有什么意思?!
是不是要指向wParam而写错了?
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一样,但是它遵守新的命名约定。
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一样,但是它遵守新的命名约定。
tvi.hItem=lpTree->itemNew.hItem;
TreeView_GetItem(pnmh->hwndFrom,&tvi);在调用 TreeView_GetItem 函数前你是否设置了 TVITEM 中的 pszText 和 cchMaxText 两个成员?从你的代码中看不到这样的语句。它们是用于接收返回数据的。
不愧是sdk:)
我去看看行不行,总之多谢了!
我在mask中使用了tvi.mask=TVIF_TEXT¦TVIF_HANDLE;
后,仍然发现tvi.pszText是null,真的没有脾气了!这个问题应该不是很难,但是肯定是什么东西有点问题,你能够给我一个能够正常使用的例子代码么?让我对找看看问题的所在,我急着用啊:)
代码可以送到:[email protected]
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!
你说得很对,刚才我也发现了这个问题,不过还是要多谢你:)