Forum > LCL

Crashing TTreeView when setting up a sub-form.

(1/1)

geraldholdsworth:
So, latest problem, which I've been battering my head agains the wall now for 24 hours and can't see a solution.

I've got a TTreeView on a form, and a custom TTreeNode:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---type //We need a custom TTreeNode, as we want to tag on some extra information TMyTreeNode = class(TTreeNode)  private   FParentDir : Integer;   FIsDir     : Boolean;  public   property ParentDir: Integer read FParentDir write FParentDir;//Parent directory reference   property IsDir    : Boolean read FIsDir write FIsDir;        //Is it a directory end;At first I couldn't get it to work in anything but the original TTreeView - I forgot to set the OnCreateNodeClass. OK, got that sorted. But I wanted to re-use the code to populate a TTreeView on another form. This just refuses to work.

Originally, I had the following procedures as part of MainForm, but separated them out (but still in the Unit). The following follows the above type declaration.

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure AddImageToTree(Tree: TTreeView;ImageToUse: TDiscImage);procedure AddDirectoryToTree(CurrDir:TTreeNode;dir:Integer;Tree:TTreeView;                                  ImageToUse:TDiscImage;var highdir:Integer);function AddFileToTree(ParentNode: TTreeNode;importfilename: String;   index: Integer;dir: Boolean;Tree:TTreeView;ImageToUse:TDiscImage): TTreeNode;And the procedures are thus:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{------------------------------------------------------------------------------}//Populate a directory tree with an image{------------------------------------------------------------------------------}procedure AddImageToTree(Tree: TTreeView;ImageToUse: TDiscImage);var //Used as a marker to make sure all directories are displayed. //Some double sided discs have each side as separate discs highdir    : Integer;begin //Clear the tree view, prior to populating it Tree.Items.Clear; //Set the highdir to zero - which will be root to start with highdir:=0; //Then add the directories, if there is at least one if Length(ImageToUse.Disc)>0 then begin  //Start by adding the root (could be more than one root, particularly on  //double sided discs)  repeat   //This will initiate the recursion through the directory structure, per side   AddDirectoryToTree(Tree.Items.Add(nil,ImageToUse.Disc[highdir].Directory),                      highdir,Tree,ImageToUse,highdir);   //Finished on this directory structure, so increase the highdir   inc(highdir);   //and continue until we have everything on the disc. This will, in effect,   //add the second root for double sided discs.  until highdir=Length(ImageToUse.Disc);  //Expand the top level of the tree (but not MMB)  if ImageToUse.FormatNumber>>4<>diMMFS then Tree.TopItem.Expand(False);  //And the root for the other side of the disc  if ImageToUse.DoubleSided then  begin   //First, we need to find it   repeat    inc(highdir);    //If there is one, of course - but it must be a directory   until(highdir>=Tree.Items.Count) or (TMyTreeNode(Tree.Items[highdir-1]).IsDir);   if highdir>Tree.Items.Count then    highdir:=Tree.Items.Count;   //Found? then expand it   if TMyTreeNode(Tree.Items[highdir-1]).IsDir then    Tree.Items[highdir-1].Expand(False);  end; end;end; {------------------------------------------------------------------------------}//Adds a directory to the TreeView - is called recursively to drill down the tree{------------------------------------------------------------------------------}procedure AddDirectoryToTree(CurrDir:TTreeNode;dir:Integer;Tree:TTreeView;                                  ImageToUse:TDiscImage;var highdir:Integer);var entry: Integer; Node: TTreeNode;begin //Make a note of the dir ref, it is the highest if dir>highdir then highdir:=dir; //Set the 'IsDir' flag to true, as this is a directory TMyTreeNode(CurrDir).IsDir:=True; //Iterate though all the entries for entry:=0 to Length(ImageToUse.Disc[dir].Entries)-1 do begin  //Adding new nodes for each one  Node:=AddFileToTree(CurrDir,ImageToUse.Disc[dir].Entries[entry].Filename,                      entry,false,Tree,ImageToUse);  //If it is, indeed, a direcotry, the dir ref will point to the sub-dir  if ImageToUse.Disc[dir].Entries[entry].DirRef>=0 then  //and we'll recursively call ourself to add these entries   AddDirectoryToTree(Node,ImageToUse.Disc[dir].Entries[entry].DirRef,Tree,                      ImageToUse,highdir); end;end; {------------------------------------------------------------------------------}//Add a file or directory to the TTreeView, under ParentNode{------------------------------------------------------------------------------}function AddFileToTree(ParentNode: TTreeNode;importfilename: String;   index: Integer;dir: Boolean;Tree:TTreeView;ImageToUse:TDiscImage): TTreeNode;begin Result:=nil; if(ParentNode=nil)or(index<0)then exit; RemoveTopBit(importfilename); //Now add the entry to the Directory List if ParentNode.HasChildren then  //Insert it before the one specified  if index<ParentNode.Count then   Result:=Tree.Items.Insert(ParentNode.Items[index],importfilename)  else //Unless this is the last one   Result:=Tree.Items.AddChild(ParentNode,importfilename) else  //Is the first child, so just add it  Result:=Tree.Items.AddChildFirst(ParentNode,importfilename); if Result<>nil then begin  if ParentNode.Parent<>nil then //No parent, so will be the root   TMyTreeNode(Result).ParentDir:=ImageToUse.Disc[TMyTreeNode(ParentNode).ParentDir].                                      Entries[ParentNode.Index].DirRef  else   TMyTreeNode(Result).ParentDir:=ParentNode.Index; //But may not be the only root  TMyTreeNode(Result).IsDir:=dir;  Tree.Repaint;  //And update the free space display  if ImageToUse=MainForm.Image then MainForm.UpdateImageInfo; end;end;Remembering about the OnCreateNodeClass event handler, I copied it to the secondary form:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{------------------------------------------------------------------------------}//This just creates our custom TTreeNode{------------------------------------------------------------------------------}procedure TMainForm.DirListCreateNodeClass(Sender: TCustomTreeView;  var NodeClass: TTreeNodeClass);begin  NodeClass:=TMyTreeNode;end;and:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---{------------------------------------------------------------------------------}//This just creates our custom TTreeNode{------------------------------------------------------------------------------}procedure TImportSelectorForm.ImportDirListCreateNodeClass( Sender: TCustomTreeView; var NodeClass: TTreeNodeClass);begin NodeClass:=TMyTreeNode;end; OK, but it still crashes.

I call this from a procedure in MainForm:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---AddImageToTree(DirList,Image); // Works OKBut, in another procedure, I call this to populate the TTreeView on the secondary form (having read in another Image):

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---AddImageToTree(ImportSelectorForm.ImportDirList,NewImage); //CrashesAs a workaround, I created a temporary TreeView in MainForm and did this:

--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---AddImageToTree(TempTreeView,NewImage);ImportSelectorForm.ImportDirList.Items:=TempTreeView.Items;Which works. I'm just confused as to why the original crashes. Of course, if I have no option but to use the second option, I'll just re-integrate those three procedures into the MainForm definition.

Oh - Lazarus 2.12 on macOS Catalina. Screen shot of error is in attachments.

geraldholdsworth:
And then I go and answer my own question.

It is because ImportSelectorForm is not yet visible, hence the TTreeView is also not visible.

Found this because I hid the TempTreeView and that then also crashed!

Navigation

[0] Message Index

Go to full version