MFC中CtreeCtrl控件實現三態複選的總結

對網上現有資料整理總結

網上所能查到的所有關於樹形控件三態顯示的做法都是添加一個已寫好的CTreeCtrl類的派生類,但經過Q姐琢磨和測試,根本無需再創建一個派生類就能實現樹形控件的三態複選,下面分享具體做法。

1.給樹形控件綁定變量

CTreeCtrl m_tc;

2.添加三態顯示框bmp資源,如下

3.添加樹形控件三態顯示效果相關函數

//.cpp文件

BOOL CxxxDlg::SetState(HTREEITEM hItem, UINT nState, UINT nStateMask, BOOL bSearch)
{
 BOOL bReturn=m_tc.SetItemState( hItem, nState, nStateMask );

 UINT iState = nState >> 12;
 if(iState!=0)
 {
  if(bSearch) TravelChild(hItem, iState);
  TravelSiblingAndParent(hItem,iState);
 }
 return bReturn;
}

void CxxxDlg::TravelChild(HTREEITEM hItem, int nState)
{
 HTREEITEM hChildItem,hBrotherItem;
 
 //查找子節點,沒有就結束
 hChildItem=m_tc.GetChildItem(hItem);
 if(hChildItem!=NULL)
 {
  //設置子節點的狀態與當前節點的狀態一致
  m_tc.SetItemState( hChildItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );
  //再遞歸處理子節點的子節點和兄弟節點
  TravelChild(hChildItem, nState);
  
  //處理子節點的兄弟節點和其子節點
  hBrotherItem=m_tc.GetNextSiblingItem(hChildItem);
  while (hBrotherItem)
  {
   //設置子節點的兄弟節點狀態與當前節點的狀態一致
   int nState1 =m_tc.GetItemState( hBrotherItem, TVIS_STATEIMAGEMASK ) >> 12;
   if(nState1!=0)
   {
    m_tc.SetItemState( hBrotherItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );
   }
   //再遞歸處理子節點的兄弟節點的子節點和兄弟節點
   TravelChild(hBrotherItem, nState);
   hBrotherItem=m_tc.GetNextSiblingItem(hBrotherItem);
  }
 }
}

void CtreeDlg::TravelSiblingAndParent(HTREEITEM hItem, int nState)
{
 HTREEITEM hNextSiblingItem,hPrevSiblingItem,hParentItem;
 
 //查找父節點,沒有就結束
 hParentItem=m_tc.GetParentItem(hItem);
 if(hParentItem!=NULL)
 {
  int nState1=nState;//設初始值,防止沒有兄弟節點時出錯
  
  //查找當前節點下面的兄弟節點的狀態
  hNextSiblingItem=m_tc.GetNextSiblingItem(hItem);
  while(hNextSiblingItem!=NULL)
  {
   nState1 = m_tc.GetItemState( hNextSiblingItem, TVIS_STATEIMAGEMASK ) >> 12;
   if(nState1!=nState && nState1!=0) break;
   else hNextSiblingItem=m_tc.GetNextSiblingItem(hNextSiblingItem);
  }
  
  if(nState1==nState)
  {
   //查找當前節點上面的兄弟節點的狀態
   hPrevSiblingItem=m_tc.GetPrevSiblingItem(hItem);
   while(hPrevSiblingItem!=NULL)
   {
    nState1 = m_tc.GetItemState( hPrevSiblingItem, TVIS_STATEIMAGEMASK ) >> 12;
    if(nState1!=nState && nState1!=0) break;
    else hPrevSiblingItem=m_tc.GetPrevSiblingItem(hPrevSiblingItem);
   }
  }
  
  if(nState1==nState || nState1==0)
  {
   nState1 = m_tc.GetItemState( hParentItem, TVIS_STATEIMAGEMASK ) >> 12;
   if(nState1!=0)
   {
    //如果狀態一致,則父節點的狀態與當前節點的狀態一致
    m_tc.SetItemState( hParentItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );
   }
   //再遞歸處理父節點的兄弟節點和其父節點
   TravelSiblingAndParent(hParentItem,nState);
  }
  else
  {
   //狀態不一致,則當前節點的父節點、父節點的父節點……狀態均爲第三態
   hParentItem=m_tc.GetParentItem(hItem);
   while(hParentItem!=NULL)
   {
    nState1 = m_tc.GetItemState( hParentItem, TVIS_STATEIMAGEMASK ) >> 12;
    if(nState1!=0)
    {
     m_tc.SetItemState( hParentItem, INDEXTOSTATEIMAGEMASK(2), TVIS_STATEIMAGEMASK );
    }
    hParentItem=m_tc.GetParentItem(hParentItem);
   }
  }
 } 
}

4.添加樹形控件單擊響應事件NM_CLICK

void CxxxDlg::OnNMClickTreeTable(NMHDR* pNMHDR, LRESULT* pResult)
{
 CPoint point;
 UINT uFlag = 0;
 GetCursorPos(&point);
 m_tc.ScreenToClient(&point);

 HTREEITEM hItem = m_tc.HitTest(point, &uFlag);

 if((hItem) && (TVHT_ONITEM & uFlag))
 {
  m_tc.Select(hItem, TVGN_CARET | TVGN_DROPHILITE); //此做法爲了不管鼠標點擊的是複選框還是文字,都高亮此節點
  if (TVHT_ONITEMSTATEICON & uFlag)
  {
   //nState: 0->無選擇鈕 1->沒有選擇 2->部分選擇 3->全部選擇
   UINT nState = m_tc.GetItemState( hItem, TVIS_STATEIMAGEMASK ) >> 12;
   nState=(nState==3)?1:3;
   SetState( hItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );
  }
  *pResult=1;
 }
 else
  *pResult = 0;
}

-------------------------------------------------over----------------------------------------------------------------

總結:以上代碼與專門創建一個CtreeCtrl派生類最大的區別:

減少了代碼量,根本沒必要再創建一個CtreeCtrl派生類。


如想實現遍歷效果

void CxxxDlg::TravelItem(HTREEITEM hTreeItem)  
{  
 HTREEITEM hCurItem = m_tc.GetChildItem(hTreeItem);
 HTREEITEM hNextItem;
 CString strItemText("");
 while(hCurItem)
 {
  //OutputDebugString(tree.GetItemText(hCurItem)); // 輸出結點文本
  strItemText = m_tc.GetItemText(hCurItem);
  hNextItem = hCurItem;
  TravelItem(hNextItem);
  hCurItem = m_tc.GetNextSiblingItem(hCurItem);
 }
    m_tc.Expand(hTreeItem,TVE_EXPAND);
}

應用時如下:

TravelItem(m_tc.GetRootItem());


//-------------------------------補充功能:空格鍵實現復現功能----------------------------------

BOOL CxxxDlg::PreTranslateMessage( MSG* pMsg )
{
if (pMsg->message == WM_KEYDOWN)  
{  
if (pMsg->wParam == VK_SPACE)  
{          
UINT btnID = GetWindowLong(pMsg->hwnd, GWL_ID); 
if (btnID == IDC_TREE_TABLE) 
{
HTREEITEM hItem = m_TreeCtrl_Table.GetSelectedItem();
if(hItem)
{
UINT nState = m_tc.GetItemState( hItem, TVIS_STATEIMAGEMASK ) >> 12;
    nState=(nState==3)?1:3;
    SetState( hItem, INDEXTOSTATEIMAGEMASK(nState), TVIS_STATEIMAGEMASK );
}
return true;  
}

}
return __super::PreTranslateMessage(pMsg);
}


//----持續改進中----


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章