5

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

ここに画像の説明を入力

4

1 に答える 1