MFC中CtreeCtrl控件实现三态复选的总结

来源:互联网 发布:学蛋糕的软件 编辑:程序博客网 时间:2024/06/05 05:31

对网上现有资料整理总结

网上所能查到的所有关于树形控件三态显示的做法都是添加一个已写好的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);
}


//----持续改进中----


0 0
原创粉丝点击