如何使此代码可重用
How to make this code re-usable
我有一个特定的方法来为 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;
和添加节点:
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 中处理数据来减少代码?
解决方案:
我将 Data 作为本地指针放入 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;
在 Button2Click
中调用 AddNode
时,指针变量 Data
仍未初始化并指向某个任意内存,该内存将被写入 AddNode
领先该访问冲突。
我仍然不确定我是否理解,为什么你需要那个 vData
参数。使 vData
成为指向 rTreeData
记录的本地指针,就像 Button1Click
中的 Data
一样,并完全删除该参数。在 Button2Click
中使用 I
索引到 vArray
.
我有一个特定的方法来为 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;
和添加节点:
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 中处理数据来减少代码?
解决方案:
我将 Data 作为本地指针放入 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;
在 Button2Click
中调用 AddNode
时,指针变量 Data
仍未初始化并指向某个任意内存,该内存将被写入 AddNode
领先该访问冲突。
我仍然不确定我是否理解,为什么你需要那个 vData
参数。使 vData
成为指向 rTreeData
记录的本地指针,就像 Button1Click
中的 Data
一样,并完全删除该参数。在 Button2Click
中使用 I
索引到 vArray
.