各位高手,我最近正在做的一个项目中使用到了CTreeCtrl这个控件,需要当点击展开按钮时动态去服务器端数据库请求数据。需要在该分类下没有子分类的情况下显示那个展开按钮
而我们都知道:使用CTreeCtrl的InsertItem()这个方法添加Item时如果该项下没有子项,那这个Item前就不会有那个展开按钮(就是那个+号)。
于是我今天查了下MSDN发现可以通过将TVITEM的cChildren设置为I_CHILDRENCALLBACK强制让该项显示展开按钮。然后设置消息响应函数处理由点击展开按钮所处发的TVN_GETDISPINFO 消息。
可是我不知道为什么我设置的消息响应函数没法添加子项目,困惑了我一天。我希望能有高手能帮我解答下。以下是我的消息响应函数void CMutiTreeCtrl::OnTvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
if((pTVDispInfo->item.mask & TVIF_CHILDREN ) == 0)
{
HTREEITEM hSelected = GetSelectedItem();
TV_INSERTSTRUCT tvinsert;
tvinsert.hParent=hSelected;
tvinsert.hInsertAfter=TVI_LAST;
tvinsert.item.mask=TVIF_TEXT;
tvinsert.item.hItem=NULL;
tvinsert.item.cchTextMax=6;
tvinsert.item.lParam=0;
tvinsert.item.pszText="展开后动态添加的节点";
*pResult = 1;
}
else *pResult =0;
}我不知道我的问题说清楚没。请教各位,希望能得到解答,谢谢。
而我们都知道:使用CTreeCtrl的InsertItem()这个方法添加Item时如果该项下没有子项,那这个Item前就不会有那个展开按钮(就是那个+号)。
于是我今天查了下MSDN发现可以通过将TVITEM的cChildren设置为I_CHILDRENCALLBACK强制让该项显示展开按钮。然后设置消息响应函数处理由点击展开按钮所处发的TVN_GETDISPINFO 消息。
可是我不知道为什么我设置的消息响应函数没法添加子项目,困惑了我一天。我希望能有高手能帮我解答下。以下是我的消息响应函数void CMutiTreeCtrl::OnTvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
// TODO: 在此添加控件通知处理程序代码
if((pTVDispInfo->item.mask & TVIF_CHILDREN ) == 0)
{
HTREEITEM hSelected = GetSelectedItem();
TV_INSERTSTRUCT tvinsert;
tvinsert.hParent=hSelected;
tvinsert.hInsertAfter=TVI_LAST;
tvinsert.item.mask=TVIF_TEXT;
tvinsert.item.hItem=NULL;
tvinsert.item.cchTextMax=6;
tvinsert.item.lParam=0;
tvinsert.item.pszText="展开后动态添加的节点";
*pResult = 1;
}
else *pResult =0;
}我不知道我的问题说清楚没。请教各位,希望能得到解答,谢谢。
解决方案 »
- 不同的操作系统,相同的DPI,控件大小显示却不同??
- 用过VS2008sp1和VS2010的朋友请进
- �رճ���Ĵ���
- 做一个系统一直遇到的问题
- socket 数据库
- 怎么关闭指定对话框上弹出的MessageBox
- 请教高手:VC MDI框架怎样调用DELPHI编的FORM(DLL)作为子窗口???
- 进行FTP服务器端或者客户端的网络编程,最终的应用程序是像CUTEFTP那样的一个软件么?
- 菜鸟送分问题之——单文档应用中的状态栏问题!
- 菜鸟问题:如何控制ListBox的显示
- 输入界面:一条记录好多字段,对话框上放不开,该怎么处理?
- 环境是VC2005, 建立了一个使用MFC的控制台程序项目,怎样使生成的程序能在别的没有VS2005安装的机器上运行。
于是我在机子上试了一下,下面是我的代码。
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
//if(pTVDispInfo->item.cChildren == I_CHILDRENCALLBACK)//我觉得应该这样判断,可结果为什么不对呢?
if(pTVDispInfo->item.mask & TVIF_CHILDREN )//你这里是不是判断反了
{
//去除Parent I_CHILDRENCALLBACK属性
TVITEM tvParent = pTVDispInfo->item;
tvParent.cChildren=1;
m_tree.SetItem(&tvParent);
HTREEITEM hChild =m_tree.InsertItem("Child",tvParent.hItem);//加入child
//设置Child I_CHILDRENCALLBACK属性
TVITEM tvChild;
ZeroMemory(&tvChild,sizeof(TVITEM));
tvChild.mask =TVIF_CHILDREN|TVIF_HANDLE;
tvChild.hItem = hChild;
tvChild.cChildren =I_CHILDRENCALLBACK;
m_tree.SetItem(&tvChild);
}
TRACE("%d\n",m_nCount++);
*pResult = 0;
1,被设为I_CHILDRENCALLBACK的项,即使mouse放在上面都会产生TVN_GETDISPINFO,我TRACE了一下,随便在上面动动mouse 就有上百个TVN_GETDISPINFO
所以我在接受到第一个TVN_GETDISPINFO时就去除了当前项的I_CHILDRENCALLBACK属性,而把它设成1,表示有child
2,可能是因为我对TVN_GETDISPINFO不了解吧,我感觉这个属性不好用,还不如直接Insert dummy child 方便.
//早知道不学五笔了,好多字都想不起来怎么打了,麻烦
OnTvnGetdispinfo 函数里面就加一句话:
pTVDispInfo->item.cChildren = 1;如下:
void CXXX::OnTvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
pTVDispInfo->item.cChildren = 1;
*pResult = 0;
}然后在 TVN_ITEMEXPANDING 消息里面添加节点。
{
CTreeCtrl& ctlTree = (CTreeCtrl&) GetTreeCtrl(); HTREEITEM hRoot = ctlTree.GetRootItem(); TV_INSERTSTRUCT itInsert = {0}; CString strText;
strText = _T("Start"); itInsert.item.pszText = const_cast<LPTSTR>((LPCTSTR)strText);
itInsert.item.state = TVIS_BOLD;
itInsert.item.mask = TVIF_CHILDREN | TVIF_HANDLE | TVIF_TEXT |
TVIF_STATE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
itInsert.item.stateMask = TVIS_BOLD | TVIS_STATEIMAGEMASK;
itInsert.item.cChildren = I_CHILDRENCALLBACK;
itInsert.hParent = hRoot;
HTREEITEM hItem = ctlTree.InsertItem(&itInsert); UpdateWindow();
}
void CMyTreeView::OnTvnItemexpanding(NMHDR *pNMHDR, LRESULT *pResult)
{
CWaitCursor curWait;
SetRedraw(FALSE); LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
// TODO: Add your control notification handler code here HTREEITEM hItem = pNMTreeView->itemNew.hItem; CTreeCtrl& ctlTree = (CTreeCtrl&) GetTreeCtrl();
// remove all subitems
HTREEITEM hRemove = ctlTree.GetChildItem(hItem);
while(hRemove)
{
ctlTree.DeleteItem(hRemove);
hRemove = ctlTree.GetChildItem(hItem);
} CString strText = _T("这是动态增加的"); AddMySubItems(hItem, strText); // 需要自己实现的函数 SetRedraw(TRUE);
Invalidate(); *pResult = 0;
}
void CMyTreeView::OnGetdispinfo(NMHDR* pNMHDR, LRESULT* pResult)
{
TV_DISPINFO* pTVDispInfo = (TV_DISPINFO*)pNMHDR;
// TODO: Add your control notification handler code here
pTVDispInfo->item.cChildren = 1;
*pResult = 0;
}
以上代码是可运行的,但须略作修改。不妨一试。
要知道鼠标不经意地划过item时,都会调用OnGetdispinfo,要是如两位那样,那不如在当初InsertItem时就把cChildren设为1了。
"Requests that a tree-view control's parent window
provide information needed to display or sort an item."You shouldn't be inserting items in response to this notification.
You also shouldn't be calling GetSelectedItem().
The TVN_ITEMEXPANDING notification is maybe a better place to insert
the child items.
Mark感谢高手帮忙。现在就去结帖