/*
1。数据库表的结构:
(
节点ID
节点父ID(PID)
及其他字段
)
ID,PID的类型无所谓,数字,字符都行,也不需要有规律,
只要保证ID字段为主键即可,比如可以用GUID 来作ID。
支持无限级。
2。TTreeNode的Data指向一个结构,结构内有一个域记录节点的ID及PID,
其他的域根据需要可自己定义。
3。从数据库生成树,这是要好好考虑的,要作到效率高,最重要的是“避免反复查询
数据库或遍历数据集”,最好是查询一次就能生成整棵树。
主要思想是:先生成一棵全是根节点的树,再做调整,这样就避免了先读出子节点,
找不到父节点的尴尬。
*/
struct NODEDATA //节点关联的数据
{
int id;
int pid;
AnsiString name;
AnsiString memo; //其他域省略...
};
void __fastcall FillTree()
{
struct NODEDATA *ndata=NULL;
TStringList *ss=NULL;
TTreeNode *aNode=NULL;
TTreeNode *bNode=NULL;
TTreeNode *pNode=NULL;
Query1->Close();
Query1->SQL->Text="select id,pid,name,memo from tree_tab";
Query1->SQL->Open();
try
{
ss=new TStringList();
TreeView->Items->BeginUpdate();//禁止刷新,提高速度
//遍历记录集
for(Query1->First(); !Query1->Eof; Query1->Next())
{
ndata=new NodeData();
ndata->id = Query1->FieldByName("id")->AsInteger;
ndata->pid = Query1->FieldByName("id")->AsInteger;
ndata->name = Query1->FieldByName("name")->AsString;
ndata->memo = Query1->FieldByName("memo")->AsString;
//生成一个根节点加入TreeView
aNode=TreeView1->Items->AddObject(NULL,ndata->name,ndata);
//记录id-TreeNode对应关系,便于下面查找
ss->AddObject(AnsiString(ndata->id),aNode);
}
Query1->Close();
ndata=NULL;
//下面是关键!!
//调整树,根据节点的pid,把节点移到相应的TreeNode下
int idx;
for(aNode=TreeView1->Items->GetFirstNode(); aNode!=NULL ;)
{
ndata = (NODEDATA*)(aNode->Data);
if(-1==(idx=ss->IndexOf(AnsiString(ndata->pid))))
{
aNode=aNode->getNextSibling();
continue;
}
else
{
pNode = (TTreeNode*)(ss->Objects[idx]);
bNode=aNode;
aNode=aNode->getNextSibling();
bNode->MoveTo(pNode,naAddChild);
}
}
}
__finally
{
delete ss; ss=NULL;
Query1->Close();
TreeView->Items->EndUpdate();
}
}