如何使此代码可重复使用

迈克·托雷蒂尼

我有一种为Virtual Treeview构建节点的特定方法(几年前我在这个示例中苦读,直到现在还没有理由更改它)。因为我在大约150种情况下使用几乎相同的代码,所以我想尝试使其重用并减少总体代码行。

我在表单上附加了带有2个按钮和Vritual Treeview的示例的完整代码:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VirtualTrees, Vcl.StdCtrls;

type

  rTreeData = record
    IndexInMyData: integer;
  end;

  tLine = record
    Level:integer;
    Txt:string;
    NodePointer: PVirtualNode;
  end;

  TForm1 = class(TForm)
    Button1: TButton;
    VTV: TVirtualStringTree;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  vArray:array of tLine;

implementation

{$R *.dfm}



procedure TForm1.Button1Click(Sender: TObject);
var
  Node: PVirtualNode;
  Data: ^rTreeData;
  i, j: integer;
begin
  SetLength(vArray,5);
  vArray[0].Level:=0; vArray[0].Txt:='One';
  vArray[1].Level:=1; vArray[1].Txt:='Two';
  vArray[2].Level:=1; vArray[2].Txt:='three';
  vArray[3].Level:=2; vArray[3].Txt:='Four';
  vArray[4].Level:=0; vArray[4].Txt:='Give';

  VTV.BeginUpdate;
  VTV.Clear;
  for i := Low(vArray) to High(vArray) do
  begin
     if i = 0 then
    begin
      Node := VTV.AddChild(nil);
      Data := VTV.GetNodeData(Node);
    end
    else
    begin
      if vArray[i].Level = 0 then
        Node := VTV.AddChild(nil)
      else if vArray[i].Level > vArray[i - 1].Level then
        Node := VTV.AddChild(Node)
      else if vArray[i].Level < vArray[i - 1].Level then
      begin
        Node := Node.Parent;
        for j := 1 to (vArray[i - 1].Level - vArray[i].Level) do
          Node := Node.Parent;
        Node := VTV.AddChild(Node);
      end
      else
      begin
        Node := Node.Parent;
        Node := VTV.AddChild(Node);
      end;

      Data := VTV.GetNodeData(Node);
    end;

    // Create link to your data record into VST node
    Data.IndexInMyData := i;
    vArray[Data.IndexInMyData].NodePointer := Node;
  end;
  VTV.FullExpand;
  VTV.EndUpdate;
end;

function AddNode(vTV: TvirtualStringTree; vI, vLevel, vLevelPrev:integer; vNode:PVirtualNode; var vData:rTreeData):PVirtualNode;
var j:integer;
begin
   if vI = 0 then
    begin
      Result := vTV.AddChild(nil);
      vData := rTreeData(vTV.GetNodeData(Result)^);
    end
    else
    begin
      if vLevel = 0 then  Result := vTV.AddChild(nil)
      else if vLevel > vLevelPrev then  Result := vTV.AddChild(vNode)
      else if vLevel < vLevelPrev then
      begin
        Result := vNode.Parent;
        for j := 1 to (vLevelPrev - vLevel) do
          Result := Result.Parent;
        Result := vTV.AddChild(Result);
      end
      else
      begin
        Result := vNode.Parent;
        Result := vTV.AddChild(Result);
      end;

      vData := rTreeData(vTV.GetNodeData(Result)^);
    end;
    vData.IndexInMyData := vI;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  Node: PVirtualNode;
  Data: ^rTreeData;

  i, j,vLevelPrev: integer;
begin
  SetLength(vArray,5);
  vArray[0].Level:=0; vArray[0].Txt:='One';
  vArray[1].Level:=1; vArray[1].Txt:='Two';
  vArray[2].Level:=1; vArray[2].Txt:='three';
  vArray[3].Level:=2; vArray[3].Txt:='Four';
  vArray[4].Level:=0; vArray[4].Txt:='Give';

  VTV.BeginUpdate;
  VTV.Clear;
  for i := Low(vArray) to High(vArray) do
  begin
    if i = 0 then
      vLevelPrev:=0
    else
      vLevelPrev:=vArray[i-1].Level;

      Node:=AddNode(VTV,i,vArray[i].Level,vLevelPrev,Node,rTreeData(Data^));

//     if i = 0 then
//    begin
//      Node := VTV.AddChild(nil);
//      Data := VTV.GetNodeData(Node);
//    end
//    else
//    begin
//      if vArray[i].Level = 0 then
//        Node := VTV.AddChild(nil)
//      else if vArray[i].Level > vArray[i - 1].Level then
//        Node := VTV.AddChild(Node)
//      else if vArray[i].Level < vArray[i - 1].Level then
//      begin
//        Node := Node.Parent;
//        for j := 1 to (vArray[i - 1].Level - vArray[i].Level) do
//          Node := Node.Parent;
//        Node := VTV.AddChild(Node);
//      end
//      else
//      begin
//        Node := Node.Parent;
//        Node := VTV.AddChild(Node);
//      end;
//
//      Data := VTV.GetNodeData(Node);
//    end;

    // Create link to your data record into VST node
    Data.IndexInMyData := i;
    vArray[Data.IndexInMyData].NodePointer := Node;
  end;
  VTV.FullExpand;
  VTV.EndUpdate;
end;

end.

因此,Button1使用我目前的代码风格来构建节点。确实有效。

Button2试图调用AddNode过程以将AddNode创建为可重复使用的代码。它可以编译,但在行号101上失败:EAccessViolation:

在此处输入图片说明

我认为使用,分配指针和值的方式存在问题……我没有越过这一行,所以我不知道其余代码是否有效。

任何建议如何解决此问题,如何使代码可重复使用?

编辑

如果删除vData参数,效果很好:现在减少了代码:

VTV.BeginUpdate;
  VTV.Clear;
  vLevelPrev:=0
  for i := Low(vArray) to High(vArray) do
  begin
    if i > 0 then vLevelPrev:=vArray[i-1].Level;

    Node:=AddNode(VTV,i,vArray[i].Level,vLevelPrev,Node);

    // Create link to your data record into VST node
    Data := VTV.GetNodeData(Node);
    Data.IndexInMyData := i;
    vArray[Data.IndexInMyData].NodePointer := Node;
  end;
  VTV.FullExpand;
  VTV.EndUpdate;

和AddNode:

function AddNode(vTV: TvirtualStringTree; vI, vLevel, vLevelPrev:integer; vNode:PVirtualNode):PVirtualNode;
var j:integer;
begin
   if vI = 0 then
    begin
      Result := vTV.AddChild(nil);
    end
    else
    begin
      if vLevel = 0 then  Result := vTV.AddChild(nil)
      else if vLevel > vLevelPrev then  Result := vTV.AddChild(vNode)
      else if vLevel < vLevelPrev then
      begin
        Result := vNode.Parent;
        for j := 1 to (vLevelPrev - vLevel) do
          Result := Result.Parent;
        Result := vTV.AddChild(Result);
      end
      else
      begin
        Result := vNode.Parent;
        Result := vTV.AddChild(Result);
      end;

    end;
end;

反正通过在AddNode中处理数据来减少代码?

解决方案:

我将数据作为本地指针放入AddNode中:

function AddNode(vTV: TvirtualStringTree; vI, vLevel, vLevelPrev:integer; vNode:PVirtualNode):PVirtualNode;
var j:integer;
    Data: ^rTreeData;
begin
   if vI = 0 then
      Result := vTV.AddChild(nil)
    else
    begin
      if vLevel = 0 then  Result := vTV.AddChild(nil)
      else if vLevel > vLevelPrev then  Result := vTV.AddChild(vNode)
      else if vLevel < vLevelPrev then
      begin
        Result := vNode.Parent;
        for j := 1 to (vLevelPrev - vLevel) do
          Result := Result.Parent;
        Result := vTV.AddChild(Result);
      end
      else
      begin
        Result := vNode.Parent;
        Result := vTV.AddChild(Result);
      end;
    end;
    Data := VTV.GetNodeData(Result);
    Data.IndexInMyData := vI;
end;

现在,我有了使用AddNode的最终简化代码:

vLevelPrev := 0;
  for i := Low(vArray) to High(vArray) do
  begin
    if i > 0 then
      vLevelPrev := vArray[i - 1].Level;
    Node := AddNode(VTV, i, vArray[i].Level, vLevelPrev, Node);
    vArray[i].NodePointer := Node;
  end;
乌韦·拉贝(Uwe Raabe)

在调用时AddNodeButton2Click指针变量Data仍未初始化,并指向某个任意内存,该内存将被写入内部,AddNode从而导致访问冲突。

我仍然不确定我是否理解,为什么您vData根本需要该参数。使原样vData指向rTreeData记录的本地指针DataButton1Click然后完全删除该参数。Button2Click使用I索引到vArray

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

如何在多个实例中重复使用此代码?

来自分类Dev

如何在SwiftUI中集成函数,以便使用输入字典创建可重复使用的代码

来自分类Dev

可重复使用的模板

来自分类Dev

如何创建可重复使用的Durandal小部件

来自分类Dev

如何在Android中创建可重复使用的活动?

来自分类Dev

如何为可重复使用的Django应用进行迁移?

来自分类Dev

如何创建方法引用可重复使用的可选映射?

来自分类Dev

如何使角度分量可重复使用?(角度2+)

来自分类Dev

如何使动作可重复使用?带有Redux的ReactJS

来自分类Dev

如何编写可重复使用的@property getter / setters?

来自分类Dev

如何为可重复使用的Django应用进行迁移?

来自分类Dev

如何在 DocuSign 中创建可重复使用的信封?

来自分类Dev

如何使倒计时可重复使用对象?

来自分类Dev

如何在Perl脚本中重复使用提示代码

来自分类Dev

Silverstripe 3.2可重复使用的块

来自分类Dev

光滑的可重复使用的InsertAndUpdate特征

来自分类Dev

实现可重复使用的按钮

来自分类Dev

QTP可重复使用的同步功能

来自分类Dev

快速可重复使用的NavigationLink

来自分类Dev

流星可重复使用的组件

来自分类Dev

多个画布,可重复使用的渐变

来自分类Dev

可重复使用的刀片模板

来自分类Dev

自定义可重复使用的动画代码应该放在哪里?

来自分类Dev

Android,可重复使用的工具栏,用于导航-将代码放置在哪里?

来自分类Dev

自定义可重复使用的动画代码应该放在哪里?

来自分类Dev

如何使用此代码清除重复项?

来自分类Dev

子查询,而不必重复使用代码

来自分类Dev

如何重复此代码

来自分类Dev

无法使用可重复使用的单元格。如何优化tableView中的平滑滚动?

Related 相关文章

  1. 1

    如何在多个实例中重复使用此代码?

  2. 2

    如何在SwiftUI中集成函数,以便使用输入字典创建可重复使用的代码

  3. 3

    可重复使用的模板

  4. 4

    如何创建可重复使用的Durandal小部件

  5. 5

    如何在Android中创建可重复使用的活动?

  6. 6

    如何为可重复使用的Django应用进行迁移?

  7. 7

    如何创建方法引用可重复使用的可选映射?

  8. 8

    如何使角度分量可重复使用?(角度2+)

  9. 9

    如何使动作可重复使用?带有Redux的ReactJS

  10. 10

    如何编写可重复使用的@property getter / setters?

  11. 11

    如何为可重复使用的Django应用进行迁移?

  12. 12

    如何在 DocuSign 中创建可重复使用的信封?

  13. 13

    如何使倒计时可重复使用对象?

  14. 14

    如何在Perl脚本中重复使用提示代码

  15. 15

    Silverstripe 3.2可重复使用的块

  16. 16

    光滑的可重复使用的InsertAndUpdate特征

  17. 17

    实现可重复使用的按钮

  18. 18

    QTP可重复使用的同步功能

  19. 19

    快速可重复使用的NavigationLink

  20. 20

    流星可重复使用的组件

  21. 21

    多个画布,可重复使用的渐变

  22. 22

    可重复使用的刀片模板

  23. 23

    自定义可重复使用的动画代码应该放在哪里?

  24. 24

    Android,可重复使用的工具栏,用于导航-将代码放置在哪里?

  25. 25

    自定义可重复使用的动画代码应该放在哪里?

  26. 26

    如何使用此代码清除重复项?

  27. 27

    子查询,而不必重复使用代码

  28. 28

    如何重复此代码

  29. 29

    无法使用可重复使用的单元格。如何优化tableView中的平滑滚动?

热门标签

归档