Recent

Author Topic: [SOLVED] TValueListEditor - Freeing related objects  (Read 1038 times)

egsuh

  • Hero Member
  • *****
  • Posts: 1817
[SOLVED] TValueListEditor - Freeing related objects
« on: August 23, 2022, 12:01:23 pm »
I'm trying to implement TValueListEditor containing objects  Here's the source code of the whole unit.

By pressing btnAdd, a new instance of TTempObj is created, which will be added together with a new row to vle (TValueListEditor), using vle.Strings.AddObject method. By pressing btnAdd several times, multiple rows are created.

And by clicking any row, the content in the RTTIMemo1 changes accordingly --- by OnSelection event --- procedure vleSelection.

If I close application here, it's fine. I do not have to free the objects myself, as vle.Strings.OwnsObjects := True; within FormCreate.  HeapTrac says there are no unallocated memory.


Problem is when I delete any row, by pressing brnDelete. If I delete one row and close the form, then it's fine. But if I select any row after deleting any one row, there occur SIGSEGV error.

That is, following code is not executed after deleting one row.

      TIMemo1.Link.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj; (either in vleSelection procedure or btnDeleteClick procedure)
 
What would be possible reason? Is it not a good idea to use TValueListEditor.Strings.Object?


Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, Grids, ComCtrls,  ValEdit, StdCtrls,  RTTICtrls;
  9.  
  10. type
  11.   TValueListEditor = class(ValEdit.TValueListEditor)
  12.       property Row;   // Redefining Row property as published
  13.   end;
  14.  
  15.   { TTempObj }
  16.  
  17.   TTempObj = class(TStringList)     // Test object that will be added to Strings.
  18.   private
  19.     function getFL: string;
  20.     procedure setFL(AValue:string);
  21.  
  22.   published
  23.     property FirstLine : string read getFL write setFL;
  24.   end;
  25.  
  26.   { TForm1 }
  27.  
  28.   TForm1 = class(TForm)
  29.     btnAdd: TButton;
  30.     brnDelete: TButton;
  31.     Label1: TLabel;
  32.     TIEdit1: TTIEdit;
  33.     TIMemo1: TTIMemo;
  34.     vle: TValueListEditor;
  35.     procedure btnAddClick(Sender: TObject);
  36.     procedure brnDeleteClick(Sender: TObject);
  37.     procedure FormCreate(Sender: TObject);
  38.     procedure vleSelection(Sender: TObject; aCol, aRow: Integer);
  39.   end;
  40.  
  41. var
  42.   Form1: TForm1;
  43.  
  44. implementation
  45.  
  46. {$R *.lfm}
  47.  
  48. var
  49.    c: integer = 0;
  50.  
  51. { TTempObj }
  52.  
  53. function TTempObj.getFL: string;
  54. begin
  55.    if count >= 1
  56.       then Result := Strings[0]
  57.       else Result := 'No item';
  58. end;
  59.  
  60. procedure TTempObj.setFL(AValue: string);
  61. begin
  62.    if Count <= 0 then Append(AValue) else Strings[0] := AValue;
  63. end;
  64.  
  65. { TForm1 }
  66.  
  67. procedure TForm1.FormCreate(Sender: TObject);
  68. begin
  69.    vle.Clear;
  70.    vle.Strings.OwnsObjects:= True;
  71. end;
  72.  
  73. procedure TForm1.vleSelection(Sender: TObject; aCol, aRow: Integer
  74.   );
  75. begin
  76.    TIMemo1.Link.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj;
  77. end;
  78.  
  79. procedure TForm1.btnAddClick(Sender: TObject);
  80. var
  81.    tobj : TTempObj;
  82.    ts: string;
  83. begin
  84.    c += 1;
  85.    tobj := TTempObj.Create;
  86.  
  87.    ts := Format('%d=VLE item %0:d', [c]);
  88.    tobj.FirstLine := 'Content in obj: ' + ts;
  89.  
  90.    vle.Strings.AddObject(ts, tobj);
  91.    TIMemo1.Link.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj;
  92. end;
  93.  
  94. procedure TForm1.brnDeleteClick(Sender: TObject);
  95. begin
  96.    TIMemo1.Link.TIObject := nil;
  97.    vle.DeleteRow(vle.Row);
  98.  
  99.    // TIMemo1.Link.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj;
  100.    // --> Error occurs here
  101. end;
  102.  
  103. end.
« Last Edit: August 24, 2022, 07:03:22 am by egsuh »

egsuh

  • Hero Member
  • *****
  • Posts: 1817
Re: TValueListEditor - Freeing related objects
« Reply #1 on: August 23, 2022, 02:37:17 pm »
I believe this is related with RTTI components, not with TValueListEditor.Strings.Objects.
I modified some codes as following, and confirmed that the object I want is correctly pointed. But error occurs at assigning the object to TTIEdit.Link.TIObject property.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.brnDeleteClick(Sender: TObject);
  2. var
  3.    ti: integer;
  4.    tobj: TTempObj;
  5. begin
  6.    TIEdit2.Link.TIObject := nil;
  7.    vle.DeleteRow(vle.Row);
  8.  
  9.    ti := vle.Row-1;
  10.    tobj := vle.Strings.Objects[ti] as TTempObj; // here, tobj.FirstLine is retrived correctly.
  11.  
  12.    TIEdit2.Link.TIObject := tobj;    // --> Error occurs here
  13. end;
  14.  

egsuh

  • Hero Member
  • *****
  • Posts: 1817
Re: TValueListEditor - Freeing related objects
« Reply #2 on: August 23, 2022, 02:53:02 pm »
I solved this issue by using TTIPropertyGrid instead of TTIMemo or TTIEdit, etc.  TTIPropertyGrid has property TIObject directly, while TTIMemo or TTIEdit, etc. have property of Link.TIObject. Not sure whether this is related.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.brnDeleteClick(Sender: TObject);
  2. begin
  3.    TIPropertyGrid1.TIObject := nil;
  4.    vle.DeleteRow(vle.Row);
  5.    TIPropertyGrid1.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj;
  6. end;
  7.  

egsuh

  • Hero Member
  • *****
  • Posts: 1817
Re: TValueListEditor - Freeing related objects
« Reply #3 on: August 24, 2022, 07:02:59 am »
I think I found the reason. Even though I set tiEdit2.Link.TIObjects := nil, still the TTIEdit try to do something with (old) nilled object at

   tiEdit2.Link.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj;

So I changed the code in the following order (it frees old object after assigning new object to TIObject), and there is no problem.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.brnDeleteClick(Sender: TObject);
  2. var
  3.    tobj: TTempObj;
  4. begin
  5.    // vle.Strings.OwnsObjects is set to False.
  6.  
  7.    // tiEdit2.Link.TIObject :=  nil;   // <-- removed this.
  8.    tobj := vle.Strings.Objects[vle.Row - 1] as TTempObj;
  9.    vle.DeleteRow(vle.Row);
  10.    tiEdit2.Link.TIObject := vle.Strings.Objects[vle.Row-1] as TTempObj;  // <-- would occur errors here
  11.    if not vle.Strings.OwnsObjects then tobj.Free;
  12. end;
  13.  

Well, it is clear now, but this error happens in my experience. Isn't it possible to do nothing with "Nil" object?
« Last Edit: August 24, 2022, 07:04:58 am by egsuh »

 

TinyPortal © 2005-2018