首先感谢an_bachelor 前辈关于我上个关于树形控件问题的答案,帖子在这里:
http://topic.csdn.net/u/20080429/15/f6a9b15d-ead7-4beb-8e58-84c417e6115c.html大概思路是这样的: 我现在每个树形节点需要关联信息,以反映它在数据库的位置(此树形控件用数据库条目构建),技术上是自己定义了一个包含信息的类:CTreeItemInfo,赋值后将此对象的指针存到TVITEM的lParam变量中. 以后响应节点的信息时就可以取出对应的对象再做进一步判断了.
我做的是一个基于对话框的程序: 在 Dlg类中定义了一个Vector:vector<CTreeItemInfo>,以便能动态添加对应的节点信息对象,这里我想用vector<CTreeItemInfo>保存所有的节点信息对象,就是CTreeItemInfo类型的对象. 每个节点的lParam的值为向vecTreeItemInfo push_back(CTreeItemInfo)后,(LPARAM)&vecTreeItemInfo.back().但是遇到一个奇怪的问题:在插入结点后,比如
vecTreeItemInfo.push_back(infoTemp);//向Vector存入infoTemp对象
lParamTemp=(LPARAM)&(vecTreeItemInfo.back());//得到此对象指针 tvInsert.hParent=NULL;
tvInsert.hInsertAfter=NULL;
tvInsert.item.mask = TVIF_TEXT;
tvInsert.item.pszText="控制器"; hTreeParent=m_ctrlTree.InsertItem(&tvInsert);
就用:
m_ctrlTree.SetItemData(hTreeParent,lParamTemp);
设置其对象的指针.在该句下断,测试语句为
int temp=((CTreeItemInfo *)(lParamTemp))->nType;//nType和strPanelID为CTreeItemInfo的成员.
CString strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID;显示正常,同时看到指针值 ,我这里是 lParamTemp=3622912,(CTreeItemInfo *)(lParamTemp)=0x00374800;
我不明白为什么LPARAM类型的值转换为CTreeItemInfo *的值会变? 希望高人讲解一下. 但是这句没问题,nType值期望是-1,strPanelID的值期望是"InValid",这里都没问题. 诡异的事情出现了!我在节点响应 TVN_SELCHANGED消息时 ,函数如下:
void CDBTestDlg::OnSelchangedTreeDisp(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here LPARAM lParamTemp=m_ctrlTree.GetItemData(pNMTreeView->itemNew.hItem); int temp=((CTreeItemInfo *)(lParamTemp))->nType;
strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID;}
这里lParamTemp仍=3622912,(CTreeItemInfo *)(lParamTemp)=0x00374800;也就是说指针正确传到函数里了,但是temp的值变为5,不是期望的-1;而且执行到
strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID; 会产生异常,调试时看到的((CTreeItemInfo *)(lParamTemp))->strPanelID值为"".我就不理解了,为什么指针值传过来没变,那个vecTreeItemInfo,Vector变量我定义在Dlg类中,怎么通过同一个指针就得不到正确结果呢?是不是Vector的用法有问题?
谢谢大家帮忙看看了!!
http://topic.csdn.net/u/20080429/15/f6a9b15d-ead7-4beb-8e58-84c417e6115c.html大概思路是这样的: 我现在每个树形节点需要关联信息,以反映它在数据库的位置(此树形控件用数据库条目构建),技术上是自己定义了一个包含信息的类:CTreeItemInfo,赋值后将此对象的指针存到TVITEM的lParam变量中. 以后响应节点的信息时就可以取出对应的对象再做进一步判断了.
我做的是一个基于对话框的程序: 在 Dlg类中定义了一个Vector:vector<CTreeItemInfo>,以便能动态添加对应的节点信息对象,这里我想用vector<CTreeItemInfo>保存所有的节点信息对象,就是CTreeItemInfo类型的对象. 每个节点的lParam的值为向vecTreeItemInfo push_back(CTreeItemInfo)后,(LPARAM)&vecTreeItemInfo.back().但是遇到一个奇怪的问题:在插入结点后,比如
vecTreeItemInfo.push_back(infoTemp);//向Vector存入infoTemp对象
lParamTemp=(LPARAM)&(vecTreeItemInfo.back());//得到此对象指针 tvInsert.hParent=NULL;
tvInsert.hInsertAfter=NULL;
tvInsert.item.mask = TVIF_TEXT;
tvInsert.item.pszText="控制器"; hTreeParent=m_ctrlTree.InsertItem(&tvInsert);
就用:
m_ctrlTree.SetItemData(hTreeParent,lParamTemp);
设置其对象的指针.在该句下断,测试语句为
int temp=((CTreeItemInfo *)(lParamTemp))->nType;//nType和strPanelID为CTreeItemInfo的成员.
CString strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID;显示正常,同时看到指针值 ,我这里是 lParamTemp=3622912,(CTreeItemInfo *)(lParamTemp)=0x00374800;
我不明白为什么LPARAM类型的值转换为CTreeItemInfo *的值会变? 希望高人讲解一下. 但是这句没问题,nType值期望是-1,strPanelID的值期望是"InValid",这里都没问题. 诡异的事情出现了!我在节点响应 TVN_SELCHANGED消息时 ,函数如下:
void CDBTestDlg::OnSelchangedTreeDisp(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here LPARAM lParamTemp=m_ctrlTree.GetItemData(pNMTreeView->itemNew.hItem); int temp=((CTreeItemInfo *)(lParamTemp))->nType;
strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID;}
这里lParamTemp仍=3622912,(CTreeItemInfo *)(lParamTemp)=0x00374800;也就是说指针正确传到函数里了,但是temp的值变为5,不是期望的-1;而且执行到
strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID; 会产生异常,调试时看到的((CTreeItemInfo *)(lParamTemp))->strPanelID值为"".我就不理解了,为什么指针值传过来没变,那个vecTreeItemInfo,Vector变量我定义在Dlg类中,怎么通过同一个指针就得不到正确结果呢?是不是Vector的用法有问题?
谢谢大家帮忙看看了!!
检查在 OnSelchangedTreeDisp 之前是否有 pop等操作如果有那么infoTemp已经释放!
vector <CTreeItemInfo*> vecTreeItemInfo;
CTreeItemInfo* infoTemp=new CTreeItemInfo;
infoTemp->nType=0xFFFFFF;
infoTemp->strPanelID="01";
vecTreeItemInfo.push_back(infoTemp);//向Vector存入infoTemp对象
LPARAM lParamTemp=(LPARAM)vecTreeItemInfo.back();
//后面省略代码不全,估计是infoTemp对象以析构。改成以上样子看看。
你用vector<CTreeItemInfo*>試試
push进入Vector中的为new出来的CTreeItemInfo的指针,infoTemp的生命周期由vecTreeItemInfo控制,程序退出时,再由vecTreeItemInfo remove和delete。
那小弟就先试一下了,可是我还是很想知道我的方法为什么不行....
检测是否有写溢出//////////////////////////////////////////////////////////////////////////////////////////////
CString? 不能在结构间用 memcpy 类似型为拷贝
CString 自已记录一个缓中,如只是 memcpy 那么么只是把缓冲地址拷到另一具 CString 中,内容并没有复制! vecTreeItemInfo.push_back(infoTemp);//向Vector存入infoTemp对象
lParamTemp=(LPARAM)&(vecTreeItemInfo.back());//得到此对象指针如果infoTemp 只是一个函数内局部变量,那么在函数退出是 CString 中的缓冲也释放了,你在
m_ctrlTree.SetItemData(hTreeParent,lParamTemp);
后检测如果,是在一具函数内那么显示结果是正常的,因为这时CString 还没释放而在
void CDBTestDlg::OnSelchangedTreeDisp(NMHDR* pNMHDR, LRESULT* pResult)
中你取出的只是一个已经释放了的CString 指针strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID;
{
public:
void ItemReset();
int nType; //0:控制器节点;1:板卡;2:回路;
int nLoopID;
CString strPanelID;
int nControllerID;
CTreeItemInfo();
virtual ~CTreeItemInfo();};您的话很深奥,我理解下,呵呵 T_T!
而allocator<CTreeItemInfo>::const_reference最終被推演為const CTreeItemInfo&
所以歸根結底 你是把一個CTreeItemInfo&再取地址保存在了LPARAM中
CString
{
...............
protected:
LPTSTR m_pchData; // 真实的数据指针,对像随对像而存在
..............
}///////////////////////////////////////////////////////////////////////////
vecTreeItemInfo.push_back(infoTemp);//向Vector存入infoTemp对象
它会新建一个内存区 A 然后将infoTemp复制到 A
等同于
xxxx::push_back(...)
{
....
CTreeItemInfo *A = new CTreeItemInfo;
memcpy(A,&infoTemp);
.....
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
将CString strPanelID;
换成
char strPanelID[xxx];就行了//如果大小不确定就用CTreeItemInfo* ,自已管理释放问题
vecTreeItemInfo.back();
lParamTemp=vecTreeItemInfo.size();
//
LPARAM lParamTemp=m_ctrlTree.GetItemData(pNMTreeView->itemNew.hItem); int idx= (int)lParamTemp;
CTreeItemInfo * pTemp= & vecTreeItemInfo[idx];
vecTreeItemInfo.push_back();
lParamTemp=vecTreeItemInfo.size();
//
LPARAM lParamTemp=m_ctrlTree.GetItemData(pNMTreeView->itemNew.hItem); int idx= (int)lParamTemp;
CTreeItemInfo * pTemp= & vecTreeItemInfo[idx];
fairyprince:
您好!
我试了下定义成strPanelID[20],可还是会出错,只是指针值传进TVN_SELCHANGED响应函数来,但感觉指针指向的单元已经不存在了,感好像是压入Vector时没有把临时变量infoTemp的值复制,或许只是引用了一下. 而且不光是CString 类型的变量,int变量的值也不对.谢谢大家了,我今晚抓紧试一下吧,最早明天结帖了,100分对于大家这么热心的帮忙来说真的太少了,我明天再加100再结,谢谢各位了.
vecTreeItemInfo.push_back(infoTemp);//向Vector存入infoTemp对象
lParamTemp= vecTreeItemInfo.size();//得到此对象指针
tvInsert.hParent=NULL;
tvInsert.hInsertAfter=NULL;
tvInsert.item.mask = TVIF_TEXT;
tvInsert.item.pszText="控制器";
hTreeParent=m_ctrlTree.InsertItem(&tvInsert);
然後要用到它取值的時候void CDBTestDlg::OnSelchangedTreeDisp(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here DWORD lParamTemp=m_ctrlTree.GetItemData(pNMTreeView->itemNew.hItem); if (lParamTemp--){
int temp=vecTreeItemInfo[lParamTemp].nType;
strTemp=vecTreeItemInfo[lParamTemp].strPanelID;
}
}
按説CTreeItemInfo中要重載operator=運算符為 CTreeItemInfo& operator =(const CTreeItemInfo& val)
{
this->strPanelID = val.strPanelID;
this->nType = val.nType;
return *this;
}但奇怪的是沒有重載也沒出問題 看來默認的拷貝構造函數對struct還是會一個一個成員調用=來賦值二步是值拷貝 至少對於非簡單類型對象如此
如果预留的空间不够,他会执行得新分配一个,足够的空间然后再将旧的数据复制到新的空间里,然后再删除旧数据!vecTreeItemInfo.push_back(); 会引起上述操作
所以,strTemp=((CTreeItemInfo *)(lParamTemp))->strPanelID; 这里可能已不是原始值了!Vector 改成 listlist 不会有上述问题