AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

CTreeCtrl树节点排序,节点复选(菜鸟版)

51自学网 2015-08-30 http://www.51zixue.net

原帖及讨论:http://bbs.bccn.net/thread-211433-1-1.html

效果描述:该功能可使某义节点下的全部子节点按某种序列重新排列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;
}
然后可在单击或双击事件中调用

 

 

 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,51zixue.net不保证资料的完整性。
上一篇:CTreeCtrl结点拖动实现(与后台联动)  下一篇:类WindowXp&nbsp;(CYisongStartMenu)开始菜单&nbsp;编程指南