www.gusucode.com > 学习VC++的一些小实例源码程序 > 学习VC++的一些小实例(界面、游戏、简单图形处理、算法、数据库操作)源码程序/code/sample/ch06/Tree/TreeView.cpp

    //Download by http://www.NewXing.com
// TreeView.cpp : implementation of the CMyTreeView class
//

#include "stdafx.h"
#include "Tree.h"

#include "TreeDoc.h"
#include "TreeView.h"
#include "AnmlData.h"
#include "SimpleListView.h"
#include "AnimalDlg.h"
#include "ModifyDlg.h"
#include "ModifyType.h"

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

/////////////////////////////////////////////////////////////////////////////
// CMyTreeView

IMPLEMENT_DYNCREATE(CMyTreeView, CTreeView)

BEGIN_MESSAGE_MAP(CMyTreeView, CTreeView)
	//{{AFX_MSG_MAP(CMyTreeView)
	ON_WM_CREATE()
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMyTreeView construction/destruction

CMyTreeView::CMyTreeView()
{
	// TODO: add construction code here

}

CMyTreeView::~CMyTreeView()
{
}

BOOL CMyTreeView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CTreeView::PreCreateWindow(cs);
}

/////////////////////////////////////////////////////////////////////////////
// CMyTreeView drawing

void CMyTreeView::OnDraw(CDC* pDC)
{
	CTreeDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	// TODO: add draw code for native data here
}

void CMyTreeView::OnInitialUpdate()
{
	CTreeView::OnInitialUpdate();


	GetTreeCtrl().ModifyStyle(NULL,
							TVS_HASBUTTONS | TVS_HASLINES | TVS_LINESATROOT);
}

/////////////////////////////////////////////////////////////////////////////
// CMyTreeView diagnostics

#ifdef _DEBUG
void CMyTreeView::AssertValid() const
{
	CTreeView::AssertValid();
}

void CMyTreeView::Dump(CDumpContext& dc) const
{
	CTreeView::Dump(dc);
}

CTreeDoc* CMyTreeView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CTreeDoc)));
	return (CTreeDoc*)m_pDocument;
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CMyTreeView message handlers

int CMyTreeView::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CTreeView::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	GetDocument()->m_pTreeView = this;
	
	return 0;
}

void CMyTreeView::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	// TODO: Add your control notification handler code here

	*pResult = 0;

	// Obtain a reference to the CTreeControl object that is
	// embedded in this view class.
	CTreeCtrl & ctlTree = GetTreeCtrl();
	
	// Determining which item the user has selected is a 2-step
	// process. You first obtain the handle to the selected item.
	HTREEITEM selectedNode = ctlTree.GetSelectedItem();

	// In the second step, you call a specific function
	// (GetItemText, GetItemData, GetItemState or GetItemImage)
	// to obtain a specific piece of information from the selected item,
	DWORD itemData = ctlTree.GetItemData(selectedNode);

	CTreeDoc * pDoc = GetDocument();
	switch (itemData)
	{
		case 0:
			// For root nodes, the list will iterate over the selected
			// item and display all the types it contains.
			pDoc->m_pListView->DisplayClassInfo(selectedNode);
			break;
		case -1:
			// In the case of a level 1 node, give it the HTREEITEM
			// and let it iterate over that node's children.
			pDoc->m_pListView->DisplayTypeInfo(selectedNode);
			break;
		default:
			// For level 2 nodes, the selected item's data contains
			// its POSITION in the document object's CList.
			pDoc->m_pListView->DisplayAnimalInfo(itemData);
	}

}

HTREEITEM CMyTreeView::FindNode(const HTREEITEM ParentNode, const CString &str) const
{
	CTreeCtrl & ctc = GetTreeCtrl();
	HTREEITEM node;
	CString s;

	if (NULL == ParentNode)
		node = ctc.GetRootItem();
	else
		if (ctc.GetRootItem() == ParentNode)
			node = ParentNode;
		else
			node = ctc.GetChildItem(ParentNode);
	
	while (node != NULL)
	{
		s = ctc.GetItemText(node);
		// Halt the search when we find what we're looking for.
		if (0 == s.CompareNoCase(str))
			return node;
		node = ctc.GetNextItem(node, TVGN_NEXT);
	}
	// If we get to here, string was never found, and node == NULL.
	return node;
}

HTREEITEM CMyTreeView::InsertNode(const HTREEITEM ParentNode,  const CString &str, const DWORD itemData)
{
	CTreeCtrl & ctc = GetTreeCtrl();
	HTREEITEM node;

	node = ctc.InsertItem(str, ParentNode, TVI_SORT);
	ctc.SetItemData(node, itemData);

	return node;
}
void CMyTreeView::PopulateTree()
{
	GetTreeCtrl().DeleteAllItems();
	GetDocument()->m_pListView->EraseList();
	InsertRootNodes();
	InsertDataNodes();
}

void CMyTreeView::InsertRootNodes()
{	
	// For this simple program, where the tree goes at most 2 levels deep,
	// item data will be 0 at all root nodes and -1 at all first level nodes.
	// At second level nodes, item data will be the POSITION of a given node
	// in the document object's CList member. Each node also contains a string.
	// See OnSelchanged to see how these 2 pieces of information are extracted
	// and used when the user clicks on a node in the tree control.

	CString s;
	for (int i = IDS_AMPHIBIANS; i <= IDS_REPTILES; i++)
	{
		s.LoadString(i);
		InsertNode(TVI_ROOT, s, 0);
	}
}

void CMyTreeView::InsertDataNodes()
{
	CTreeDoc* pDoc = GetDocument();

	// The idea here is to iterate over the document's CList object	and
	// insert some data from each member of the CList into the tree control.
	// Data not inserted in the tree will be shown in the list view when the
	// user selects an item from the tree. The leaf nodes of the tree control
	// will store a POSITION member that will facilitate searching the
	// document's CList by the list view.
	POSITION current, pos = pDoc->m_AnimalList.GetHeadPosition();
	while (NULL != pos)
	{
		current = pos;
		CAnimalInfo & rAnimal = pDoc->m_AnimalList.GetNext(pos);
		LocateAndInsert(rAnimal, current);
	}
}
BOOL CMyTreeView::LocateAndInsert(const CAnimalInfo & Animal, const POSITION pos)
{
	HTREEITEM classnode, typenode;

	// Begin by locating the node where the item will be inserted.
	// If the root node doesn't exist, return from function.
	if ((classnode = FindNode(NULL, Animal.m_class)) == 0)
		return FALSE;

	// Next, iterate over that node looking for the type,
	// and insert type if it doesn't exist.
	if ((typenode = FindNode(classnode, Animal.m_type)) == 0)
		typenode = InsertNode(classnode, Animal.m_type, (DWORD)-1);

	if (0 == typenode)
		return FALSE;

	// By this time we know we've got the class and the type.
	// If the animal itself isn't already inserted, insert it.
	if ((FindNode(typenode, Animal.m_animal)) == 0)
		if (InsertNode(typenode, Animal.m_animal, (DWORD) pos) != 0)
			return TRUE;
	return FALSE;
}
void CMyTreeView::ModifySelection()
{
	// Obtain a reference to the CTreeControl object.
	CTreeCtrl & ctlTree = GetTreeCtrl();
	
	// Obtain the handle of the selected item.
	HTREEITEM selectedNode = ctlTree.GetSelectedItem();

	// If item data indicates it's at level 0, do nothing.
	// At level one, let the user change the spelling of the animal's type. 
	// Otherwise, let the user modify the animal's name or weight,
	// but not its class or type.
	DWORD itemData = ctlTree.GetItemData(selectedNode);
	switch (itemData)
	{
		case 0:
			break;
		case -1:
			ModifyType(selectedNode, itemData);
			break;
		default:
			ModifyAnimal(selectedNode, itemData);
	}
}

void CMyTreeView::DeleteSelection()
{
	// Obtain a reference to the CTreeControl object.
	CTreeCtrl & ctlTree = GetTreeCtrl();
	
	// Obtain the handle of the selected item.
	HTREEITEM selectedNode = ctlTree.GetSelectedItem();

	// If item data indicates it's at level 0 or -1 do nothing.
	// Otherwise, confirm the deletion, delete the item from the tree,
	// then delete it from the CList.
	DWORD itemData = ctlTree.GetItemData(selectedNode);

	if (0 == itemData || -1 == itemData)
		return;

	CString AnimalName = ctlTree.GetItemText(selectedNode);
	CString s;
	s.Format("Are you sure you want to delete '%s' from the database?",
			 AnimalName);
	int rc = MessageBox(s, "Confirm Deletion", MB_YESNO | MB_ICONQUESTION);
	if (IDNO == rc)
		return;

	// Before deleting the selected item, obtain a handle to its parent.
	HTREEITEM parent = ctlTree.GetParentItem(selectedNode);

	// Remove the selected item from the tree.
	ctlTree.DeleteItem(selectedNode);

	// Then remove it from the document's CList and set the modified flag.
	CTreeDoc * pDoc = GetDocument();
	pDoc->m_AnimalList.RemoveAt((POSITION)itemData);
	pDoc->SetModifiedFlag();

	// Finally, select the deleted node's parent.
	ctlTree.SelectItem(parent);
}

void CMyTreeView::EditSelection()
{
	CAnimalDlg dlg;

	if (IDOK == dlg.DoModal())
	{
		// Construct CAnimalInfo object with 4 values from the dialog object.
		CAnimalInfo my_object(dlg.m_class, dlg.m_type,
								dlg.m_animal, dlg.m_weight);
		
		// Insert the object into the document class.
		CTreeDoc * pDoc = GetDocument();
		POSITION pos = pDoc->InsertData(my_object);
		
		// Then insert it into the tree view.
		LocateAndInsert(my_object, pos);
	}
}

void CMyTreeView::ModifyType(const HTREEITEM selectedNode, const DWORD itemData)
{
	CTreeCtrl & ctlTree = GetTreeCtrl();
	CString AnimalType = ctlTree.GetItemText(selectedNode);

	CModifyType dlg;
	dlg.m_type = AnimalType;

	if (IDOK == dlg.DoModal())
	{
		// First, change the text in the selected node of the tree.
		ctlTree.SetItemText(selectedNode, dlg.m_type);
		
		// Second, sort the parent of the selected node, since the
		// new spelling may require a re-sort.
		HTREEITEM parent = ctlTree.GetParentItem(selectedNode);
		ctlTree.SortChildren(parent);
		
		// Iterate over the CList and change any node with the old spelling.
		CTreeDoc * pDoc = GetDocument();
		POSITION current, pos = pDoc->m_AnimalList.GetHeadPosition();
		while (NULL != pos)
		{
			// Since GetNext advances its POSITION argument, save it.
			current = pos;

			// Grab the current object.
			CAnimalInfo & rAnimal2 = pDoc->m_AnimalList.GetNext(pos);

			// If its type is that same as the selected node,
			// change the spelling.
			if (rAnimal2.m_type == AnimalType)
				pDoc->m_AnimalList.GetAt(current).m_type = dlg.m_type;
		}
		pDoc->SetModifiedFlag();
	}
}

void CMyTreeView::ModifyAnimal(const HTREEITEM selectedNode, const DWORD itemData)
{
	CTreeDoc * pDoc = GetDocument();

	// Obtain, from the document's Clist, the selected item.
	// The node in the tree contains that object's POSITION in the CList.
	CAnimalInfo & rAnimal = pDoc->m_AnimalList.GetAt((POSITION)itemData);

	// Create the modifying dialog box and initialize it.
	CModifyDlg dlg;
	dlg.m_animal = rAnimal.m_animal;
	dlg.m_weight = rAnimal.m_weight;

	// If user chooses OK, modify object in the CList, and
	// modify the object in the tree view.
	if (IDOK == dlg.DoModal())
	{
		rAnimal.m_animal = dlg.m_animal;
		rAnimal.m_weight = dlg.m_weight;

		// Since the CList is not const, GetAt() can be used as an lvalue.
		pDoc->m_AnimalList.GetAt((POSITION)itemData) = rAnimal;
		pDoc->SetModifiedFlag();

		// Since the tree doesn't store the weight, there's only
		// one thing to update in the tree.
		CTreeCtrl & ctlTree = GetTreeCtrl();
		ctlTree.SetItemText(selectedNode, rAnimal.m_animal);

		// The selected node will refresh itself. However, changing
		// the spelling may require that the parent of the selected
		// node have its children sorted.
		HTREEITEM parent = ctlTree.GetParentItem(selectedNode);
		ctlTree.SortChildren(parent);

		// The list must be manually refreshed. This is the
		// same line of code used in CTreeView::OnSelchanged.
		pDoc->m_pListView->DisplayAnimalInfo(itemData);
	}
}