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 + -
显示快捷键?