Chinaunix首页 | 论坛 | 博客
  • 博客访问: 368495
  • 博文数量: 715
  • 博客积分: 40000
  • 博客等级: 大将
  • 技术积分: 5005
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 14:46
文章分类

全部博文(715)

文章存档

2011年(1)

2008年(714)

我的朋友

分类:

2008-10-13 16:38:14

按数据库记录构建树控件
作者:



代码运行效果图如下:


简介:
将树中的每一个项目作为数据库中的一条记录(ACCESS2000),将程序启动时,对数据库进行读操作;创建树的各个项目时,是对数据库进行读操作,每次的读取,都是在可是查寻符合条件的记录,并将其一一添加到树中!

实现方法:
准备:
使用ACCESS2000,创建一个数据库,名字为City.mdb(我们将制作一个关于省与市的树,特别适合通讯录);
在数据库中创建一表,表名为TreeItem,字段内容与类型如下图:



ID: 索引号码(可有,可无)
Name: 项目名称(必须)
ParentItem: 父项名称(必须)
SecNum: 电话区号(可有,可无)

输入一些原始数据.数据库已经准备好,那我们就进行实地的编程阶段.
程序实现:
创建一个基于对话框的工程---TreeData

一.ADO的引入和初始化

由于在程序中,我使用了ADO来连接和操作数据库,所以要进行以下操作:
1.在Stdafx.h中添加引作ADO的代码:
//--------------------------------------------
#import "c:\program files\common files\system\ado\msado15.dll" no_namespace rename("EOF","adoEOF")
//--------------------------------------------
2.在TreeData.h中声明两个私有变量:
public: 
	_ConnectionPtr m_pTreeConn;//连接创建
private:
	CString TreeConnString;//连接字符串
3.在CTreeDataApp的构造函数CTreeDataApp中添加如下代码:
//-------------------------------------------
m_TreeConnString=_T("Provider=Microsoft.Jet.OLEDB.4.0;")
_T("Data Source=DataBase\\City.mdb;");
//-------------------------------------------
4.在CTreeDataApp的初始化函数中添加如下代码:
//-------COM初始化--------------------------------
AfxOleInit();
/******************连接通讯录数据库********************/
HRESULT hRes;
try
{
	hRes=m_pTreeConn.CreateInstance(_T("ADODB.Connection"));
	m_pTreeConn->ConnectionTimeout = 8;
	//连接ACCESS2000
	hRes=m_pTreeConn->Open(_bstr_t((LPCTSTR) m_strTelDataSource),
		_T(""),_T(""),adModeUnknown);
}
catch(_com_error e)///捕捉异常
{
	CString errormessage;
	errormessage.Format(_T("连接TelBook.mdb数据库失败!\r\n错误信息:%s"),e.ErrorMessage());
	AfxMessageBox(errormessage);///显示错误信息
	return FALSE;
}
二.Recordset的创建:

1.在CTreeDataDlg.h中声明变量:
//------------------------------------------
private:
	HRESULT hRes;
	_RecordsetPtr m_TreeRecordset; //用于创建一个查询记录集
//------------------------------------------
public:
	CImageList m_TreeBootImage; //Tree的图标
2. (1).在对话框窗口中添加一个TreeCtrl控件,一个ComboExe控件; TreeCtrl的风格设置如下图;


(2).导入一个BMP文件,做为Tree的项目图标(TreeBoot.bmp),将其ID设置为IDB_TreeBootImage;

(3).在向导中,为三个控件添加连接对象.



3.在CTreeDataDlg中右击,选择添加一个成员函数TreeAddTree(bool Ta):
void CBusinessView::TreeAddTree(bool Ta)
{
	//--------------Tree控件操作变量------------------------
	TVINSERTSTRUCT tvInsert;
	HTREEITEM hParent;
	//------------------------------------------------
	tvInsert.hParent = NULL;
	tvInsert.hInsertAfter = NULL;
	tvInsert.item.mask = TVIF_TEXT;
	//-----------------创建图象标签----------------------------
	m_TreeBootImage.Create ( IDB_TreeBootImage,20,1,ILC_COLOR8);
	m_ctrlTree.SetImageList ( &m_TreeBootImage,TVSIL_NORMAL );
	m_ctrlTree.SetTextColor (RGB(7,145,13));
	//--------添加根目录----------------------------------------
	tvInsert.item.pszText = _T("中国");
	hParent = m_ctrlTree.InsertItem(&tvInsert);
	//---------------添加子目录-------------------------------
	TreeAddSubTree("中国","1",hParent);
	//---------------------展开Tree目录------------------
	m_ctrlTree.Expand(hParent,TVE_EXPAND);
}
4.添加一个COM变量到CString变量的转换函数:
//-----------------实现了VARIANT类型的值转换成CString类型--------------
CString CBusinessView::VariantToCString(VARIANT var)
{
	CString strValue;
	_variant_t var_t;
	_bstr_t bst_t;
	time_t cur_time;
	CTime time_value;
	COleCurrency var_currency;
	switch(var.vt)
	{
		case VT_EMPTY:strValue=_T("");break;
		case VT_UI1:strValue.Format ("%d",var.bVal);break;
		case VT_I2:strValue.Format ("%d",var.iVal );break;
		case VT_I4:strValue.Format ("%d",var.lVal);break;
		case VT_R4:strValue.Format ("%f",var.fltVal);break;
		case VT_R8:strValue.Format ("%f",var.dblVal);break;
		case VT_CY:
			var_currency=var;
			strValue=var_currency.Format(0);
			break;
		case VT_BSTR:
			var_t=var;
			bst_t=var_t;
			strValue.Format ("%s",(const char*)bst_t);
			break;
		case VT_NULL: strValue=_T(""); break;
		case VT_DATE:
			cur_time=var.date;
			time_value=cur_time;
			strValue=time_value.Format("%A,%B%d,%Y");
			break;
		case VT_BOOL: strValue.Format ("%d",var.boolVal ); break;
		default: strValue=_T(""); break;
	}
	return strValue;
}
5.同样的方法添加另外一个成员函数TreeAddSubTree(CString ParTree,CString strChildTree,HTREEITEM hPartItem):
此成员函数是一个递归函数.
if (strChildTree!="0")
{
	//----------------使用到的变量进行定义----------
	_RecordsetPtr m_pTreeRecordset; //用于创建一个查询记录集
	_variant_t vChild;
	//--------------Tree控件操作变量------------------------
	HTREEITEM hCurrent;
	//----------------------------------------------
	CString strSQL,strCurItem;
	//-----------------------------------------------
	strSQL="SELECT * FROM TreeItem where ParentItem like ''%" ;
	strSQL=strSQL+ParTree+"%''";
	try
	{
		HRESULT hTRes;
		hTRes = m_pTreeRecordset.CreateInstance(_T("ADODB.Recordset"));
		if (SUCCEEDED(hTRes))
		{
			//----------------------------------------------------
			hTRes = m_pTreeRecordset->Open((LPTSTR)strSQL.GetBuffer(130),
			_variant_t((IDispatch *)(((CBusinessApp*)AfxGetApp())->m_pTreeConnection),true),
			adOpenDynamic,adLockPessimistic,adCmdText);
			if(SUCCEEDED(hTRes))
			{
				TRACE(_T("连接成功!\n"));
				//------------------------------------------
				m_pTreeRecordset->MoveFirst();
				if (!(m_pTreeRecordset->adoEOF))
				{

					while(!m_pTreeRecordset->adoEOF)
					{
					hCurrent = m_ctrlTree.InsertItem((LPCTSTR)(_bstr_t)						(m_pTreeRecordset->GetCollect("Name")), hPartItem, NULL);
					//---------------将内容添加到City的Combo控件中------------------
					m_ctrlComboCity.AddString(VariantToCString(m_pTreeRecordset->GetCollect("Name")));
					if (TreeSumRecordCount(VariantToCString						(m_pTreeRecordset->GetCollect("Name")))>0)
					{
						TreeAddSubTree(VariantToCString(m_pTreeRecordset->GetCollect("Name")),
							(VariantToCString(m_pTreeRecordset->GetCollect("Name"))),
							hCurrent);
					}

					if (!(m_pTreeRecordset->adoEOF))
					{
						m_pTreeRecordset->MoveNext();
					}
				} 
			}
			//---------------------------------------
		}
	}
}
catch(_com_error e)///捕捉异常
{
	CString errormessage;
	MessageBox("创建City记录集失败!",ParTree+strChildTree);
}
}
6.添加一个求当前项子项串的成员函数ReturnTreeChilds(CString strCurItem):
此成员函数也是递归函数.
//----------------提取当前所选择项的子项文本所组成的字符串------------------------
CString CTreeDataDlg::ReturnTreeChilds(CString strCurItem)
{
	CString strTreeChildren;//记录子项文本所组成的字符串
	if (TreeSumRecordCount(strCurItem) > 0)
	{
		//--------------------进入递归运算---------------------
		_RecordsetPtr m_pTreeRecordset; //用于创建一个查询记录集
		_variant_t vCur;
		CString strSQL;
		//-----------------------------------------------
		strSQL="SELECT * FROM TreeItem where ParentItem like ''%" ;
		strSQL=strSQL+strCurItem+"%''";
		try
		{
			HRESULT hTRes;
			hTRes = m_pTreeRecordset.CreateInstance(_T("ADODB.Recordset"));
			if (SUCCEEDED(hTRes))
			{
			//----------------------------------------------------
			hTRes = m_pTreeRecordset->Open((LPTSTR)strSQL.GetBuffer(130),
				_variant_t((IDispatch *)(((CTreeDataApp*)AfxGetApp())->m_pTreeConn),true),
				adOpenDynamic,adLockPessimistic,adCmdText);
			if(SUCCEEDED(hTRes))
			{
				TRACE(_T("连接成功!\n"));
				//------------------------------------------
				m_pTreeRecordset->MoveFirst();
				vCur=(m_pTreeRecordset->GetCollect("Name"));
				if (TreeSumRecordCount(VariantToCString(vCur))>=0)
				{
					while(!m_pTreeRecordset->adoEOF)
					{
						vCur=(m_pTreeRecordset->GetCollect("Name"));
						strTreeChildren+=(",''"+VariantToCString(vCur)+"''");
						if (TreeSumRecordCount(VariantToCString(vCur))!=0)
						{
							strTreeChildren+=ReturnTreeChilds(VariantToCString(vCur));
						}
						if (!(m_pTreeRecordset->adoEOF))
						{
							m_pTreeRecordset->MoveNext();
						}
					} 
				}
			//---------------------------------------
			}
		}
	}
	catch(_com_error e)///捕捉异常
	{
		CString errormessage;
		AfxMessageBox("创建ChildTree记录集失败!"+strCurItem);
	}
}
return strTreeChildren;
}
7.处理TreeCtrl控件的点击(OnClick)和改变选择项(SelchangedTree)事件:
void CTreeDataDlg::OnSelchangedTree1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	NM_TREEVIEW* pNMTreeView = (NM_TREEVIEW*)pNMHDR;
	//--------------------------------------------------------
	hTreeCurrent=m_ctrlTree.GetSelectedItem ();
	hTreeParent=m_ctrlTree.GetParentItem(m_ctrlTree.GetSelectedItem ());
	//-------------------树型控件的图标更改---------
	m_ctrlTree.SetItemImage(hTreeCurrent,1,true );
	//---------------------------------------------- 
	TreeCurrent="''"+m_ctrlTree.GetItemText(hTreeCurrent)+"''";
	TreeParent=m_ctrlTree.GetItemText (hTreeParent);
	//---------------------处理ListTree中的相应显示内容--------------
	//-------------提取树中当前项及其子项的内容------
	hTreeCurrent=m_ctrlTree.GetSelectedItem ();
	m_strEdit=TreeCurrent+ReturnTreeChilds(m_ctrlTree.GetItemText(hTreeCurrent));
	UpdateData(false);//子项内容显示到Edit控件中
	//---------------------------------------------------
	*pResult = 0;
}
void CTreeDataDlg::OnClickTree1(NMHDR* pNMHDR, LRESULT* pResult) 
{
	//-------------------树型控件的图标还原---------
	m_ctrlTree.SetItemImage(hTreeCurrent,0,true );
	//----------------------------------------------
	*pResult = 0;
}
三.在BOOL CTreeDataDlg::OnInitDialog()中添加以下代码:
TreeAddTree();
总结:

这个程序主要是在数据库中进行操作,主干是两个递归成员函数;对于递归,让你自己来理解吧!


--------------------next---------------------

写的不错收藏了! ( ddlddy 发表于 2008-8-21 10:23:00)
 
怎么后面的没有跟进了啊 ( haifengcumt 发表于 2008-1-6 22:50:00)
 
我在调试过程中,发现一个问题。希望对感兴趣的人有一点帮助。

SELECT *FROM TREEITEM WHERE PARITEM LIKE '% %'

这条语句不是完全匹配,比如
like 后为 at
private 也会被视为满足条件。最好去掉like 
. ( stray 发表于 2004-3-17 22:11:00)
 
要是使用ODBC应该怎么实现 ( jichunxiang 发表于 2003-8-26 17:10:00)
 
谢谢作者,我刚好要用的这个,太感激了 ( angle_88 发表于 2003-7-8 10:01:00)
 
如果数据库的表多了一个兄弟节点,那递归算法该怎么写呢? ( sunrenliang 发表于 2002-12-28 13:59:00)
 
编译第一次就出错,多写点,把LISTVIEW32也关联进来 ( hww02 发表于 2002-12-12 14:24:00)
 
文章不错,写得很仔细。图文并茂.哪天没事我也写一个。 ( liuc_xxx 发表于 2002-12-5 15:40:00)
 
对我现在的工作帮助很大,谢谢!!!
不过有一个新的需求,您能实现树的drag和drop吗?
比如拖拉'北京'这个结点到word, 然后drop,这时候word中就会出现'北京', 如果节点有子节点,则子节点也会显现到word中.
谢谢!!! ( sunrenliang 发表于 2002-12-4 15:27:00)
 
对我很实用,但我想问一下:如果有与之关联的列表框listctrl怎么办,向资源管理器那样 ( neter 发表于 2002-12-3 8:40:00)
 
.......................................................

--------------------next---------------------

阅读(149) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~