Recent

Author Topic: Error when closing Project  (Read 413 times)

Possum

  • Jr. Member
  • **
  • Posts: 69
    • uDoPage
Error when closing Project
« on: December 08, 2019, 11:40:11 pm »
I'm trying to add text to a Treeview node so when I click the node text will show up in a memo..

If you know better way please let me know...



I get the error shown below when I close my project..

I am trying to place add text objects to a treeview. But when I close the project I get the below error.

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
  9.   StdCtrls;
  10.  
  11.  
  12. type
  13.     noteob = class
  14.        strs : WideString;
  15.       constructor Create;
  16.       destructor Destroy; override;
  17.     end;
  18.  
  19. type
  20.  
  21.   { TForm1 }
  22.  
  23.   TForm1 = class(TForm)
  24.     Button1: TButton;
  25.     Button2: TButton;
  26.     Button3: TButton;
  27.     Button4: TButton;
  28.     Memo1: TMemo;
  29.     TreeView1: TTreeView;
  30.     procedure Button1Click(Sender: TObject);
  31.     procedure Button2Click(Sender: TObject);
  32.     procedure Button3Click(Sender: TObject);
  33.     procedure Button4Click(Sender: TObject);
  34.     procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
  35.     procedure TreeView1Changing(Sender: TObject; Node: TTreeNode;
  36.       var AllowChange: Boolean);
  37.   private
  38.     { private declarations }
  39.      procedure AddNode( LastNode : TTreeNode; nodelevel : integer; lbl : string; note : noteob );
  40.      function ReadChars( numchars : integer; fs : TFileStream ) : string;
  41.      procedure DoLoad( fn : string );
  42.      procedure DoSave( fn : string );
  43.   public
  44.     { public declarations }
  45.   end;
  46.  
  47. var
  48.   Form1: TForm1;
  49.  
  50. implementation
  51.  
  52. {$R *.lfm}
  53.  
  54. constructor noteob.Create;
  55. begin
  56.   inherited Create;
  57.   // := TStringList.Create;
  58. end;
  59.  
  60. destructor noteob.Destroy;
  61. begin
  62.  // strs.Free;
  63.   inherited Destroy;
  64. end;
  65.  
  66.  
  67.  
  68. { TForm1 }
  69.  
  70.  
  71. procedure TForm1.AddNode( LastNode : TTreeNode; nodelevel : integer; lbl : string; note : noteob );
  72. begin
  73.    if (TreeView1.Items.Count = 0) then
  74.     {   NewNode := } TreeView1.Items.AddChildObject(nil, lbl, note)
  75.    else if (nodelevel > LastNode.level) then
  76.       { NewNode:= } TreeView1.Items.AddChildObject(LastNode, lbl, note)
  77.    else
  78.    begin // if this node is 'outdented' (it has a lower nodelevel than the
  79.          // node above it) find the first existing node at its nodelevel
  80.          // and add the NewNode to it.
  81.     while nodelevel < LastNode.level  do
  82.             LastNode := LastNode.Parent;
  83.  
  84.       { NewNode := } TreeView1.Items.AddObject(LastNode, lbl, note);
  85.    end;
  86. end;
  87.  
  88.  
  89. function TForm1.ReadChars( numchars : integer; fs : TFileStream ) : string;
  90. var
  91.    i : integer;
  92.    c : char;
  93.    s : string;
  94. begin
  95.    for i := 1 to numchars do
  96.    begin
  97.        fs.ReadBuffer(c,sizeof(c));
  98.        s := s + c;
  99.    end;
  100.    result := s;
  101. end;
  102.  
  103. procedure TForm1.DoLoad( fn : string );
  104. // File Open
  105. var
  106.    fs : TFileStream;
  107.    i, slen, NumOfNodes,  nodelevel : integer;
  108.    note : noteob;
  109.    lbl : String[255];
  110.    s : string;
  111.   LastNode : TTreeNode;
  112. begin
  113.   LastNode := nil;
  114.   fs := TFileStream.Create( fn, fmOpenRead );
  115.   TreeView1.Items.Clear;
  116.   TreeView1.Repaint;
  117.  
  118.   try // ...finally
  119.     try  // ...except
  120.        // READ: Number of Nodes
  121.        fs.ReadBuffer(NumOfNodes, sizeof(NumOfNodes));
  122.        for i := 0 to NumOfNodes-1 do
  123.        begin
  124.           // READ: Node Label
  125.          fs.ReadBuffer(lbl,sizeof(lbl));
  126.          // READ: Node level
  127.            fs.ReadBuffer(nodelevel, sizeof(nodelevel));
  128.           // READ: Length of String data
  129.          fs.ReadBuffer( slen, sizeof( slen ) );
  130.          s := '';
  131.           // READ: and Construct String S from them
  132.          s := ReadChars( slen, fs ) ;
  133.          // CREATE noteob, assign String S to its text field
  134.          note := noteob.create;
  135.          note.strs := s;
  136.          AddNode( LastNode, nodelevel, lbl, note );
  137.          LastNode := TreeView1.Items[TreeView1.Items.Count-1];
  138.          Treeview1.FullExpand;
  139.          memo1.Text := noteob(Treeview1.Items[0].Data).strs;
  140.        end;
  141.      except on E:Exception do
  142.         ShowMessage( ' Couldn''t load from stream: ' + E.message );
  143.      end;
  144.   finally
  145.      fs.Free;
  146.   end;
  147.   Caption := ExtractFileName(fn);
  148. end;
  149.  
  150.  
  151.  
  152. procedure TForm1.DoSave( fn : string );
  153. var
  154.    fs : TFileStream;
  155.    lbl : string[255];
  156.    s : string;
  157.    i, stri, slen, NumOfNodes, nodelevel : integer;
  158. begin
  159.    fs := TFileStream.Create( fn, fmCreate );
  160.    try // ...finally
  161.      try // ...except
  162.          // WRITE: Num of nodes in TreeView
  163.         NumOfNodes := TreeView1.Items.Count;
  164.         fs.WriteBuffer(NumOfNodes, sizeof(NumOfNodes));
  165.          // WRITE: the labels and data of the nodes
  166.         for i := 0 to TreeView1.Items.Count-1 do
  167.         begin
  168.             // WRITE: node label
  169.             lbl := TreeView1.Items[i].Text; //!! NEED to supply LEVEL too
  170.             fs.WriteBuffer(lbl,sizeof(lbl));
  171.  
  172.             // WRITE: Node level
  173.              nodelevel := TreeView1.Items[i].Level;
  174.              fs.WriteBuffer(nodelevel, sizeof(nodelevel));
  175.  
  176.             // assign txt data to String S
  177.             s := noteob(TreeView1.Items[i].Data).strs;
  178.             slen := length(s);
  179.             // WRITE: Length of String S
  180.             fs.WriteBuffer(slen, sizeof(slen));
  181.             // WRITE: String S one char at a time.
  182.  
  183.             for stri := 1 to slen do
  184.                fs.WriteBuffer( s[stri], sizeof( char ) );
  185.         end;
  186.       except on Exception do
  187.         ShowMessage( 'Stream could not be written! ' );
  188.       end;
  189.    finally
  190.       fs.free;
  191.    end;
  192. end;
  193.  
  194.  
  195. procedure TForm1.Button1Click(Sender: TObject);
  196.   var
  197.      Node : TTreeNode;
  198.      note : noteob;
  199.   begin
  200.      note := noteob.create;
  201.      Node := TreeView1.Items.AddObject(TreeView1.Selected, 'NewItem', note);
  202.      Node.Selected := true;
  203.      Node.EditText;
  204.  
  205.   end;
  206.  
  207. procedure TForm1.Button2Click(Sender: TObject);
  208. begin
  209.    DoSave('zz.txt');
  210. end;
  211.  
  212. procedure TForm1.Button3Click(Sender: TObject);
  213. begin
  214.   DoLoad('zz.txt');
  215. end;
  216.  
  217. procedure TForm1.Button4Click(Sender: TObject);
  218. Var
  219. I : integer;
  220. begin
  221.      for i := 0 to treeview1.Items.Count - 1 do
  222.          noteob(TreeView1.Items[i].Data).free;
  223.  
  224. end;
  225.  
  226. procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
  227. begin
  228.    if Treeview1.Selected <> nil then
  229.           memo1.Text := noteob(Treeview1.Selected.Data).strs;
  230. end;
  231.  
  232. procedure TForm1.TreeView1Changing(Sender: TObject; Node: TTreeNode;
  233.   var AllowChange: Boolean);
  234. begin
  235. if Treeview1.Selected <> nil then
  236.      Begin
  237.      If memo1.Modified = True then
  238.            noteob(Treeview1.Selected.Data).strs := memo1.Text;
  239.      End;
  240. end;
  241.  
  242.  
  243. end.
  244.  
  245.  

I know if I run this code the error will happen when I close the app.

Code: Pascal  [Select][+][-]
  1. procedure TForm1.TreeView1Changing(Sender: TObject; Node: TTreeNode;
  2.   var AllowChange: Boolean);
  3. begin
  4. if Treeview1.Selected <> nil then
  5.      Begin
  6.      If memo1.Modified = True then
  7.            noteob(Treeview1.Selected.Data).strs := memo1.Text;
  8.      End;
  9. end;
  10.  
« Last Edit: December 09, 2019, 12:16:59 am by Possum »

winni

  • Hero Member
  • *****
  • Posts: 1806
Re: Errot
« Reply #1 on: December 08, 2019, 11:44:43 pm »
Hi!

So there must be somewhere some bad code:

* look in the procedure FormOnClose
* look in the finalization section of your units - all units

Without code it is hard to say - there can be other problems.

Winni

jamie

  • Hero Member
  • *****
  • Posts: 3532
Re: Error when closing Project
« Reply #2 on: December 09, 2019, 02:13:57 am »
I would say that maybe the Managed system is losing track of the strings...

 Could it be when freeing the nodes the managed string is not getting free'd properly ..

 I would try first to not set the memo.txt to anything , in other words, don't assign the text to any nodes... Compile, run and exit, see if you get the error..

 you need to experiment a bit here.
The only true wisdom is knowing you know nothing

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 6616
  • Debugger - SynEdit - and more
    • wiki
Re: Error when closing Project
« Reply #3 on: December 09, 2019, 02:40:56 am »
Well for starters... and for testing: before you access data, check it is of the desired type.
Code: Pascal  [Select][+][-]
  1. assert(TObject(some_node_or_selected.Data) is noteob);

Button4Click frees them all. So any access thereafter, should crash (probably immediately....

Also, why WideString? TMeme.Text is AnsiString. Just needless conversion of the string?
I know, its temp, the code tells you want a TStringList.

Btw, do yourself a favour: TNoteOb
As you read existing names in Pascal, you will get used to it, and find it helpful.


Also, if you run the project from the IDE, then you should be running in the debugger.
After the crash, the debugger should be able to show you some info. Check the stack window.

Possum

  • Jr. Member
  • **
  • Posts: 69
    • uDoPage
Re: Error when closing Project
« Reply #4 on: December 09, 2019, 10:10:47 pm »
Solved

When Closing the form the treeview changing event fired.

Causing

Code: Pascal  [Select][+][-]
  1.   PItemRecord(Treeview1.Selected.Data)^.Text := Memo1.text;

This would cause the Error.  So I fixed it with a boolean

Code: Pascal  [Select][+][-]
  1.   if not Closing then
  2.            noteob(Treeview1.Selected.Data).strs := memo1.Text;

The Closing Boolean is set to true in the onClose even of the form.

This is a work around

Cheers..
« Last Edit: December 10, 2019, 04:29:49 am by Possum »

 

TinyPortal © 2005-2018