Solved

Can't create TreeNodes while in Create constructor of a TWinControl

Posted on 2004-04-29
5
339 Views
Last Modified: 2010-04-05
I designed a new visual component (TWinComponent) that contains a TreeView. When I create a node in the Create constructor (after initialization of the TreeView), I can't use this Node in latter procedure. i.e. when inserting a new node (Child or Sibling) if works fine in the create constructor but failed (raise various exception) when added in other function. Here is the Example that failed:

TTest = class(TWinControl)
    private
       fTreeView : TTreeView;
       fNode1 : TTreeNode;
       fNode2 : TTreeNode;
    public
       constructor Create(AOwner : TComponent); override;
       destructor Destroy; override;
       procedure Test(AString : String);
    end;

constructor TTest.Create(AOwner: TComponent);
begin
     inherited;
     fTreeView := TTreeView.Create(Self);
     fTreeView.Parent := Self;
     fTreeView.Align := alClient;
     fTreeView.ReadOnly := True;

     fNode1 := fTreeView.Items.Add(nil,'Node1');
     fNode2 := fTreeView.Items.AddChild(fNode1,'Node2'); //This works fine
end;

procedure TTest.Test(AString : String);
var
   ANode : TTreeNode;
begin
       ANode := fTreeView.Items.AddChild(fNode1,AString); // This yield to various Exception
       // ... Perform various operation
end;

Alternatively the following work around works fine.

TTest = class(TWinControl)
    private
       fTreeView : TTreeView;
       fNode1 : TTreeNode;
       fNode2 : TTreeNode;
       fPrepared : Boolean;
       procedure Prepare;
    public
       constructor Create(AOwner : TComponent); override;
       destructor Destroy; override;
       procedure Test(AString : String);
    end;

constructor TTest.Create(AOwner: TComponent);
begin
     inherited;
     fTreeView := TTreeView.Create(Self);
     fTreeView.Parent := Self;
     fTreeView.Align := alClient;
     fTreeView.ReadOnly := True;
     fPrepared := False;
end;

procedure TTest.Test(AString : String);
begin
       fNode1 := fTreeView.Items.Add(nil,'Node1');
       fNode2 := fTreeView.Items.AddChild(fNode1,'Node2'); //This works fine
       fPrepared := true;
end;

procedure TTest.Prepare;
var
   ANode : TTreeNode;
begin
       if not fPrepared then
            Prepare;
       ANode := fTreeView.Items.AddChild(fNode1,AString); // This yield to various Exception
       // ... Perform various operation
end;

Note: the TTest is registered in the VCL Palette and dropped in the form during design.
0
Comment
Question by:mavrj
  • 2
  • 2
5 Comments
 
LVL 3

Expert Comment

by:MikProg
ID: 10948790
A piece of code where you call Test and Prepare. (and i think you swap body of them)
0
 
LVL 1

Author Comment

by:mavrj
ID: 10948852
Good point ! Sorry for the mistake. Tried to make it to simple :-)

Read:

procedure TTest.Prepare;
begin
       fNode1 := fTreeView.Items.Add(nil,'Node1');
       fNode2 := fTreeView.Items.AddChild(fNode1,'Node2'); //This works fine
       fPrepared := true;
end;

procedure TTest.Test(AString : String);
var
   ANode : TTreeNode;
begin
       if not fPrepared then
            Prepare;
       ANode := fTreeView.Items.AddChild(fNode1,AString); // This yield to various Exception
       // ... Perform various operation
end;
0
 
LVL 17

Accepted Solution

by:
geobul earned 250 total points
ID: 10952126
Hi,

Perhaps the reason is in the streaming mechanism when you are saving/loading your component.

1. When you drop your component on a form these two nodes are created by the constructor(design-time).
2. When you save/run your project these two nodes are already there (created automatically because they were saved/streamed) and
fNode1 := fTreeView.Items.Add(nil,'Node1');
actually fails to add a new node and fNode1 remaims unititialized.
3. When you execute your Test method it raises an AV because fNode1 is nil (or points somewhere else).

I might be wrong, of course.

Regards, Geo
0
 
LVL 3

Expert Comment

by:MikProg
ID: 10956324
geobul>You forget to write solution code

TTest = class(TWinControl)
    private
       fTreeView : TTreeView;
       fNode1 : TTreeNode;
       fNode2 : TTreeNode;
    protected
       procedure Loaded; override;
    public
       constructor Create(AOwner : TComponent); override;
       destructor Destroy; override;
       procedure Test(AString : String);
    end


procedure TTest.Loaded;
begin
   fNode1:=fTreeView.Items.GetFirstNode;
   fNode2:=fNode2.GetFirstChild;
end;
0
 
LVL 17

Expert Comment

by:geobul
ID: 10956777
Yes, exactly - overriding Loaded is the way to go. I had no time for testing yesterday (last night actually :-).
0

Featured Post

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

789 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question