数据库->树型结构(TVirtualStringTree篇)

本文介绍如何使用TVirtualStringTree构建高效的树形结构,并展示了具体的单元文件代码。包括定义树节点结构、构建子树的过程及如何在树上显示文本等关键步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.数据库结构与我的上一篇文章数据库->树型结构(TTreeView篇)完全相同

 

2.我的创建TVirtualStringTree树结构的单元文件代码

unit BuildVirtualTreeUnit;
 
interface
 
uses
  DB, ADODB, ComCtrls,Dialogs,VirtualTrees;
 
// 定义树结点对数据库表记录对应的结构体
type
  PNode = ^TNode;
  TNode = record
    FID:integer;    // 记录的ID号
    FCaption:string;
    FBM:TBookMark;  // 定位记录的指针(书签)
end;
 
function BuildTree(DataSet: TADODataSet; TV: TVirtualStringTree; SelfField,SelfName,ParentField:String):boolean;
 
implementation
 
function BuildTree(DataSet: TADODataSet; TV: TVirtualStringTree; SelfField,SelfName,ParentField:String):boolean;
  { 以下子函数为在表中查找第一个PNode=AIndex的记录}
  function FindKey(AIndex: integer; FFirst:boolean): boolean;
  begin
    Result:=DataSet.Locate(ParentField,AIndex,[loCaseInsensitive]);
  end;
  { 以下函数在FindKey的基础上找出下一个符合的记录}
  function FindNext(AIndex: integer): boolean;
  begin
    DataSet.Next;
    if DataSet.Eof then
      Result:=false
    else
      Result:=DataSet.FieldValues[ParentField]=AIndex;
    if not Result then DataSet.Prior;
  end;
  { 以下函数据构造当前结点的一级子树 }
  function GetChildNode(index: integer; ANode: PVirtualNode):integer;
  var
    MyNode:PNode;
    Node:PVirtualNode;
  begin
    if FindKey(index,true) then
    begin
      Node:=TV.AddChild(ANode);
      MyNode := TV.GetNodeData(Node)  ;
      with DataSet do
      begin
        MyNode^.FID :=FieldValues[SelfField];
        MyNode^.FBM :=GetBookmark;
        MyNode^.FCaption := FieldValues[SelfName];
      end;

      Result:=1;
      while FindNext(index) do
      begin
       Node:=TV.AddChild(ANode);
        MyNode := TV.GetNodeData(Node);
        with DataSet do
        begin
          MyNode^.FID :=FieldValues[SelfField];
          MyNode^.FBM :=GetBookmark;
          MyNode^.FCaption := FieldValues[SelfName];
        end;

        Result:=Result+1;
      end;
    end
    else
      Result:=0;
  end;
  { 以下函数据以ANode 为结当,构造一棵属于自己的子树}
  procedure BuildMe(AIndex: integer; ANode: PVirtualNode);
  var
    NodeNum:integer;
    Node:PVirtualNode;
    i:integer;
  begin
    NodeNum:=GetChildNode(AIndex,ANode);
    //exit;
    if NodeNum>0 then
    begin
      if ANode=nil then Node:=TV.GetFirst
      else
        Node:=ANode.FirstChild;
      for i:=1 to NodeNum do
      begin
        BuildMe(PNode(TV.GetNodeData(Node))^.FID,Node);
        Node:=TV.GetNext(Node);
      end;
    end;
  end;
  // 组合部份
begin
  if (DataSet=nil) or (DataSet.Active =false) then
    Result:=false
  else if (TV=nil) then
    Result:=false
  else begin
    TV.Clear;
    BuildMe(0,nil);
    Result:=true;
  end;
end;
 
end.

 

 

3.要在TVirtualStringTree上显示文字,需要提供一个回调:

procedure TfrmMain.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);
var
  _pNode:PNode;
begin

  _pNode := Sender.GetNodeData(Node);
  if Assigned(_pNode) then
    CellText := _pNode.FCaption;

end;

 

5.当在TVirtualStringTree上点击时,可以获取当时项对应的数据库记录:

procedure TfrmMain.VSTClick(Sender: TObject);
var
  _pNode:PNode;
begin
  _pNode := VST.GetNodeData(VST.FocusedNode) ;
  //第一种方式
   ShowMessage(_pNode^.FCaption);

 //第二种方式
  DM.dsGroup_.GotoBookmark(_pNode.FBM);
  ShowMessage(DM.dsGroup_.FindField('group_name').AsString);
end;

 

 

4.调用

BuildTree(DM.dsGroup_,VST,'id','group_name','parent_id');

  

注:TVirtualStringTree的功能非常的强大,速度效率绝非TTreeView能比的。自然使用起来就复杂,但是只要掌握了它的原理,就很好理解了.

上传容量有限,含packge和source V5.5.2: (10 Nov 2014) * Various improvements regarding code style * Implemented #471: Added emVisibleDueToExpansion and emSelected to TVTExportMode * Fixed issue #488: XE7 packages should depend on one another and use suffix 21 * Fixed issue #462: Undo r636, make VirtualTreesD require VirtualTreesR again * Fixed issue #489 XE2 compiler switch error V5.5.1: (13 Oct 2014) * Fixed issue #479: The style hooks for the VCL styles are now registered for TVirtualStringTree and TVirtualDrawTree instead of TBaseVirtualTree, which makes it easier to use own style hooks in derived classes. * Partial fix for issue #478: The standard VCL property StyleElemets (public in TControl in RAD Studio XE3 and higher) is now supported and published for TVirtualStringTree and TVirtualDrawTree (XE3 and higher). This means you can define if the font and the backgrounbd color is taken from the VCL style or the control's properties. Leaving out seBorder is not yet working well, more work will be necessary. * Fixed issue #473: Return type of GetUtilityImages should be TCustomImageList * Fix for issue #470: VCL Styles and sorting failure * Added missing inherited to CMMouseEnter() * Fixed issue #468: Redundant code in CreateSystemImageSet() * Fixed issue #482: AutoScale() could cause exception during form load. * Added fix for #466: No parent window if column created in constructor * Fixed issue #446: ScrollIntoView does not work properly after applying patch from issue #339 * Improvements for toAlwaysSelectNode option: Selection of next sibling has been improved in case the currently selected node is being removed. * Added missing begin/end-block in MeasureItemHeight() * Improved fix for issue #438: Now correctly initializing member of property TVTColors.UnfocusedColor * Improved fix for issue #447: DoMeasureItem() was called for Node instead of Child. * Minor improvement in appearance of border lines in HTML export. * Fixed issue #480: Warning when compiling Delphi XE2 packages * Fixed #472: Redundant conditions in TVclStyleScrollBarsHook.WMMouseMove * Fixed #476: Simplify TVTDragImage.WillMove() * Fixed issue #485: unit VirtualTrees does not compile with {$TYPEDADDRESS ON}
<think>嗯,用户问的是Angular的nz-table结构结合虚拟滚动。首先,我得回忆一下NG-ZORRO的组件库,nz-table确实支持结构,而虚拟滚动是为了处理大数据量时的性能优化。那怎么把两者结合起来呢? 首先,结构通常需要数据有children字段,用来嵌套子节点。而虚拟滚动一般是处理大量数据的,通过只渲染可视区域内的元素来减少DOM节点,提升性能。但结构展开后,子节点可能不在可视区域,这时候虚拟滚动会不会有问题?比如,展开一个父节点后,子节点可能被隐藏或者位置计算不正确? 可能需要检查NG-ZORRO的文档,看nz-table是否支持同时使用结构和虚拟滚动。记得之前版本的nz-table可能对形和虚拟滚动的兼容性有问题,但最近的版本或许有改进。用户可能需要确保版本足够新,比如9.x以上? 然后,使用虚拟滚动时,需要设置nzVirtualScroll属性,并且提供nzVirtualItemSize作为每行的高度。结构的数据可能需要扁平化处理,或者在组件内部处理展开后的节点位置。不过,如果nz-table本身支持结构和虚拟滚动,可能数据不需要手动扁平化,组件会自动处理。 另外,结构展开时,虚拟滚动的高度计算可能动态变化,这时候需要通知虚拟滚动组件更新高度。可能需要使用ChangeDetectorRef或者调用组件的refresh方法。 还有,样式方面,虚拟滚动可能需要固定高度的容器,用户需要给nz-table设置合适的高度,比如style="{ height: '400px' }"。同时,确保CSS样式正确,不会导致滚动区域计算错误。 可能还需要注意,展开和折叠节点时,虚拟滚动的正确渲染。比如,当展开一个节点,子节点插入到当前父节点下方,虚拟滚动需要重新计算这些子节点的位置,并确保它们在滚动时正确显示。 最后,可以给用户一个示例代码,展示如何同时使用结构和虚拟滚动。可能需要引入NzTableModule,NzVirtualScrollModule等模块,配置数据结构和必要的属性。同时提醒用户注意版本兼容性,以及处理可能的性能问题。</think>Angular NZ-Table 的结构与虚拟滚动结合使用时,可以高效处理**大规模形数据**的渲染性能问题。以下是分步说明: --- ### 一、基础概念 1. **结构** - 数据需包含层级关系(如 `children` 字段) - 通过 `nzExpand` 控制展开/折叠 - 示例数据结构: ```typescript interface TreeNode { id: string; name: string; children?: TreeNode[]; } ``` 2. **虚拟滚动** - 仅渲染可视区域内容,减少 DOM 节点数量 - 需设置 `nzVirtualScroll` 和 `nzVirtualItemSize`(单行高度) --- ### 二、实现步骤 #### 1. 启用结构 ```html <nz-table #virtualTable nzVirtualScroll [nzData]="treeData" [nzVirtualItemSize]="50" [nzVirtualMaxBufferPx]="200" [nzVirtualMinBufferPx]="100" > <thead> <tr> <th nzWidth="200">Name</th> <th>Action</th> </tr> </thead> <tbody> <ng-container *nzVirtualFor="let data of virtualTable.data"> <tr [nzExpand]="data.expand" (nzExpandChange)="onExpand(data)"> <td>{{ data.name }}</td> <td> <button nz-button (click)="toggleExpand(data)">展开/折叠</button> </td> </tr> <tr *ngIf="data.expand && data.children"> <td colspan="2"> <!-- 递归渲染子节点 --> <nz-table-inner [data]="data.children"></nz-table-inner> </td> </tr> </ng-container> </tbody> </nz-table> ``` #### 2. 扁平化数据处理(关键) 虚拟滚动需要**线性数据**,但结构是嵌套的。需预先转换: ```typescript flattenData(treeData: TreeNode[]): TreeNode[] { const result: TreeNode[] = []; const flatten = (nodes: TreeNode[]) => { nodes.forEach(node => { result.push(node); if (node.expand && node.children) { flatten(node.children); } }); }; flatten(treeData); return result; } ``` #### 3. 动态更新展开状态 ```typescript onExpand(node: TreeNode): void { node.expand = !node.expand; this.treeData = [...this.flattenData(this.originalData)]; // 强制刷新虚拟滚动 } ``` --- ### 三、注意事项 1. **版本兼容性** - 确保 NG-ZORRO 版本 ≥ 9.3.0(完整支持虚拟滚动) 2. **性能优化** - 使用 `trackBy` 避免不必要的重渲染 - 控制展开层级深度(避免 DOM 节点爆炸) 3. **样式调整** ```css nz-table { height: 600px; /* 必须设置固定高度 */ } ``` --- ### 四、典问题解决 - **Q:展开子项后滚动错位?** A:更新数据后调用 `virtualTable.cdkVirtualScrollViewport.checkViewportSize()` - **Q:虚拟滚动区域空白?** A:检查 CSS 高度是否正确,确保父容器无 `overflow:hidden` --- 通过结合结构与虚拟滚动,可轻松处理 **10万+节点** 数据,同时保持交互流畅性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值