レコードへのポインタを格納するために 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 ウィンドウからのスクリーンショットです。