CTreeCtrl树节点排序,节电复选(菜鸟版)
效果描述:该功能可使某义节点下的全部子节点按某种序列重新排列SortChildren是为该结点下面的所有子节点排序,注意只是子节点,不包括子节点的子节点。SortChildrenCB是自定义排序方式。现给出大体例子
SortChildrenCB中的TVSORTCB需要用到一个回调函数常常是难点。
INT CHvrTree::SortItem(HTREEITEM hItem)
{
BOOL bRet;
CHvrTree *ptree = this;
TVSORTCB sortpage;
g_pLogger->Debug("<%s(%d)> SortItem(): Enter",D_PC_LOG_NAME_HVRTREE, __LINE__);
//////////////////////////////////////////////////////////////////////////
// ソーティング情報
g_pLogger->Info("<%s(%d)> SortItem(): ソーティングノード,hItem - %08x"
,D_PC_LOG_NAME_HVRTREE, __LINE__,hItem );
sortpage.hParent = hItem;
sortpage.lpfnCompare = MyCompareProc;
sortpage.lParam = (LPARAM)ptree;
bRet = SortChildrenCB(&sortpage);
if ( bRet )
{
g_pLogger->Debug("<%s(%d)> SortItem(): Leave",D_PC_LOG_NAME_HVRTREE, __LINE__);
return D_PC_SUCCESS;
}
else
{
g_pLogger->Debug("<%s(%d)> SortItem(): Leave",D_PC_LOG_NAME_HVRTREE, __LINE__);
return D_PC_FAILURE;
}
}
入口参数是两个在要排序的序列中的无序参数
INT CALLBACK CHvrTree::MyCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
{
CHvrTree* pTreeCtrl = (CHvrTree*) lParamSort;
HTREEITEM hItem1 = (HTREEITEM)lParam1;
HTREEITEM hItem2 = (HTREEITEM)lParam2;
// ノードのアイコンに付けられた固有の番号によって、ノードタイプ取得
INT nKind1 = pTreeCtrl->GetItemType(hItem1);
INT nKind2 = pTreeCtrl->GetItemType(hItem2);
// 1.01 : カテゴリソーティングを機能修正
//////////////////////////////////////////////////////////////////////////
// ノードタイプ取得チェック
if ( (nKind1<0)||(nKind2<0) )
{
g_pLogger->Error( "<%s(%d)> MyCompareProc: 目標ノードノードタイプ情報取得できない, nType - %d",
D_PC_LOG_NAME_HVRTREE, __LINE__, D_PC_FAILURE );
return D_PC_ERRCODE_HVRTREE_GETTREE_FAIL;
}
// 1.01 - END
// ノード情報取得
BOOL bRet;
ST_TREE_NODE *pnodeInfo1 = NULL; // ノード1の情報
ST_TREE_NODE *pnodeInfo2 = NULL; // ノード2の情報
bRet = pTreeCtrl->m_mapNode.Lookup(hItem1,(void*&)pnodeInfo1); // ノード1の情報取得
if(bRet == FALSE)
{
// 目標ノード情報取得できない
g_pLogger->Error( "<%s(%d)> MyCompareProc: 目標ノード情報取得できない, hItem - %08x",
D_PC_LOG_NAME_HVRTREE, __LINE__, hItem1 );
return D_PC_ERRCODE_HVRTREE_GETTREE_FAIL;
}
bRet = pTreeCtrl->m_mapNode.Lookup(hItem2,(void*&)pnodeInfo2); // ノード2の情報取得
if(bRet == FALSE)
{
// 目標ノード情報取得できない
g_pLogger->Error( "<%s(%d)> MyCompareProc: 目標ノード情報取得できない, hItem - %08x",
D_PC_LOG_NAME_HVRTREE, __LINE__, hItem2 );
return D_PC_ERRCODE_HVRTREE_GETTREE_FAIL;
}
INT nRet = NULL; // 戻り値
if( nKind1 == nKind2)
{
// ノード1とノード2は同じノードタイプの場合
// ノード1とノード2はカテゴリーノードの場合
if( nKind1 == D_PC_NODE_CATE_1)
{
CString strItem1,strItem2;
// カテゴリー名取得
strItem1 = pTreeCtrl->GetItemText(hItem1);
strItem2 = pTreeCtrl->GetItemText(hItem2);
// カテゴリー名比較
nRet = strcmp(strItem1, strItem2);
}
// 1.01 : カテゴリソーティングを機能修正
else if( nKind1 == D_PC_NODE_CATE_2)
{
CString strItem1,strItem2;
// カテゴリー名取得
strItem1 = pTreeCtrl->GetItemText(hItem1);
strItem2 = pTreeCtrl->GetItemText(hItem2);
// カテゴリー名比較
nRet = strcmp(strItem1, strItem2);
}
// 1.01 - END
else if( nKind1 == D_PC_NODE_CAM )
{
// ノード1とノード2はカメラノードの場合
// カメラ番号取得
INT nCamId1 = pnodeInfo1->Id;
INT nCamId2 = pnodeInfo2->Id;
// カメラ番号比較
nRet = nCamId1 - nCamId2;
}
else if( nKind1 == D_PC_NODE_HVR )
{
// ノード1とノード2は物件ノードの場合
ST_HVR_INFO hvrInfo1, hvrInfo2;
CString strItem1, strItem2;
// 物件番号取得
INT nHvrId1 = pnodeInfo1->Id;
INT nHvrId2 = pnodeInfo2->Id;
// 物件情報取得
g_hvrUser.GetHvrInfo(nHvrId1, &hvrInfo1);
g_hvrUser.GetHvrInfo(nHvrId2, &hvrInfo2);
// 1.05 : 物件の順機能修正
// 物件カナ名取得
strItem1.Format("%s",hvrInfo1.szKana);
strItem2.Format("%s",hvrInfo2.szKana);
// 物件カナ名比較
nRet = CCheckWord::CompareValidKataName( strItem1, strItem2 );
if (nRet == 0)
{
if (nHvrId1 > nHvrId2)
{
nRet = 1;
}else
{
nRet = -1;
}
}
// 1.05 - END
}
else
{
// 他の場合
nRet = NULL;
}
}
else
{
// ノード1とノード2は違いノードタイプの場合
nRet = nKind1 - nKind2;
}
return nRet;
}
GetItemType是获得结点状态即它的图标,主要是利用了GetItemImage得到其图标
复选重绘
有时可能会用到复选操作,即点击一个结点时该结点和另一个结点同时被选中(如其父结点)
可使用系统消息OnCustomDraw,该消息须手动添加
该功能的实质是:先把要选则的所有节点刷上颜色,再到调用时如单击或双击事件把不需要的颜色去掉
virtual void OnCustomDraw(NMHDR *pHdr, LRESULT *pResult);
BEGIN_MESSAGE_MAP(CHvrTree, CTreeCtrl)
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomDraw)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
void CHvrTree::OnCustomDraw(NMHDR *pHdr, LRESULT *pResult)
{
LPNMLVCUSTOMDRAW lplvcd = (LPNMLVCUSTOMDRAW)pHdr;
INT nState;
switch(lplvcd->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
* pResult= CDRF_NOTIFYITEMDRAW;
break;
// アイテムが描画される前
case CDDS_ITEMPREPAINT:
nState = lplvcd->nmcd.uItemState;
if((nState == (CDIS_FOCUS|CDIS_SELECTED)) || (nState == CDIS_SELECTED) )
{
lplvcd->clrTextBk = D_PC_DEV_ADD_BLACK_BRUSH;
// アイテムの文字色を設定
lplvcd->clrText = D_PC_DEV_LIST_RUN_COLOR;
* pResult= CDRF_DODEFAULT;
break;
}
else
{
* pResult= 0;
break;
}
default:
* pResult = 0;
break;
}
}
判断结点状态可使用GetItemState。如判断结点是否展开
UINT nState;
nState = GetItemState( hItem,TVIS_EXPANDED );
if ( 0 == (nState & TVIS_EXPANDED) )
{
// ノード非展開の場合
SetItemImage(hItem,D_PC_NODE_TREEROOT,D_PC_NODE_TREEROOT);
}
else
{
SetItemImage( hItem,D_PC_NODE_TREEROOTCOL,D_PC_NODE_TREEROOTCOL );
}
复选
INT CHvrTree::SetActiveItem( ULONG lHvrId,ULONG lCamId )
{
HTREEITEM hHvrItem; //
HTREEITEM hCamItem; //
HTREEITEM hCam;
HTREEITEM hSelectItem; //
ST_TREE_NODE *pCamNode; //
BOOL bRet;
UINT nState = NULL;
g_pLogger->Debug("<%s(%d)> SetActiveItem(): Enter",D_PC_LOG_NAME_HVRTREE, __LINE__);
//////////////////////////////////////////////////////////////////////////
// 这部分主要是把原来的一些结点状态清空
SetItemState( m_hItem,0,TVIS_SELECTED );
for (int k=0;k<m_aryActiveItem.GetSize();k++)
{
SetItemState( m_aryActiveItem.GetAt(k),0,TVIS_SELECTED );
}
m_aryActiveItem.RemoveAll();
//////////////////////////////////////////////////////////////////////////
// WM_LBUTTONDOWN消息让树控件获得焦点
m_pDeviceDlg->PostMessage(WM_LBUTTONDOWN,0,0);
// 查找节点信息
bRet = m_mapHvrNode.Lookup((short)lHvrId,(void*&)hHvrItem);
if ( bRet == FALSE )
{
// 以下为错误处理
g_pLogger->Error("<%s(%d)> SetActiveItem(): m_mapHvrNode拞HVR僲乕僪枹敪尒丄lHvrId - %d",
D_PC_LOG_NAME_HVRTREE, __LINE__ ,lHvrId );
g_pLogger->Debug("<%s(%d)> SetActiveItem(): Leave",D_PC_LOG_NAME_HVRTREE, __LINE__);
return D_PC_FAILURE;
}
// 便利子节点
hCamItem = GetChildItem( hHvrItem );
while ( hCamItem != NULL )
{
bRet = m_mapNode.Lookup( hCamItem,(void*&)pCamNode );
if ( bRet == FALSE )
{
// 错误处理
g_pLogger->Error("<%s(%d)> SetActiveItem(): 僇儊儔僲乕僪枹敪尒,hCamItem - %08x",
D_PC_LOG_NAME_HVRTREE, __LINE__ ,hCamItem );
g_pLogger->Debug("<%s(%d)> SetActiveItem(): Leave",D_PC_LOG_NAME_HVRTREE, __LINE__);
return D_PC_FAILURE;
}
// 如果找到了与入口参数相同的ID就退出。搜索结束
if ( pCamNode->Id == lCamId )
{
hCam = pCamNode->hItem;
break;
}
hCamItem = GetNextVisibleItem(hCamItem);
}
//////////////////////////////////////////////////////////////////////////
// 将符合条件的值粗如一个实现定义好的数组
INT i = 0;
hSelectItem = hCamItem;
while ( hSelectItem != NULL )
{
m_aryActiveItem.Add( hSelectItem ); // 向数组中添加值
i++;
hSelectItem = GetParentItem(hSelectItem);
}
//////////////////////////////////////////////////////////////////////////
// 为数组中的值设定状态
for (int j=0;j<m_aryActiveItem.GetSize();j++)
{
nState = GetItemState( m_aryActiveItem.GetAt(j), TVIS_EXPANDED);
if(0 != (nState & TVIS_EXPANDED))
{ // 节点非展开的展开的场合
SetItemState( m_aryActiveItem.GetAt(j),0,TVIS_SELECTED);
}
else
{
SetItemState( m_aryActiveItem.GetAt(j),TVIS_SELECTED,TVIS_SELECTED);
}
}
//////////////////////////////////////////////////////////////////////////
SetItemState( hHvrItem,TVIS_SELECTED,TVIS_SELECTED);
g_pLogger->Debug("<%s(%d)> SetActiveItem(): Leave",D_PC_LOG_NAME_HVRTREE, __LINE__);
return D_PC_SUCCESS;
}
然后可在单击或双击事件中调用