在使用树控件时,想要实现单击展开,结果单击时的确可以展开了,但是随机而来的BUG多多。。
例如单击ITEM前面的+号展开不了,而且是展开一下然后立即收回,而且已经单击展开后的ITEM再也不能展开了。
由于树控件插入项时对子项个数使用了I_CHILDRENCALLBACK,类似于虚列表的方法,所以怀疑是否是虚列表的BUG,经过仔细的跟踪,终于找到结决办法。
在建树时,不要对根结点作插入,只是展开它就可以了,否则会因为使用虚列表的动态插入在根结点下插入两次重复的项目。
HTREEITEM hRoot = InsertItem(strName, nImage, nSel);
SetItemData(hRoot,(DWORD)lpidl);
TV_ITEM tv;
tv.mask = TVIF_CHILDREN ;
tv.hItem = hRoot;
tv.cChildren = I_CHILDRENCALLBACK;
SetItem( &tv);
Expand(hRoot, TVE_EXPAND);
Expand(GetChildItem(hRoot), TVE_EXPAND);
展开时,判断展开要求,是展开时则插入子目录,插子目录时如果该目录下有子目录则将 tv.cChildren 设为I_CHILDRENCALLBACK,是收拢时则删除所有子结点并将tv.cChildren 设为I_CHILDRENCALLBACK,
void CExpTree::OnItemexpanding(NMHDR* pNMHDR, LRESULT* pResult)
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
if(pNMHDR->code == TVN_ITEMEXPANDING )
{
NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
// TODO: Add your control notification handler code here
HTREEITEM hItemNew = pNMTreeView->itemNew.hItem;
BOOL bExpand = GetItemState(hItemNew, TVIS_EXPANDED ) & TVIS_EXPANDED;
if(hItemNew != NULL &&
pNMTreeView->action == TVE_EXPAND &&
lpMalloc != NULL
&& !bExpand
)
{
SetRedraw(FALSE);
this->LockWindowUpdate();
InsertChildItem(hItemNew);
UnlockWindowUpdate();
SetRedraw(TRUE);
}
else if(pNMTreeView->action == TVE_COLLAPSE && bExpand)
{
DeleteTree(hItemNew);
TV_ITEM tv;
tv.mask = TVIF_CHILDREN ;
tv.hItem = hItemNew;
tv.cChildren = I_CHILDRENCALLBACK;
SetItem( &tv);
}
}
*pResult = 0;
}
在单击时不能仅仅根据结点就展开,还应判断单击的位置是否在结点前面的+号上,如果在加号上就不要展开了,因为加号也会触发一个expand事件,这个两个expand会使用结点先展开,再合拢,出现前面所说的BUG。(让我小郁闷了两天,一直没空解决的,终于干掉它了)
void CExpTree::OnClick(NMHDR* pNMHDR, LRESULT* pResult)
{
// TODO: Add your control notification handler code here
POINT point;
GetCursorPos(&point);
::ScreenToClient(m_hWnd, &point);
UINT Flags = 0;
HTREEITEM hItemNew = this->HitTest(CPoint(point), &Flags);
if(hItemNew != NULL && !(Flags & TVHT_ONITEMBUTTON ) )//不是在+号上时
{
if(!(GetItemState(hItemNew, TVIS_EXPANDED ) & TVIS_EXPANDED))
{
Expand(hItemNew, TVE_EXPAND);
}
}
*pResult = 0;
}