/* 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(); } }