For Meikl

Hi, Meikl.

You helped me last week with my question titled "Records" by providing me with a sample program.

I am thinking of adapting the program sample you gave so that i can add the parent nodes in myself when required instead of having them fixed inside the program.

I am hoping that you can help me by showing me how i can adapt the program so as to allow for this.

can you help?
mi6agentAsked:
Who is Participating?
 
kretzschmarCommented:
hi

well if you change the typ-field of a record, then the record-entry must change to another parentnode

for ex.
you have a record AName, which has the typ friend

friend
|-AName
|-AName2
workers
|-Aname3

you change the type to best friend and update the record,
the result will be then in the tree

friend
|-AName2
best friend
|-AName
workers
|-AName3

parentswap indicates, that the type has changed and introduce a node move to the other parent which matches the changed type via the insertnode-method

meikl ;-)
0
 
kretzschmarCommented:
well, i would help you, but i don't know yet, what exactly you mean?

do you mean variable parents?

if so, then just add a secondary file with a structure like
ID : Integer;
Name : String[50];

which is read in the inittree-method?

well, could post this evening a sample,
if you mean this

meikl ;-)
0
 
mi6agentAuthor Commented:
Hi Meikl

What i am looking to do is to start with no parents in the treeview and be able to add/delete a parent node to the treeview when i want.  Then i will be able to add a record under the new parent.

I just can't work out a way to be able to do that and be able to save and reload it all back in when i restart the program.

Hope this explains it better for you

0
Cloud Class® Course: Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

 
kretzschmarCommented:
well,

sounds like
it could be done,
as i mentioned above

sample follows in ~9 hours

meikl ;-)
0
 
mi6agentAuthor Commented:
thanks Meikl - i shall wait till it suits you.  

speak to you later.
0
 
kretzschmarCommented:
sorry, got not the time today
(during week is too much todo)

if you are not in hurry, then i post it hopefully tomorrow
otherwise open another q for all

meikl ;-)
0
 
mi6agentAuthor Commented:
That's ok Meikl, i can wait.  I know you will help if you can so i shall wait for you.
0
 
mi6agentAuthor Commented:
thought i would increase the points for you since you are kind enough to help me on this one again.
0
 
kretzschmarCommented:
you do not need to raise the points for me,
have begun yesterday, but not ready yet

this evening it comes :-)

meikl ;-)
0
 
mi6agentAuthor Commented:
Thanks Meikl.  As for the points, your help is worth it.
0
 
kretzschmarCommented:
well, here it comes

well, its already a one file based app,
i've the typ-field in the record to string,
also the combobox is now at the style-property so adjusted,
that u can type in or select an entry->style csDropDown

the inittree method is canceled,
a new method findparent is introduced,
this method looks up, if a given typ alredady exists in the tree,
and returns the node if found.

the insertnode is changed,
it calls now the findparent-method,
if findparent nothing found,
a root node is ceated with given typ
and the comboboxlist is expanded with the new typ-entry.

so it should be now very dynamic,
the root entrys now depends on that what
you type in the combobox

empty rootnodes will disappear after next appstart

unit r_file_tree3_u;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ComCtrls, ExtCtrls;

Type TheRec = Record  //a record
                LastName  : String[100];
                FirstName : String[100];
                //more attributes could stand here
                Typ      : String[100];
                Deleted  : Boolean;
              end;


type
  TForm1 = class(TForm)
    TreeView1: TTreeView;
    Panel1: TPanel;
    Edit1: TEdit;
    Edit2: TEdit;
    BInsert: TButton;
    BUpdate: TButton;
    BDelete: TButton;
    ComboBox1: TComboBox;
    procedure FormCreate(Sender: TObject);
    procedure BInsertClick(Sender: TObject);
    procedure BUpdateClick(Sender: TObject);
    procedure BDeleteClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure TreeView1Change(Sender: TObject; Node: TTreeNode);
    procedure FormDestroy(Sender: TObject);
  private
    NodeList : TList;      //Never used
    f : file of TheRec;    // file of this record
    rec : TheRec;   {Buffer} // a memorybuffer for this record
    Currentrecord : LongInt; {FileCursor}  //Points to the current record in the file
    RecordCount : LongInt; {RecordCount} //Holds the amount of records in the file
    Procedure PopulateEdits;
    Procedure PopulateRecord;
    Procedure CleanUpFile_at_Back;  //looks at the last record, if this is deleted, and deletes it
    Procedure CleanUpFile;          //Deletes all records, which are marked for deletion
    Procedure LoadTree;             //adds the level two nodes from files
    Procedure GetRecord(ARecNo : LongInt);  //gets a record
    Procedure UpdateRecord;         //Upsate a Record
    Procedure MarkToDeleteRecord;   //Marks a record for delete
    Procedure InsertNode(AName : String; AType : String; ARecNo : LongInt; DoSelect : Boolean);  //Inserts a Node into the tree
    Procedure AdJustControls(Switch : Boolean);  //Dis-/Enables Buttons
    Procedure InsertRecord;         //Insert a Record
    Function Findparent(AType : String) : TTreeNode;  //Find the Parent by Typ
  public
    { Public-Deklarationen }
  end;



var
  Form1: TForm1;


implementation

{$R *.DFM}

//open the file
procedure TForm1.FormCreate(Sender: TObject);
var I : Integer;
begin
  assignfile(f,'MyFile3.Dat');  //we will work with this file
  if not(fileexists('MyFile3.Dat')) then  //if this file not exists
    rewrite(f)  //create this file
  else
    reset(f);   //open this file
  CurrentRecord := 0;      //
  RecordCount := fileSize(f);
  LoadTree;
end;

Procedure TForm1.InsertRecord;
begin
  PopulateRecord;
  rec.Deleted := False;
  seek(f,RecordCount);  //goto last record
  write(f,rec);
  inc(RecordCount);
  CurrentRecord := RecordCount;
  InsertNode(rec.LastName,rec.typ,CurrentRecord,True);
end;

procedure TForm1.BInsertClick(Sender: TObject);
begin
  InsertRecord;
end;

procedure TForm1.BUpdateClick(Sender: TObject);
begin
  UpdateRecord;
end;

procedure TForm1.UpdateRecord;
var
  ParentSwap : Boolean;
begin
  if CurrentRecord > 0 then
  begin
    //must we Move the ChildeNode
    ParentSwap := rec.typ <> combobox1.Text;
    PopulateRecord;
    seek(f,CurrentRecord-1);
    write(f,rec);
    If ParentSwap then
    begin
      TreeView1.Selected.Delete;
      InsertNode(rec.LastName,rec.typ,CurrentRecord,True);
    end
    else
      TreeView1.Selected.Text := rec.LastName; //Update NodeText
  end;
end;

Procedure TForm1.MarkToDeleteRecord;
Begin
  rec.deleted := true;
  seek(f,CurrentRecord-1);
  write(f,rec);
  treeview1.selected.Delete;
End;


procedure TForm1.BDeleteClick(Sender: TObject);
begin
  MarkToDeleteRecord;
end;


procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  closefile(f);
end;

Procedure TForm1.AdJustControls(Switch : Boolean);
var I : integer;
begin
  BUpdate.Enabled := Switch;
  BDelete.Enabled := Switch;
  If Not(Switch) then
  begin
    combobox1.ItemIndex := -1;
    edit1.text := '';
    edit2.text := '';
  end;
end;

procedure TForm1.TreeView1Change(Sender: TObject; Node: TTreeNode);
begin

  If Node.Level > 0 then
  begin
    GetRecord(Integer(node.Data));
    PopulateEdits;
  End;
  AdjustControls(Node.Level > 0);
end;

Procedure TForm1.GetRecord(ARecNo : LongInt);
begin
  If (ARecNo > 0) and (ARecNo <= RecordCount) then
  begin
    try
      seek(f,ARecNo-1);
      read(f,rec);
      CurrentRecord := ARecNo;
    except
      raise;
    end;
  End
  else
    raise exception.create('GetRecord : Recno Out of Bounds');
end;

procedure TForm1.PopulateEdits;
begin
  edit1.text := rec.FirstName;
  edit2.text := rec.LastName;
  //maybe more attributes
  ComboBox1.Text := rec.typ;
end;

procedure TForm1.PopulateRecord;
Begin
  rec.FirstName := edit1.text;
  rec.LastName := edit2.text;
  if comboBox1.Text <> '' then
    rec.Typ := ComboBox1.Text
  else
    raise exception.create('Typ must be set!');
  //maybe more attributes
End;

Procedure TForm1.CleanUpFile_at_Back;
var
  endloop : Boolean;
begin
  if RecordCount > 0 then
  begin
    endloop := False;
    while (not endloop) and (RecordCount > 0) do
    begin
      getrecord(RecordCount);
      if rec.Deleted then
      begin
        seek(f,RecordCount-1);
        truncate(f);
        dec(RecordCount);
      end
      else endloop := true;
    end;
  end;
end;

Procedure TForm1.CleanUpFile;
var
  tmpCurrentRecord : Integer;
Begin
  If RecordCount > 0 then
  begin
    tmpCurrentRecord := 1;
    CleanUpFile_at_Back;  //be sure the last record isn't deleted
    while tmpCurrentRecord < RecordCount do
    begin
      GetRecord(tmpCurrentRecord);
      if rec.Deleted then
      begin
        GetRecord(RecordCount);  //swap records
        seek(f,tmpCurrentRecord-1);
        write(f,rec);
        seek(f,RecordCount-1);
        truncate(f);         //snip
        dec(RecordCount);
        CleanUpFile_at_Back; //be sure the new last record isn't deleted
      end;
      inc(tmpCurrentRecord);
    end;
  end;
  CloseFile(f);  //force physically write
  reset(f);
  CurrentRecord := 0;  //reinit
  If (filesize(f) = RecordCount) then
    RecordCount := FileSize(f)
  else
    raise exception.Create('CleanUp : Something goes wrong');
end;

Function TForm1.Findparent(AType : String) : TTreeNode;
begin
  Result := TreeView1.Items.GetFirstNode;
  While (Result <> NIL) and (Result.Text <> AType) do
    Result := Result.GetNextSibling;
end;


procedure TForm1.InsertNode(AName : String;
                            AType : String;
                            ARecNo : LongInt;
                            DoSelect : Boolean);
var
  ANode : TTreeNode;
  AIndex : Integer;
Begin
  //Search the parentnode
  ANode := FindParent(AType);
  If Anode = Nil then  //Not found
  begin
    Anode := TreeView1.Items.Add(NIL,AType); //Add RootEntry
    ComboBox1.Items.Add(AType);              //Expand Combo
  end;
  ANode := TreeView1.Items.AddChild(ANode,AName); //Create Node
  ANode.Data := Pointer(ARecNo);  //Store recordposition
  If DoSelect Then
  begin
    TreeView1.Selected := ANode;  //Select Node
    ANode.MakeVisible;
  end;
end;

procedure TForm1.LoadTree;
Begin
  CleanUpFile;   //Delete all marked physically
  CurrentRecord := 0;    //load From Beginning
  seek(f,CurrentRecord);
  While not eof(f) do
  begin
    Read(f,rec);
    inc(CurrentRecord);
    InsertNode(rec.LastName,rec.typ,CurrentRecord,False);
  end;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  NodeList.Free; //free the list of RootNodes
end;

end.

hope this helps
ask if something unclear

meikl ;-)
0
 
mi6agentAuthor Commented:
Thanks Meikl, you did it again!  I wish i was as good as you at doing all of this.

One question though, what exactly is the purpose of "ParentSwap" i can't seem to figure out what it does.
0
 
mi6agentAuthor Commented:
thanks meikl, i think i understand it a bit better now.

as i said, you are a genius and thank you very much for your help in all of this.

0
 
mi6agentAuthor Commented:
again, i give and excellent grade for an excellent answer and an excellent guy that took the time to help.

thanks.
0
 
kretzschmarCommented:
no no, i'm not a genius

well glad you like it
you a very generous with your points, thnaks :-)

good luck again

meikl ;-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.