treectrlhelper.cpp

来自「管理项目进度工具的原代码」· C++ 代码 · 共 739 行 · 第 1/2 页

CPP
739
字号
// TreeCtrlHelper.cpp: implementation of the CTreeCtrlHelper class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "TreeCtrlHelper.h"
#include "holdredraw.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

const int HVISIBLE = 20;

CTreeCtrlHelper::CTreeCtrlHelper(CTreeCtrl& tree) : m_tree(tree)
{
	m_pVisibleIndices = new CMapIndices();
}

CTreeCtrlHelper::~CTreeCtrlHelper()
{
	delete m_pVisibleIndices;
}

CMapIndices& CTreeCtrlHelper::VIMap()
{
	ASSERT (m_pVisibleIndices);

	return *m_pVisibleIndices;
}
	
const CMapIndices& CTreeCtrlHelper::VIMap() const
{
	ASSERT (m_pVisibleIndices);

	return *m_pVisibleIndices;
}

int CTreeCtrlHelper::GetItemPos(HTREEITEM hti, HTREEITEM htiParent)
{
	ASSERT (m_tree.GetParentItem(hti) == htiParent);
	
	int nPos = 1;
	HTREEITEM htiChild = m_tree.GetChildItem(htiParent);
	
	while (htiChild && htiChild != hti)
	{
		nPos++;
		htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
	}
	
	return nPos;
}

int CTreeCtrlHelper::GetItemLevel(HTREEITEM hti)
{
	int nLevel = 0;
	hti = m_tree.GetParentItem(hti);
	
	while (hti)
	{
		nLevel++;
		hti = m_tree.GetParentItem(hti);
	}
	
	return nLevel;
}

BOOL CTreeCtrlHelper::HasFocus(BOOL bIncEditing)
{
	CWnd* pFocus = m_tree.GetFocus();
	
	return (pFocus && (pFocus == &m_tree || (bIncEditing && pFocus == m_tree.GetEditControl())));
}

void CTreeCtrlHelper::ExpandAll(BOOL bExpand, HTREEITEM hti)
{
   CHoldRedraw hr(m_tree);

   ExpandItem(hti, bExpand);
}

void CTreeCtrlHelper::ExpandItem(HTREEITEM hti, BOOL bExpand)
{
   if (hti)
      m_tree.Expand(hti, bExpand ? TVE_EXPAND : TVE_COLLAPSE);

   HTREEITEM htiChild = m_tree.GetChildItem(hti);

   while (htiChild)
   {
      ExpandItem(htiChild, bExpand);
      htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
   }
}

void CTreeCtrlHelper::GetClientRect(LPRECT lpRect, HTREEITEM htiFrom)
{
	m_tree.GetClientRect(lpRect);

	if (htiFrom)
	{
		CRect rItem;
		m_tree.GetItemRect(htiFrom, rItem, FALSE);
		lpRect->top = max(0, rItem.top); // rItem.top could be invisible
	}
}

HTREEITEM CTreeCtrlHelper::GetFirstVisibleTopLevelItem(int& nPos)
{
	HTREEITEM htiTopVis = GetTopLevelParentItem(m_tree.GetFirstVisibleItem());

	// iterate the top level items to find out what pos this is
	nPos = GetItemPos(htiTopVis, NULL);
	
	return htiTopVis;
}

HTREEITEM CTreeCtrlHelper::GetTopLevelParentItem(HTREEITEM hti)
{
	HTREEITEM htiPrevParent = hti;
	hti = m_tree.GetParentItem(hti);

	while (hti)
	{
		htiPrevParent = hti;
		hti = m_tree.GetParentItem(hti);
	}
	
	return htiPrevParent;
}

void CTreeCtrlHelper::InvalidateItem(HTREEITEM hti, BOOL bChildren)
{
	CRect rItem;
	
	if (m_tree.GetItemRect(hti, rItem, FALSE))
		m_tree.InvalidateRect(rItem);
	
	if (bChildren && IsItemExpanded(hti))
	{
		HTREEITEM htiChild = m_tree.GetChildItem(hti);
		
		while (htiChild)
		{
			InvalidateItem(htiChild, TRUE);
			htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
		}
	}
}

int CTreeCtrlHelper::BuildVisibleIndexMap(CMapIndices& index)
{
	index.RemoveAll();
	
	HTREEITEM hti = m_tree.GetChildItem(NULL);
	
	while (hti)
	{
		AddVisibleItemToIndex(index, hti);
		hti = m_tree.GetNextItem(hti, TVGN_NEXT);
	}
	
	return index.GetCount();
}

void CTreeCtrlHelper::AddVisibleItemToIndex(CMapIndices& index, HTREEITEM hti)
{
	ASSERT (hti);
	
	int nIndex = index.GetCount();
	index[hti] = nIndex;
	
	if (IsItemExpanded(hti))
	{
		HTREEITEM htiChild = m_tree.GetChildItem(hti);
		
		while (htiChild)
		{
			AddVisibleItemToIndex(index, htiChild);
			htiChild = m_tree.GetNextItem(htiChild, TVGN_NEXT);
		}
	}
}

void CTreeCtrlHelper::EnsureVisibleEx(HTREEITEM hti, BOOL bVPartialOK, BOOL bHPartialOK)
{
	CRect rItem;

	if (m_tree.GetItemRect(hti, rItem, FALSE))
	{
		CRect rClient, rText, rIntersect;

		m_tree.GetClientRect(rClient);
	
		BOOL bNeedHScroll = TRUE, bNeedVScroll = TRUE;

		// vertically
		rClient.InflateRect(0, m_tree.GetItemHeight());

		if (rIntersect.IntersectRect(rClient, rItem))
		{
			if (bVPartialOK || (rItem.top >= rClient.top && rItem.bottom <= rClient.bottom))
				bNeedVScroll = FALSE;
		}

		// horizontally
		rClient.DeflateRect(HVISIBLE, 0);
		m_tree.GetItemRect(hti, rText, TRUE);

		if (rIntersect.IntersectRect(rClient, rText))
		{
			if (bHPartialOK || (rText.left >= rClient.left && rText.right <= rClient.right))
				bNeedHScroll = FALSE;
		}

		// see if we're close enough already
		if (!bNeedVScroll && !bNeedHScroll)
			return;

		m_tree.SetRedraw(FALSE);

		// vertical scroll
		if (bNeedVScroll)
		{
			// now get us as close as possible first
			// Only use CTreeCtrl::EnsureVisible if we're not in the right vertical pos
			// because it will also modify the horizontal pos which we don't want
			m_tree.EnsureVisible(hti);
			m_tree.GetItemRect(hti, rItem, FALSE);

			CRect rOrg(rItem);
			
			if (rItem.top < rClient.top || (bVPartialOK && rItem.bottom < rClient.top))
			{
				while (rClient.top > (bVPartialOK ? rItem.bottom : rItem.top))
				{
					m_tree.SendMessage(WM_VSCROLL, SB_LINEUP);
					m_tree.GetItemRect(hti, rItem, TRUE); // check again
					
					// check for no change
					if (rItem == rOrg)
						break;
					
					rOrg = rItem;
				}
			}
			else if (rItem.bottom > rClient.bottom || (bVPartialOK && rItem.top > rClient.bottom))
			{
				while (rClient.bottom < (bVPartialOK ? rItem.top : rItem.bottom))
				{
					m_tree.SendMessage(WM_VSCROLL, SB_LINEDOWN);
					m_tree.GetItemRect(hti, rItem, TRUE); // check again
					
					// check for no change
					if (rItem == rOrg)
						break;
					
					rOrg = rItem;
				}
			}
			
			bNeedVScroll = TRUE;
		}

		// horizontal scroll
		// reset scroll pos if we previously called CTreeCtrl::EnsureVisible
		if (bNeedVScroll)
		{
			m_tree.SendMessage(WM_HSCROLL, SB_LEFT);
			m_tree.GetItemRect(hti, rText, TRUE);
		}

		if (bNeedVScroll || bNeedHScroll)
		{
			rItem = rText;
			CRect rOrg(rItem);

			if (rItem.left < rClient.left || (bHPartialOK && rItem.right < rClient.left))
			{
				while (rClient.left > (bHPartialOK ? rItem.right : rItem.left))
				{
					m_tree.SendMessage(WM_HSCROLL, SB_LINELEFT);
					m_tree.GetItemRect(hti, rItem, TRUE); // check again

					// check for no change
					if (rItem == rOrg)
						break;

					rOrg = rItem;
				}
			}
			else if (rItem.right > rClient.right || (bHPartialOK && rItem.left > rClient.right))
			{
				while (rClient.right < (bHPartialOK ? rItem.left : rItem.right))
				{
					m_tree.SendMessage(WM_HSCROLL, SB_LINERIGHT);
					m_tree.GetItemRect(hti, rItem, TRUE); // check again

					// check for no change
					if (rItem == rOrg)
						break;

					rOrg = rItem;
				}
			}
		}
		
		m_tree.SetRedraw(TRUE);
	}
	else
		m_tree.EnsureVisible(hti);
}

BOOL CTreeCtrlHelper::ItemLineIsOdd(CMapIndices& index, HTREEITEM hti)
{
	// simple check on whether Visible item map has been created
	// for the first time
	if (m_tree.GetCount() && !index.GetCount())
		BuildVisibleIndexMap(index);
	
	int nIndex = -1;
	
	if (index.Lookup(hti, nIndex))
		return (nIndex % 2);
	
	return FALSE;
}

void CTreeCtrlHelper::SetItemIntegral(HTREEITEM hti, int iIntegral)
{
	TVITEMEX tvi;
	tvi.mask = TVIF_HANDLE | TVIF_INTEGRAL;
	tvi.hItem = hti;
	tvi.iIntegral = iIntegral;
	
	m_tree.SetItem((LPTVITEM)&tvi);
}

BOOL CTreeCtrlHelper::IsItemExpanded(HTREEITEM hItem) const
{
	return m_tree.GetItemState(hItem, TVIS_EXPANDED) & TVIS_EXPANDED;
}

void CTreeCtrlHelper::SetItemChecked(HTREEITEM hti, TCH_CHECK nChecked)
{
	int nCheckState = 0;
   
   switch (nChecked)
   {
   case TCHC_UNCHECKED:
      nCheckState = INDEXTOSTATEIMAGEMASK(1);
      break;
      
   case TCHC_CHECKED:
      nCheckState = INDEXTOSTATEIMAGEMASK(2);
      break;
      
   case TCHC_MIXED:
      nCheckState = INDEXTOSTATEIMAGEMASK(3);
      break;
   }

   if (nCheckState)

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?