我正在使用 TVirtualStringTree 来存储指向记录的指针。
最初有一个包含记录列表的 TList。
我正在使用 OnInitNode 事件遍历 TList 并将每个记录的数据分配给树的节点。
但是,当检索与 OnNewText 事件处理程序中的节点关联的数据时,返回的指针具有与树中最初存储的地址不同的地址。
此外,我通过调试可以看出,从节点中检索到的指针(指向记录数据)与最初存储在节点中的指针不同。我需要将更改的数据保存到数据库中,并且需要使用更改的数据引用记录。应该像引用指针一样简单,但问题是指针不一样。
我不确定我做错了什么,希望有人能帮我解决这个问题。
提前致谢。
这是我的代码:
数据结构和声明:
TTherapData = record
TherapID: Integer;
TherapName: String[120];
TherapInstr: String[120];
Selected_DB: Byte;
Selected: Byte;
end;
PTherapData = ^TTherapData;
FTherapDataList: TList<PTherapData>;
FTherapDataListAsg_Iter: Integer;
vstRxList_Asg: TVirtualStringTree;
将数据加载到 TList 中,然后加载到树中:
procedure TfmPatient_Conslt.LoadTherapList(const ADBLoad: Boolean = False);
var
TherapData: PTherapData;
d, x: Integer;
begin
datamod.uspLKTHERAP_S.First;
while not datamod.uspLKTHERAP_S.Eof do
begin
New(TherapData);
TherapData^.TherapID := datamod.uspLKTHERAP_SROW_ID.AsInteger;
TherapData^.TherapName := datamod.uspLKTHERAP_SIMPRTHERAP.AsString;
TherapData^.TherapInstr := EmptyStr;
TherapData^.Selected := 0;
TherapData^.Selected_DB := 0;
FTherapDataList.Add(TherapData);
datamod.uspLKTHERAP_S.Next;
end;
datamod.uspCONSLT_RX_S.First;
while not datamod.uspCONSLT_RX_S.Eof do
begin
d := datamod.uspCONSLT_RX_SRX_ID.AsInteger;
TherapData := FTherapDataList[TherapDataList_GetIndexOfID(d)];
TherapData^.TherapInstr := datamod.uspCONSLT_RX_SRX_INSTRUCTION.AsString;
TherapData^.Selected := 1;
TherapData^.Selected_DB := 1;
datamod.uspCONSLT_RX_S.Next;
end;
x := TherapDataList_CountSelectedItems;
FTherapDataListAsg_Iter := 0;
vstRxList_Asg.NodeDataSize := SizeOf(TTherapData);
vstRxList_Asg.RootNodeCount := 0;
vstRxList_Asg.RootNodeCount := x;
end;
procedure TfmPatient_Conslt.vstRxList_AsgInitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
var
TherapData: PTherapData;
begin
TherapData := Sender.GetNodeData(Node);
while (FTherapDataList[FTherapDataListAsg_Iter]^.Selected <> 1) do
Inc(FTherapDataListAsg_Iter);
TherapData^.TherapID := FTherapDataList[FTherapDataListAsg_Iter]^.TherapID;
TherapData^.TherapName := FTherapDataList[FTherapDataListAsg_Iter]^.TherapName;
TherapData^.TherapInstr := FTherapDataList[FTherapDataListAsg_Iter]^.TherapInstr;
{ TherapData := FTherapDataList[FTherapDataListAsg_Iter]; } //
{ TherapData^ := FTherapDataList[FTherapDataListAsg_Iter]^; } //
Inc(FTherapDataListAsg_Iter);
end;
procedure TfmPatient_Conslt.vstRxList_AsgGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType; var CellText: string);
var
TherapData: PTherapData;
begin
TherapData := Sender.GetNodeData(Node);
if Assigned(TherapData) then
if (Column = 0) then
CellText := TherapData^.TherapName
else if (Column = 1) then
CellText := TherapData^.TherapInstr;
end;
procedure TfmPatient_Conslt.vstRxList_AsgEditing(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
var Allowed: Boolean);
begin
Allowed := (Column = 1);
end;
检索数据。我注意到这里的问题:
procedure TfmPatient_Conslt.vstRxList_AsgNewText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
NewText: string);
var
TherapData: PTherapData;
begin
if (Column = 1) then
begin
TherapData := Sender.GetNodeData(Node);
if Assigned(TherapData) then // <---- There is a debug breakpoint here
// and the watch window screen-shot
// is taken here
TherapData^.TherapInstr := NewText;
// Showmessage(Format('%p', [TherapData])); // <---- The pointer value is not the same
// as that originally stored !
end;
end;
这是我将列表数据保存到数据库的地方,也是我需要树来更改原始数据而不是副本的原因:
procedure TfmPatient_Conslt.SaveRxListToDB;
var
TherapData: PTherapData;
begin
for TherapData in FTherapDataList do
begin
if (TherapData^.Selected = 1) and (TherapData^.Selected_DB = 0) then
begin
// Add new entries to DB
// :ROW_ID, :CONSLT_ID, :RX_ID, :RX_INSTRUCTION
datamod.uspCONSLT_RX_I.ParamByName('ROW_ID').AsInteger := 0;
datamod.uspCONSLT_RX_I.ParamByName('CONSLT_ID').AsInteger := FConsultationID;
datamod.uspCONSLT_RX_I.ParamByName('RX_ID').AsInteger := TherapData^.TherapID;
datamod.uspCONSLT_RX_I.ParamByName('RX_INSTRUCTION').AsString := TherapData^.TherapInstr;
datamod.uspCONSLT_RX_I.PrepareSQL(False);
datamod.uspCONSLT_RX_I.ExecProc;
TherapData^.Selected_DB := 1;
end
else if (TherapData^.Selected = 1) and (TherapData^.Selected_DB = 1) then
begin
// Update existing DB entries
// :CONSLT_ID, :RX_ID, :RX_INSTRUCTION
datamod.uspCONSLT_RX_U.ParamByName('CONSLT_ID').AsInteger := FConsultationID;
datamod.uspCONSLT_RX_U.ParamByName('RX_ID').AsInteger := TherapData^.TherapID;
datamod.uspCONSLT_RX_U.ParamByName('RX_INSTRUCTION').AsString := TherapData^.TherapInstr;
datamod.uspCONSLT_RX_U.PrepareSQL(False);
datamod.uspCONSLT_RX_U.ExecProc;
end
else if (TherapData^.Selected = 0) and (TherapData^.Selected_DB = 1) then
begin
// Delete removed entries from DB
// :CONSLT_ID, :RX_ID
datamod.uspCONSLT_RX_D.ParamByName('CONSLT_ID').AsInteger := FConsultationID;
datamod.uspCONSLT_RX_D.ParamByName('RX_ID').AsInteger := TherapData^.TherapID;
datamod.uspCONSLT_RX_D.PrepareSQL(False);
datamod.uspCONSLT_RX_D.ExecProc;
TherapData^.Selected_DB := 0;
end;
end;
end;
这是 Debug->Watch List 窗口的屏幕截图: