以下适用于32位模式,但不适用于64位,适用于TVN_ITEMEXPANDING鼠标点击&键盘事件。
Object.h
afx_msg void OnTvnItemexpandingTreectrl(NMHDR *pNMHDR, LRESULT *pResult);
Object.cpp
BEGIN_MESSAGE_MAP(Object, CDialogEx)
ON_NOTIFY(TVN_ITEMEXPANDING, IDC_TREECTRL, OnTvnItemexpandingTreectrl)
END_MESSAGE_MAP()
void Object::LoadTree()
{
m_TreeCtrl1.DeleteAllItems();
HTREEITEM hParentItem = TVI_ROOT;
std::list<OBJ>::iterator itObj = m_Obj.begin()->m_Obj.begin();
for (size_t i = 0; i < m_Obj.begin()->m_Obj.size(); i++, ++itObj)
{
TVINSERTSTRUCT tvis;
TVITEM tvItem = { 0 };
tvItem.mask = LVIF_TEXT | LVIF_PARAM | TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE;
tvItem.cChildren = I_CHILDRENCALLBACK;
tvItem.pszText = itObj->m_TreeDesc.GetBuffer();
tvItem.cchTextMax = MAX_ITEMLEN;
tvItem.lParam = reinterpret_cast<LPARAM>(&*itObj);
tvis.item = tvItem;
tvis.hParent = TVI_ROOT;
tvis.hInsertAfter = TVI_LAST;
hParentItem = m_TreeCtrl1.InsertItem(&tvis);
RecurseBuildTree(itObj->m_Obj, m_TreeCtrl1, hParentItem, TVI_LAST);
}
hParentItem = m_TreeCtrl1.GetFirstVisibleItem();
for (size_t i = 0; i < m_Obj.begin()->m_Obj.size(); i++)
{
HTREEITEM hNext = hParentItem;
OBJ *pObjNext = reinterpret_cast<OBJ*>(m_TreeCtrl1.GetItemData(hNext));
m_TreeCtrl1.SetCheck(hNext, pObjNext->m_bItemDisplayed);
RecurseTreeSetCheck(m_TreeCtrl1, hParentItem);
hParentItem = m_TreeCtrl1.GetNextItem(hNext, TVGN_NEXT);
}
}
void Object::OnTvnItemexpandingTreectrl(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
*pResult = 0;
}
void ExpandTreeItem(CTreeCtrl &tree, HTREEITEM hItem, UINT nCode)
{
HTREEITEM hChild;
if (tree.ItemHasChildren(hItem))
{
tree.Expand(hItem, nCode);
hChild = tree.GetChildItem(hItem);
while (hChild)
{
ExpandTreeItem(tree, hChild, nCode);
hChild = tree.GetNextItem(hChild, TVGN_NEXT);
}
}
}
void Object::ToggleItemState(HTREEITEM hti, CTreeCtrl &treectrl, const HTREEITEM hParentNode)
{
if (hti == hParentNode)
{
const int iImage = treectrl.GetItemState(hParentNode, TVIS_STATEIMAGEMASK) >> 12;
OBJ *pObj = reinterpret_cast<OBJ*>(treectrl.GetItemData(hti));
pObj->m_bItemDisplayed = (iImage == 1 ? 2 : 1);
}
else
{
const int iImage = treectrl.GetItemState(hParentNode, TVIS_STATEIMAGEMASK) >> 12;
treectrl.SetItemState(hti, INDEXTOSTATEIMAGEMASK(iImage == 1 ? 2 : 1), TVIS_STATEIMAGEMASK);
OBJ *pObj = reinterpret_cast<OBJ*>(treectrl.GetItemData(hti));
pObj->m_bItemDisplayed = (iImage == 1 ? 2 : 1);
}
if (treectrl.ItemHasChildren(hti)) //failing in release mode for root level node.
{
HTREEITEM htiChild = treectrl.GetChildItem(hti);
if (htiChild)
ToggleItemState(htiChild, treectrl, hParentNode);
else
return;
HTREEITEM htiSibling = treectrl.GetNextSiblingItem(htiChild);
while (htiSibling)
{
ToggleItemState(htiSibling, treectrl, hParentNode);
htiSibling = treectrl.GetNextSiblingItem(htiSibling);
}
}
}
观察:
以下是64位发布模式失败但仅适用于根节点:
if (treectrl.ItemHasChildren(hti))
我有一个可以手动调用ExpandTreeItem()&amp;的按钮。 tree.Expand()调用OnTvnItemexpandingTreectrl(),但是在64位模式下鼠标&amp;键盘不会调用TVN_ITEMEXPANDING,对于其他事件,它可以正常工作。
我怀疑它可能与
的初始化有关 TVINSERTSTRUCT tvis;
TVITEM tvItem = { 0 };
但我真的不知道自己在寻找什么。
如果我需要发布更多代码,请告诉我。
由于
答案 0 :(得分:0)
解决方案只是消息的设计吗?
此处引用文档TVM_EXPAND
当首先通过TVM_EXPAND消息扩展项目时,该动作生成TVN_ITEMEXPANDING和TVN_ITEMEXPANDED通知代码,并且设置项目的TVIS_EXPANDEDONCE状态标志。只要此状态标志保持设置,后续TVM_EXPAND消息就不会生成TVN_ITEMEXPANDING或TVN_ITEMEXPANDED通知。要重置TVIS_EXPANDEDONCE状态标志,必须发送TVM_EXPAND消息,并设置TVE_COLLAPSE和TVE_COLLAPSERESET标志。尝试显式设置TVIS_EXPANDEDONCE将导致不可预测的行为。
答案 1 :(得分:0)
想想我可能找到了原因:
tvItem.cChildren = I_CHILDRENCALLBACK; //<<failing in 64bit mode.
//Upto 0xFFFFFFFE works ok but not -1?
以下最小代码可用于复制问题:
//header
struct ItemData
{
CString Name;
int Value;
CString ToString() const
{
CString str;
str.Format(_T("%s = %d"), Name, Value);
return str;
}
};
CTreeCtrl m_tree;
std::vector<ItemData*> m_data;
//source
void CTreeSortDemoDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Control(pDX, IDC_TREE, m_tree);
}
void CTreeSortDemoDlg::GenerateTreeContent()
{
ItemData* data1 = new ItemData;
data1->Value = 3;
data1->Name.Format(_T("%c%c"), 'P', data1->Value);
m_data.push_back(data1);
m_data.push_back(data1);
ItemData* data2 = new ItemData;
data2->Value = 3;
data2->Name.Format(_T("%c%c"), 'P', data2->Value);
m_data.push_back(data2);
m_data.push_back(data2);
HTREEITEM hParentItem = TVI_ROOT;
TVINSERTSTRUCT tvis;
TVITEM tvItem = { 0 };
tvItem.mask = LVIF_TEXT | LVIF_PARAM | TVIF_CHILDREN | TVIF_HANDLE | TVIF_STATE;
tvItem.cChildren = I_CHILDRENCALLBACK; //<<failing in 64bit mode. 1 works ok?
tvItem.pszText = L"Parent";
tvItem.cchTextMax = MAX_PATH;
tvItem.lParam = reinterpret_cast<LPARAM>(&m_data);
tvis.item = tvItem;
tvis.hParent = TVI_ROOT;
tvis.hInsertAfter = TVI_LAST;
hParentItem = m_tree.InsertItem(&tvis);
//////
TVINSERTSTRUCT tvis2;
TVITEM tvItem2 = { 0 };
std::vector<ItemData*>::iterator itData = m_data.begin();
tvItem2.mask = LVIF_TEXT | LVIF_PARAM | TVIF_HANDLE | TVIF_STATE;
tvItem2.cChildren = 0;
tvItem2.pszText = L"child";
tvItem2.cchTextMax = MAX_PATH;
tvItem2.lParam = reinterpret_cast<LPARAM>(&itData);
tvis2.item = tvItem2;
tvis2.hParent = hParentItem;
tvis2.hInsertAfter = TVI_LAST;
HTREEITEM hItemThis = m_tree.InsertItem(&tvis2);
}
编辑:
如果要在树生成中使用I_CHILDRENCALLBACK,则还必须使用TVN_GETDISPINFO,即
ON_NOTIFY(TVN_GETDISPINFO, IDC_TREE, OnGetdispinfoTreectrl)
void CTreeSortDemoDlg::OnGetdispinfoTreectrl(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTVDISPINFO pTVDispInfo = reinterpret_cast<LPNMTVDISPINFO>(pNMHDR);
TVITEM* pItem = &(pTVDispInfo)->item;
ItemData *pData = reinterpret_cast<ItemData*>(pItem->lParam);
if (pItem->mask & TVIF_CHILDREN)
{
if (pData != NULL)
{
pItem->cChildren = I_CHILDRENCALLBACK;
}
}
}
奇怪的是,行为表现得如何。