classtreectrl.cpp

来自「深入浅出Visual C++入门进阶与应用实例 随书光盘 作者 何志丹」· C++ 代码 · 共 272 行

CPP
272
字号
// ClassTreeCtrl.cpp : implementation file
//


#include "ClassTreeCtrl.h"
#include "stdafx.h"
#include "Resource.h"
#include "ModifyClassTreeNode.h"

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

/////////////////////////////////////////////////////////////////////////////
// CClassTreeCtrl

CClassTreeCtrl::CClassTreeCtrl()
{
	m_bReadOnly = false;
	m_pMainData = NULL;
	m_pWndAcceptMessage = NULL ;
}

CClassTreeCtrl::~CClassTreeCtrl()
{

}


BEGIN_MESSAGE_MAP(CClassTreeCtrl, CTreeCtrl)
	//{{AFX_MSG_MAP(CClassTreeCtrl)
	ON_NOTIFY_REFLECT(NM_RCLICK, OnRclick)
	ON_COMMAND(ID_ADDNODE, OnAddnode)
	ON_COMMAND(ID_DELETE_NODE, OnDeleteNode)
	ON_COMMAND(ID_MODIFY_NODE, OnModifyNode)
	ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnSelchanged)
	ON_WM_CREATE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CClassTreeCtrl message handlers

//根据数据分成子树
bool CClassTreeCtrl::InitTree(HTREEITEM hParentItem, CClassTreeNodeData * pTreeNodeData)
{
	if(NULL == pTreeNodeData)
		return false;

	HTREEITEM hItem = InsertItem(pTreeNodeData->m_strText,hParentItem);
	SetItemData(hItem,(DWORD)pTreeNodeData->m_nID);

	//递归分成子树
	for(int i = 0 ; i < pTreeNodeData->m_pSubNode.GetSize() ; i++ )
	{
		CClassTreeNodeData * pSubTreeNode = pTreeNodeData->m_pSubNode[i] ;
		if(NULL == pSubTreeNode)
		{
			ASSERT(false);
			continue;
		}
		InitTree(hItem,pSubTreeNode);
	}
	
	return true;
}

//根据关联数据分成树
bool CClassTreeCtrl::InitTree()
{
	if(!InitTree(TVI_ROOT,&m_pMainData->m_ClassTreeRoot))
		return false ;
	
	if(NULL != m_pMainData)
	{
		CClassTreeNodeData * pCurTreeNodeData = m_pMainData->GetCurTreeNode() ;
		if(NULL != pCurTreeNodeData )
		{
			HTREEITEM hSelectItem = GetItemByID(GetRootItem(),pCurTreeNodeData->m_nID );
			SelectItem(hSelectItem);
		}	
	}

	return true ;
}
void CClassTreeCtrl::OnRclick(NMHDR* pNMHDR, LRESULT* pResult) 
{
	if(m_bReadOnly)//如果为只读不能弹出菜单
		return ;

	CPoint pt(0, 0);
	::GetCursorPos(&pt);
	ScreenToClient (&pt);
	UINT nFlags;
	HTREEITEM hNewSel = HitTest(pt, &nFlags);//右键击中节点
	if(NULL == hNewSel)
		return ;	

	//选中此节点
	SelectItem(hNewSel);
	
	CMenu menu;
	HINSTANCE hOldInstance = AfxGetResourceHandle();
	AfxSetResourceHandle(g_hInstance);
	menu.LoadMenu(IDR_RBUTTONMENU);	
	AfxSetResourceHandle(hOldInstance);
	CMenu * pMenu = menu.GetSubMenu(0);
	if(NULL == GetParentItem(hNewSel))
	{//根节点不能删除
		pMenu->DeleteMenu(ID_DELETE_NODE,MF_BYCOMMAND);
	}
	ClientToScreen(&pt);
	pMenu->TrackPopupMenu(TPM_CENTERALIGN| TPM_RIGHTBUTTON,pt.x,pt.y,this);

	*pResult = 0;
}

void CClassTreeCtrl::OnAddnode() 
{
	HTREEITEM hItem = GetSelectedItem();
	if(NULL == hItem)
		return ;//此限制有必要吗?

	//让用户输入相关信息
	int nParentID = GetItemData(hItem);
	CString strText = "新节点";
	CString strDir  = "";	
	CModifyClassTreeNodeDlg dlg;
	dlg.SetMainData(m_pMainData);
	do
	{
		if(!dlg.GetNewTreeNode(strText,strDir,nParentID))
			return ;
		CString strMess ;
		if(m_pMainData->CanAddTreeNode(strText,nParentID,strDir,strMess))
			break;
		else
			AfxMessageBox(strMess);	//非法数据重新输入	
	}while(true);
	
	if(NULL == m_pMainData)
	{
		ASSERT(false);
		return ;
	}
	int nID ;
	if(!m_pMainData->AddTreeNode(strText,nParentID,strDir,nID))
		return ;//刷新内存及数据库中的内容
	
	//更新树控件的内容
	hItem = GetItemByID(GetRootItem(),nParentID);//当前节点不一定是新节点的父节点
	hItem = InsertItem(strText,hItem);
	SetItemData(hItem,nID);
	SelectItem(hItem);
}

void CClassTreeCtrl::OnDeleteNode() 
{
	HTREEITEM hItem = GetSelectedItem();
	if(NULL == hItem)
		return ;
	
	int nID = GetItemData(hItem);
	if(NULL == m_pMainData)
	{
		ASSERT(false);
		return ;
	}
	if(!m_pMainData->DeleteTreeNode(nID))//从内存及数据库中删除数据
		return  ;
	
	DeleteItem(hItem);//删除树迭件的节点
}


void CClassTreeCtrl::OnModifyNode() 
{
	HTREEITEM hItem = GetSelectedItem();//选中节点
	if(NULL == hItem)
		return ;	
	int nID = GetItemData(hItem);
	HTREEITEM hParentItem = GetParentItem(hItem);//选中节点的父节点
	if(NULL == hParentItem)
		return ;
	int nParentID = GetItemData(hParentItem);
	CString strText = GetItemText(hItem);//当前节点的内容
	CClassTreeNodeData* pTreeNode = m_pMainData->GetTreeNodeByID(nID);
	ASSERT(NULL != pTreeNode);
	CString strDir  = pTreeNode->m_strDirName;
	//让用户输入相关信息
	CModifyClassTreeNodeDlg dlg;
	dlg.SetMainData(m_pMainData);
	do
	{
		if(!dlg.GetNewTreeNode(strText,strDir,nParentID))
			return ;
		CString strMess ;
		if(m_pMainData->CanEditTreeNode(nID,strText,nParentID,strDir,strMess))
			break;
		else//给用户提示,好让用户重新输入
			AfxMessageBox(strMess);
	}while(true);
	
	if(NULL == m_pMainData)
	{
		ASSERT(false);
		return ;
	}
	if(!m_pMainData->EditTreeNode(nID,strText,strDir,nParentID))
		return ;//更新内存及数据库中的数据

	//更新树迭件的信息(全部删除,重新生成)
	DeleteAllItems();
	InitTree(TVI_ROOT,&m_pMainData->m_ClassTreeRoot);
	hItem = GetItemByID(GetRootItem(),nID);
	SelectItem(hItem);

}

HTREEITEM CClassTreeCtrl::GetItemByID(HTREEITEM hParentID,int nID)
{
	if(NULL == hParentID)
		return NULL;
	int iData = GetItemData(hParentID);
	if(nID == iData)
		return hParentID ;

	//递归
	HTREEITEM hItem = GetChildItem(hParentID);
	while(NULL != hItem)
	{
		HTREEITEM hFindItem = GetItemByID(hItem,nID);
		if(NULL != hFindItem)
			return hFindItem;
		hItem = GetNextSiblingItem(hItem);
	}

	return NULL;
}

void CClassTreeCtrl::PreSubclassWindow() 
{
	//失去焦点的时候,也可清楚的看到那个节点被选中
	ModifyStyle(NULL,TVS_SHOWSELALWAYS);
	
	CTreeCtrl::PreSubclassWindow();
}

CMainData* CClassTreeCtrl::SetMainData(CMainData *pData)
{
	m_pMainData = pData ;
	return m_pMainData ;
}

void CClassTreeCtrl::OnSelchanged(NMHDR* pNMHDR, LRESULT* pResult) 
{	
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	HTREEITEM hNewItem = pNMTreeView->itemNew.hItem ;
	if(NULL == hNewItem)
		return ;

	DWORD uID = GetItemData(hNewItem);
	if(NULL == m_pWndAcceptMessage)
		return ;
	m_pWndAcceptMessage->SendMessage(WM_USER_CLASSTREE_ITEMCHANGED,(WPARAM)uID,NULL);

	*pResult = 0;
}

⌨️ 快捷键说明

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