在使用樹控件時,想要實現單擊展開,結果單擊時的確可以展開了,但是隨機而來的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;
}