2006. december 11., hétfő

How to synchronize a TTreeView with a TMemo


Problem/Question/Abstract:

I'm trying to synchronize different nodes in a TTreeView with different text displayed in a TMemo control.

Answer:

Lets assume you want to store the memo text into TStringList instances and store the stringlist reference into the node.data property. The first order of the day is to create the stringlists. You do that when you create the nodes, that is the logical place to do it. So after you have added a node you do a

node.Data := TStringlist.Create;

The stringlist is initially empty, of course. So if you have some data to load into the node you can load it into the stringlist with a statement like

TStringlist(node.data).Text := SomeStringValue;

The act of moving the text to the memo and back is now a simple assignment, no stringlists get created for that since we already have them. The main problem is to get aware when the user moves to a new node, so the old (perhaps edited) node can be updated from the memo. This seems to be another problem that is giving you grief. The solution is to track the *last* selected node, the one whos content is currently in the memo. Add a field

FLastNode: TTreeNode;

to your form (private section). This field starts out as Nil (no node active).

procedure TForm1.tv_eg5Change(Sender: TObject; Node: TTreeNode);
begin
  if Node.Selected and (FLastNode <> Node) then
  begin
    if Assigned(FLastNode) then
      TStringlist(FLastNode.Data).Assign(memo1.lines);
    Memo1.Lines.Assign(TStringlist(Node.Data));
    FLastNode := Node;
  end;
end;

procedure TForm1.Memo1Exit(Sender: TObject);
begin
  if assigned(FLastnode) then
    TStringlist(FLastNode.Data).Assign(memo1.lines);
end;

You have to check whether the memos Onexit event happens before or after the treeviews OnChange event if you have focus on the memo and click on an item in the treeview. If it happens after the OnChange event the Onexit handler needs to be modified to look like

procedure TForm1.Memo1Exit(Sender: TObject);
begin
  if assigned(FLastnode) and not treeview1.focused then
    TStringlist(FLastNode.Data).Assign(memo1.lines);
end;

Otherwise you will assign the memos content just back from the node the OnChange handler just loaded it from.

A final thing you have to do is free the stringlist items attached to the treeview before the form is destroyed. If you don't use drag & dock with the treeview or the form it is on you could use the OnDeletion event of the treeview for this, doing a

TObject(node.data).Free;

in the handler. If drag & dock is involved this is not a good idea since the event fires each time the treeview or its parent changes from undocked to docked status and back. In this case the forms OnCloseQuery or OnClose event may be suitable. There you iterate over the treeviews nodes and do the free on each as above.

Nincsenek megjegyzések:

Megjegyzés küldése