TreeCtrlMultiColumn.cpp
上传用户:maicowu
上传日期:2007-01-02
资源大小:87k
文件大小:18k
源码类别:
TreeView控件
开发平台:
Visual C++
- /************************************
- REVISION LOG ENTRY
- Revision By: Mihai Filimon
- Revised on 6/13/98 11:58:20 AM
- Comments: TreeCtrlMultiColumn.cpp: implementation of the CTreeMultiColumnCtrl class.
- ************************************/
- #include "stdafx.h"
- #include "TreeCtrlMultiColumn.h"
- #include "tfilltree.h"
- #define IDLIST 0x1111
- #define dxNode 20
- #define dxSquareNode 9
- #define rgbLine RGB(128,128,128)
- #define rgbExpand RGB(0,0,0)
- #define PS_DOT 2
- //////////////////////////////////////////////////////////////////////
- // Construction/Destruction
- //////////////////////////////////////////////////////////////////////
- BEGIN_MESSAGE_MAP(CTreeMultiColumnCtrl, CTsyslistviewex)
- //{{AFX_MSG_MAP(CTreeMultiColumnCtrl)
- ON_WM_LBUTTONDOWN()
- ON_WM_KEYDOWN()
- //}}AFX_MSG_MAP
- END_MESSAGE_MAP()
- _STTreeMCCloneMessage CTreeMultiColumnCtrl::m_mapCloneMessage;
- // Function name : CTreeMultiColumnCtrl::CTreeMultiColumnCtrl
- // Description : Constructor
- // Return type :
- CTreeMultiColumnCtrl::CTreeMultiColumnCtrl(int nHeightRel):CTsyslistviewex(nHeightRel)
- {
- m_bInsideCode = 0;
- m_nTreeColumn = 0;
- m_nLastItemFind = -1;
- m_nLastItemFound = -1;
- }
- // Function name : CTreeMultiColumnCtrl::~CTreeMultiColumnCtrl
- // Description : virtual Destructor
- // Return type :
- CTreeMultiColumnCtrl::~CTreeMultiColumnCtrl()
- {
- }
- // Function name : CTreeMultiColumnCtrl::SetRootColumn
- // Description : Set the new tree column.
- // Return type : int
- // Argument : int nNewTreeColumn
- int CTreeMultiColumnCtrl::SetRootColumn(int nNewTreeColumn)
- {
- ASSERT (nNewTreeColumn < GetCountColumn());
- ASSERT (nNewTreeColumn >= 0);
- int nOldTreeColumn = m_nTreeColumn;
- m_nTreeColumn = nNewTreeColumn;
- Invalidate();
- return nOldTreeColumn;
- }
- // Function name : CTreeMultiColumnCtrl::GetRootColumn
- // Description : Return the current tree column
- // Return type : int
- int CTreeMultiColumnCtrl::GetRootColumn() const
- {
- return m_nTreeColumn;
- }
- // Function name : CTreeMultiColumnCtrl::DrawCell
- // Description : Draw a cell of tree control
- // Return type : void
- // Argument : CDC* pDC
- // Argument : CRect& drawRect
- // Argument : DWORD format
- // Argument : int nItem
- // Argument : int nColumn
- void CTreeMultiColumnCtrl::DrawCell(CDC* pDC, CRect& drawRect, DWORD format, int nItem, int nColumn)
- {
- m_bInsideCode++;
- if (nColumn == m_nTreeColumn)
- {
- CRect clipRect(drawRect);
- clipRect.top -= 2;
- clipRect.bottom += 2;
- CRgn clipRgn; clipRgn.CreateRectRgnIndirect(clipRect);
- pDC->SelectClipRgn(&clipRgn);
- int i = GetItemData(nItem);
- CArray<int,int> arPathParents;
- int level = GetItemPath(i, arPathParents);
- int x = drawRect.left;
- int yTop = drawRect.top;
- int yBottom = drawRect.bottom;
- CPoint middle(dxNode / 2, drawRect.Height() / 2);
- int psStyle = PS_SOLID;
- CPen penGray( psStyle, 1, rgbLine);
- CPen penBlack(PS_SOLID, 1, rgbExpand);
- CPen* pOldPen = (CPen*)pDC->SelectObject(penGray);
- int j = 0;
- for (j = 0; j < level; j++, x += dxNode)
- if (!IsLastChildren(arPathParents[j]))
- {
- pDC->MoveTo(x + middle.x, yTop - 1);
- pDC->LineTo(x + middle.x, yBottom + 1);
- }
- int yM1 = (yBottom + yTop) / 2;
- int yM2 = yM1;
- int xM1 = x + middle.x;
- int xM2 = xM1;
- if (ItemHasChildren(i))
- {
- SIZE size = {dxSquareNode, dxSquareNode};
- POINT point = {xM1 - size.cx / 2, yM1 - size.cy / 2};
- pDC->FrameRect(CRect(point,size), &CBrush(rgbLine));
- xM1 -= size.cx / 2;
- xM2 += size.cx / 2;
- pDC->SelectObject(penBlack);
- pDC->MoveTo(xM1 + 2, yM1);
- pDC->LineTo(xM2 - 1, yM1);
- yM1 -= size.cy / 2;
- yM2 += size.cy / 2;
- if (!ItemIsExpanded(i))
- {
- pDC->MoveTo(x + middle.x, yM1 + 2);
- pDC->LineTo(x + middle.x, yM2 - 1);
- }
- pDC->SelectObject(penGray);
- }
- if (i != 0)
- {
- pDC->MoveTo(x + middle.x, yTop - 1);
- pDC->LineTo(x + middle.x, yM1);
- }
- if (!IsLastChildren(i))
- {
- pDC->MoveTo(x + middle.x, yM2);
- pDC->LineTo(x + middle.x, yBottom + 1);
- }
- pDC->MoveTo(xM2, (yBottom + yTop) / 2);
- pDC->LineTo(x + dxNode, (yBottom + yTop) / 2);
- x += dxNode;
- drawRect.left = x + 2;
- pDC->SelectClipRgn(NULL);
- }
- CTsyslistviewex::DrawCell(pDC, drawRect, format, nItem, nColumn);
- m_bInsideCode--;
- }
- // Function name : CTreeMultiColumnCtrl::PreSubclassWindow
- // Description : When control is subclassed, object try to construct a clone of this list object
- // Return type : void
- void CTreeMultiColumnCtrl::PreSubclassWindow( )
- {
- CTsyslistviewex::PreSubclassWindow();
- ModifyStyle(LVS_SORTASCENDING,0);
- ModifyStyle(LVS_SORTDESCENDING,0);
- m_listItems.Create(WS_CHILD, CRect(0,0,0,0), this, IDLIST);
- }
- // Function name : CTreeMultiColumnCtrl::WindowProc
- // Description : Treat messages separatly if variable m_bInsideCode is zero
- // Return type : LRESULT
- // Argument : UINT message
- // Argument : WPARAM wParam
- // Argument : LPARAM lParam
- LRESULT CTreeMultiColumnCtrl::WindowProc( UINT message, WPARAM wParam, LPARAM lParam )
- {
- LRESULT result = NULL;
- if (m_bInsideCode == 0)
- if (m_mapCloneMessage.IsCloneMessage(message))
- {
- result = m_listItems.SendMessage(message, wParam, lParam);
- UpdateTree(message, wParam, lParam, result);
- return result;
- }
- if (m_bInsideCode == 0)
- if (m_mapCloneMessage.IsHeaderMessage(message))
- if (m_listItems.GetSafeHwnd())
- m_listItems.SendMessage(message, wParam, lParam);
- result = CTsyslistviewex::WindowProc(message, wParam, lParam );
- return result;
- }
- // Function name : CTreeMultiColumnCtrl::SetItemParent
- // Description : Set the new parent of iItem to iItemParent
- // Return type : BOOL
- // Argument : int iItem
- // Argument : int iItemParent
- BOOL CTreeMultiColumnCtrl::SetItemParent(int iItem, int iItemParent)
- {
- UpdateTree(LVM_SETPARENT, iItem, iItemParent, 0);
- return TRUE;
- }
- // Function name : CTreeMultiColumnCtrl::GetItemParent
- // Description : Return -1 if iItem do not have parent
- // Return type : int
- int CTreeMultiColumnCtrl::GetItemParent(int iItem)
- {
- int value = -1;
- if (m_mapParents.Lookup(iItem, value))
- return value;
- return -1;
- }
- // Function name : CTreeMultiColumnCtrl::GetPath
- // Description : Insert parents of iItem in arParents.
- // Return type : int
- // Argument : int iItem
- // Argument : CArray<int,int>&
- // Argument : arParents
- int CTreeMultiColumnCtrl::GetItemPath(int iItem, CArray<int, int>& arParents)
- {
- arParents.RemoveAll();
- int i = iItem;
- while ((i = GetItemParent(i))>=0)
- arParents.InsertAt(0, i);
- return arParents.GetSize();
- }
- // Function name : CTreeMultiColumnCtrl::ItemIsExpanded
- // Description : Return TRUE if Item is Expanded, FALSE if iItem is collapsed
- // Return type : BOOL
- // Argument : int iItem
- BOOL CTreeMultiColumnCtrl::ItemIsExpanded(int iItem)
- {
- BOOL value = FALSE;
- if (m_mapItemExpanded.Lookup(iItem, value))
- return value;
- return FALSE;
- }
- // Function name : CTreeMultiColumnCtrl::UpdateTree
- // Description : Update the tree control function by message receive by object
- // Return type : void
- // Argument : UINT message
- // Argument : WPARAM wParam
- // Argument : LPARAM lParam
- // Argument : LRESULT result
- void CTreeMultiColumnCtrl::UpdateTree(UINT message, WPARAM wParam, LPARAM lParam, LRESULT result)
- {
- m_bInsideCode++; // Do not process WindowProc...
- switch (message)
- {
- // Set new parent
- case LVM_DELETEALLITEMS:
- {
- m_listItems.DeleteAllItems();
- DeleteAllItems();
- m_mapItemExpanded.RemoveAll();
- m_mapParents.RemoveAll();
- break;
- }
- case LVM_SETPARENT:
- {
- int iItem = (int)wParam;
- int iItemParent = (int)lParam;
- int iItemOldParent = GetItemParent(iItem);
- LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = iItem;
- int i = FindItem(&fInfo);
- while ( (i < GetItemCount()) && ((int)GetItemParent(GetItemData(i)) == iItemOldParent) )
- {
- DeleteItem(i);
- if (iItemOldParent < 0)
- break;
- }
- m_mapItemExpanded.RemoveKey(iItem);
- if (ItemIsExpanded(iItemParent))
- {
- fInfo.flags = LVFI_PARAM;
- fInfo.lParam = iItemParent;
- i = FindItem(&fInfo);
- int newI = InsertItem(i < 0 ? GetItemCount() : i + 1, m_listItems.GetItemText(iItem,0));
- SetItemData(newI, iItem);
- for (int t = 1; t < GetCountColumn(); t++)
- SetItemText(newI, t, m_listItems.GetItemText(iItem,t));
- }
- m_mapParents[iItem] = iItemParent;
- if (CWnd* pParent = GetParent())
- pParent->SendMessage(LVM_SETPARENT, iItem, iItemParent);
- Invalidate();
- break;
- }
- // Insert item
- case LVM_INSERTITEMA:
- case LVM_INSERTITEMW:
- {
- int niItem = InsertItem(GetItemCount(),((const LV_ITEM FAR *)lParam)->pszText);
- SetItemData(niItem,result);
- break;
- }
- // Set the item text
- case LVM_SETITEMA:
- case LVM_SETITEMW:
- case LVM_SETITEMTEXTA:
- case LVM_SETITEMTEXTW:
- {
- const LV_ITEM FAR * pItem = (const LV_ITEM FAR *)lParam;
- LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = pItem->iItem;
- int sItem = FindItem(&fInfo);
- if (sItem >= 0)
- SetItemText(sItem, pItem->iSubItem, pItem->pszText);
- break;
- }
- }
- m_bInsideCode--;
- }
- // Function name : CTreeMultiColumnCtrl::ExpandItem
- // Description : Expand nItem if this has childrens
- // Return type : void
- // Argument : int nItem
- void CTreeMultiColumnCtrl::ExpandItem(int nItem)
- {
- m_bInsideCode++;
- ASSERT (nItem >= 0);
- ASSERT (nItem < m_listItems.GetItemCount());
- if (ItemHasChildren(nItem))
- if (!ItemIsExpanded(nItem))
- {
- LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = nItem;
- int iEnd = FindItem(&fInfo);
- if (iEnd >= 0)
- {
- m_mapItemExpanded[nItem] = TRUE;
- int iStart = iEnd;
- int iChild = GetFirstItemChild(nItem);
- while (iChild >= 0)
- {
- int newI = InsertItem(++iEnd,m_listItems.GetItemText(iChild,0));
- for (int t = 1; t < GetCountColumn(); t++)
- SetItemText(newI, t, m_listItems.GetItemText(iChild,t));
- SetItemData(newI, iChild);
- iChild = GetNextItemChild();
- }
- RedrawItems(iStart,iStart);
- if (CWnd* pParent = GetParent())
- pParent->SendMessage(LVM_EXPAND, nItem, 0);
- }
- }
- m_bInsideCode--;
- }
- // Function name : CTreeMultiColumnCtrl::RecExpandItems
- // Description : Expand all childs of nItem recursively
- // Return type : void
- // Argument : int nItem
- void CTreeMultiColumnCtrl::RecExpandItems(int nItem)
- {
- ExpandItem(nItem);
- int iChild = GetFirstItemChild(nItem);
- CArray<int,int> arChilds;
- while (iChild >= 0)
- {
- arChilds.Add(iChild);
- iChild = GetNextItemChild();
- };
- for (int k = 0; k < arChilds.GetSize(); k++)
- RecExpandItems(arChilds[k]);
- }
- // Function name : CTreeMultiColumnCtrl::CollapseItem
- // Description : Close item nItem if that has childrens
- // Return type : void
- // Argument : int nItem
- void CTreeMultiColumnCtrl::CollapseItem(int nItem)
- {
- m_bInsideCode++;
- ASSERT (nItem >= 0);
- ASSERT (nItem < m_listItems.GetItemCount());
- if (ItemHasChildren(nItem))
- if (ItemIsExpanded(nItem))
- {
- m_mapItemExpanded.RemoveKey(nItem);
- LV_FINDINFO fInfo; fInfo.flags = LVFI_PARAM; fInfo.lParam = nItem;
- int iEnd = FindItem(&fInfo);
- if (iEnd >=0)
- {
- int iStart = iEnd;
- iEnd++;
- while (iEnd < GetItemCount())
- {
- CArray<int,int> arPathParents;
- int nTrueItem = GetItemData(iEnd);
- int level = GetItemPath(nTrueItem, arPathParents);
- if (level)
- {
- level--;
- while ((level>=0) && (arPathParents[level] != nItem)) level--;
- if ( level>=0 )
- {
- m_mapItemExpanded.RemoveKey(nTrueItem);
- DeleteItem(iEnd);
- }
- else
- break;
- }
- else break;
- }
- RedrawItems(iStart,iStart);
- if (CWnd* pParent = GetParent())
- pParent->SendMessage(LVM_COLLAPSE, nItem, 0);
- }
- }
- m_bInsideCode--;
- }
- // Function name : CTreeMultiColumnCtrl::GetItemLevel
- // Description : Return the level of item nItem
- // Return type : int
- // Argument : int nItem
- int CTreeMultiColumnCtrl::GetItemLevel(int nItem)
- {
- int i = nItem;
- int result = 0;
- while ((i = GetItemParent(i))>=0) result++;
- return result;
- }
- // Function name : CTreeMultiColumnCtrl::IsPtnInSquareRect
- // Description : Return true if item from point has childrens, and point is in
- // square node.
- // Return type : BOOL
- // Argument : CPoint point
- BOOL CTreeMultiColumnCtrl::IsPtnInSquareRect(CPoint point)
- {
- int subItem = -1;
- int nItem = HitTestEx(point, subItem);
- CRect rect;
- if (subItem == m_nTreeColumn)
- {
- int nTrueItem = GetItemData(nItem);
- if (ItemHasChildren(nTrueItem))
- if (GetSubItemRect(nItem, subItem, rect))
- {
- CRect rectSquare(CPoint(rect.left + GetItemLevel(nTrueItem) * dxNode + (dxNode - dxSquareNode) / 2, (rect.top + rect.bottom)/2 - dxSquareNode/2), CSize(dxSquareNode,dxSquareNode));
- return rectSquare.PtInRect(point + CPoint(-2,0));
- }
- }
- return FALSE;
- }
- // Function name : CTreeMultiColumnCtrl::OnLButtonDown
- // Description : If user press the left button of mouse...
- // Return type : void
- // Argument : UINT nFlags
- // Argument : CPoint point
- void CTreeMultiColumnCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- {
- int subItem = -1;
- int nItem = HitTestEx(point, subItem);
- if ((nItem >= 0) && (IsPtnInSquareRect(point)))
- {
- int nTrueItem = GetItemData(nItem);
- if (ItemHasChildren(nTrueItem))
- if (!ItemIsExpanded(nTrueItem))
- ExpandItem(nTrueItem);
- else
- CollapseItem(nTrueItem);
- }
- CTsyslistviewex::OnLButtonDown(nFlags, point);
- }
- // Function name : CTreeMultiColumnCtrl::OnKeyDown
- // Description : If user press the one of following keys...
- // Return type : void
- // Argument : UINT nChar
- // Argument : UINT nRepCnt
- // Argument : UINT nFlags
- void CTreeMultiColumnCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
- {
- m_bInsideCode++;
- int iSelected = -1;
- while ((iSelected = GetNextItem(iSelected, LVNI_SELECTED))>=0)
- {
- int nTrueItem = GetItemData(iSelected);
- switch (nChar)
- {
- case VK_ADD:
- case VK_RIGHT:
- {
- ExpandItem(nTrueItem);
- break;
- }
- case VK_SUBTRACT:
- case VK_LEFT:
- {
- CollapseItem(nTrueItem);
- break;
- }
- case VK_MULTIPLY:
- {
- RecExpandItems(nTrueItem);
- break;
- }
- }
- iSelected++;
- }
- m_bInsideCode--;
- if ((nChar != VK_RIGHT) && (nChar != VK_LEFT))
- CTsyslistviewex::OnKeyDown(nChar, nRepCnt, nFlags);
- }
- // Function name : CTreeMultiColumnCtrl::Fill
- // Description : Fill the tree control with items from lpszItems. See tfilltree.h, tfilltree.cpp
- // Return type : void
- // Argument : LPCTSTR lpszItems
- void CTreeMultiColumnCtrl::Fill(LPCTSTR lpszItems)
- {
- STFillTreeMultiColumn s(this, lpszItems);
- s.Fill();
- }
- // Function name : CTreeMultiColumnCtrl::Delete
- // Description :
- // Return type : BOOL
- // Argument : int nItem
- // Argument : BOOL bRecurse
- BOOL CTreeMultiColumnCtrl::Delete(int nItem)
- {
- int nTrueItem = GetItemData(nItem);
- if (!ItemHasChildren(nTrueItem))
- {
- m_bInsideCode++;
- DeleteItem(nItem);
- m_mapItemDeleted[nTrueItem] = TRUE;
- int lItem = max(0, nItem - 1);
- RedrawItems(lItem, lItem);
- m_bInsideCode--;
- return TRUE;
- }
- return FALSE;
- }
- // Function name : CTreeMultiColumnCtrl::IsDeleted
- // Description :
- // Return type : BOOL
- // Argument : int nItem
- BOOL CTreeMultiColumnCtrl::IsDeleted(int nItem)
- {
- BOOL bValue = FALSE;
- m_mapItemDeleted.Lookup(nItem, bValue);
- return bValue;
- }
- // Function name : CTreeMultiColumnCtrl::ItemHasChildren
- // Description : Return TRUE if item iItem has at least one children
- // Return type : BOOL
- // Argument : int iItem
- BOOL CTreeMultiColumnCtrl::ItemHasChildren(int iItem)
- {
- int key = -1;
- int value = -1;
- POSITION position = m_mapParents.GetStartPosition();
- while (position)
- {
- m_mapParents.GetNextAssoc(position, key, value);
- if (!IsDeleted(value))
- if (!IsDeleted(key))
- if (value == iItem)
- return TRUE;
- }
- return FALSE;
- }
- // Function name : CTreeMultiColumnCtrl::GetFirstItemChild
- // Description : Return the index of first item child of nItem
- // Return type : int
- // Argument : int nItem
- int CTreeMultiColumnCtrl::GetFirstItemChild(int nItem)
- {
- m_nLastItemFind = -1;
- m_nLastItemFound = nItem;
- return GetNextItemChild();
- }
- // Function name : CTreeMultiColumnCtrl::GetNextItemChild
- // Description : Return the index of next item child of nItem
- // Return type : int
- int CTreeMultiColumnCtrl::GetNextItemChild()
- {
- m_nLastItemFind++;
- while (IsDeleted(m_nLastItemFind) || ((m_nLastItemFind < m_listItems.GetItemCount()) && (GetItemParent(m_nLastItemFind) != m_nLastItemFound)))
- m_nLastItemFind++;
- if (m_nLastItemFind < m_listItems.GetItemCount())
- return m_nLastItemFind;
- return -1;
- }
- // Function name : CTreeMultiColumnCtrl::IsLastChildren
- // Description : Check if iItem is last children
- // Return type : BOOL
- // Argument : int iItem
- BOOL CTreeMultiColumnCtrl::IsLastChildren(int iItem)
- {
- int iParent = GetItemParent(iItem);
- int cItem = m_listItems.GetItemCount();
- int i = iItem + 1;
- while (i < cItem)
- {
- if (!IsDeleted(i))
- if (!IsDeleted(GetItemParent(i)))
- if (GetItemParent(i) == iParent)
- return FALSE;
- i++;
- }
- return TRUE;
- }
- //-------------------------------------------------------------------------------//