Solved

Virtual Treeview how to...

Posted on 2001-08-13
6
3,404 Views
Last Modified: 2013-11-18
Greetings,

Short version: How do I iterate through specific data (say a StringList) adding information to the data structure I've associated with the VT?

Long version:
I just downloaded Mike's Virtual Treeview earlier today and while I'm as impressed as everyone else with it =) I am stuck on some pretty basic stuff.

The tree will have 5 root nodes. Off of the root nodes will be 3 to 15 child nodes.

To populate the tree, I want to read information from an Ini file.

So, I read the sections from the ini file:

var
  AppIni : TIniFile;
  tmpList: TStringList;
begin
  AppIni:= TIniFile.Create(ChangeFileExt(paramstr(0),'.ini'));
  tmpList := TStringList.Create;
 
  AppIni.ReadSections(tmpList);
end;

Now I have the section list and I can retrieve specific section values but I can't figure out how to use this information to create/add (?) my treenodes and associate the particular Ini section with the data structure for a given node.

More:

The ini file looks like this:

[Some UniqueNumber]
1=cancancanandthensome
2=The price of gas is crazy.
3=another sentence.

[Some other topic]
1=Another topic sentence here.
2=There can be many keys under each topic.

The treeview would look like this:

MainNode
MainNode
MainNode
  SomeUnigueNumber
MainNode
  Some other topic

Clicking on SomeUniqueNumber node would allow access to the node's data (which is just the keys from that topic in the ini file).

Sorry to be so long winded about it.

reddarin
0
Comment
Question by:reddarin
  • 3
  • 2
6 Comments
 
LVL 27

Accepted Solution

by:
kretzschmar earned 300 total points
ID: 6383454
not sure for what you are after

maybe this sample helps

unit tv_iniF_u;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  IniFiles, StdCtrls, VirtualTrees;

type
  TForm1 = class(TForm)
    VirtualStringTree1: TVirtualStringTree;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure VirtualStringTree1GetText(Sender: TBaseVirtualTree;
      Node: PVirtualNode; Column: Integer; TextType: TVSTTextType;
      var Text: WideString);
    procedure VirtualStringTree1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

type TDataRec = Record
                  Name  : String[200];
                  Value : String[200];
                end;
     PDataRec = ^TDataRec;

procedure TForm1.Button1Click(Sender: TObject);
var
  AIniFile : TIniFile;
  scList   : TStringList;
  vList    : TStringList;
  I,J      : Integer;
  RNode,ANode : PVirtualNode;
  AData    : PDataRec;

begin
  AIniFile := TIniFile.Create('D:\AIni.Ini');  //Open IniFile
  scList   := TstringList.Create;   //SectionList
  vList    := TstringList.Create;   //Valuelist
  try
    VirtualStringTree1.Clear;       //ClearTree
    VirtualStringTree1.NodeDataSize := SizeOf(TDataRec);  //Adjust Node-DataBuffer
    AIniFile.ReadSections(scList);  //Read Sections
    For I := 0 to scList.Count - 1 do
    begin
      RNode := VirtualStringTree1.AddChild(NIL);   //Add RootNode
      AData := VirtualStringTree1.GetNodeData(RNode);  //Get NodeDataBuffer
      AData.Name := 'Nothing';                         //Fill DataRecord
      AData.Value := scList[i];
      AIniFile.ReadSectionValues(scList[i],vList);  //Read SectionValues
      for J := 0 to vList.Count-1 do
      begin
        ANode := VirtualStringTree1.AddChild(RNode);  //Add ChildNode
        AData := VirtualStringTree1.GetNodeData(ANode); //Get NodeDataBuffer
        AData.Name := vList.Names[J];                 //Fill DataRecord
        AData.Value := vList.Values[vList.Names[J]];
      end;
    end;
  finally   //Clean Up
    scList.Free;
    vList.Free;
    AIniFile.Free;
  end;
end;

//Show the text in the tree
procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: Integer; TextType: TVSTTextType;
  var Text: WideString);
var AData : PDataRec;
begin
  AData := VirtualStringTree1.GetNodeData(Node);
  If Assigned(AData) then
    If VirtualStringTree1.GetNodeLevel(Node) = 0 then
      Text := AData.Value  //RootText
    else
      Text := AData.Name;  //NoneRootText
end;

//show the value of a none root Node
procedure TForm1.VirtualStringTree1Click(Sender: TObject);
var AData : PDataRec;
begin
  AData := VirtualStringTree1.GetNodeData(VirtualStringTree1.GetFirstSelected);
  If Assigned(AData) then
    If not (VirtualStringTree1.GetNodeLevel(VirtualStringTree1.GetFirstSelected) = 0) then
      ShowMessage(AData.Value);
end;

end.

meikl ;-)
0
 
LVL 3

Expert Comment

by:smurff
ID: 6383561
listening
0
 
LVL 6

Author Comment

by:reddarin
ID: 6384177
Hi meikl,

Looks promising. Let me try out your code.

>not sure for what you are after

Well. What are the odds my boss might read this post? =)

I have to do daily reports. Although the content of each day's report is fairly unique within a 20someodd day frame, the frame repeats itself. So Day 1 will repeat in about a month and a day, Day 2 in a month and 2 days, Day 3 in a month and 3 days and so on.

I'd send in a report and realize a day or two later that I'd forgotten some item that probably should have been included. In addition to that, there can be several items (10 to 15) for any given day but not all need to be included in the report.

I'd already constructed a small app to keep the report subject lines uniform so it was a small step from there to keeping the report content uniform but not identical for any given day month to month.

There are probably a dozen different ways I could have organized my information to accomplish the same goal without the use of Delphi, but I seldom pass up the opportunity to automate some tedious or interesting function with Delphi.

reddarin
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 
LVL 6

Author Comment

by:reddarin
ID: 6386905
Thank you very much meikl. Your example pointed the way :)

Here is a slightly generic version of the procedure I created to populate the tree with data from the ini file. Can you look it over and let me know if I've missed anything or perhaps used some questionable technique?

reddarin


type
  TDataRecord = record
    Caption   : string;
    TextValue : string;
    bDirty    : boolean;
  end;
PDataRecord = ^TDataRecord;

procedure TfrmOptions.InitOptions;

const
  MAIN_ROOT = 0;
  SUB_1     = 1;
  SUB_2     = 2;
  SUB_3     = 3;
  SUB_4     = 4;
var
  iniFile     : TIniFile;
  SectionList : TStringList;
  tmpList     : TStringList;
  nIdx        : integer;
  RNodes      : array [0..4] of PVirtualNode;
  ANode       : PVirtualNode;
  strCap      : string;
  AData       : PDataRecord;
  NodeSelected: integer;
begin
  try
  iniFile     := TIniFile.Create(ChangeFileExt(paramstr(0),'.ini'));
  SectionList := TStringList.Create;
  iniFile.ReadSections(SectionList);

  try
    {I have a Main section that is not needed here}
    SectionList.Delete(SectionList.IndexOf('Main'));
  except
  end;

  tvCat.NodeDataSize  := SizeOf(TDataRecord);
  RNodes[MAIN_ROOT] := tvCat.AddChild(nil);
  AData := tvCat.GetNodeData(RNodes[MAIN_ROOT]);
  AData.Caption := 'Main Root';

  for nIdx := SUB_1 to SUB_4 do begin
    RNodes[nIdx] := tvCat.AddChild(RNodes[MAIN_ROOT]);
    AData := tvCat.GetNodeData(RNodes[nIdx]);
    case nIdx of
      SUB_1    : begin
        strCap := 'Secondary 1';
      end;
      SUB_2    : begin
        strCap := 'Secondary 2';
      end;
      SUB_3    : begin
        strCap := 'Secondary 3';
      end;
      SUB_4    : begin
        strCap := 'Secondary 4';
      end;
    end;//case

    AData.Caption   := strCap;
    AData.TextValue := '';
    AData.bDirty    := FALSE;
  end;

  tmpList := TStringList.Create;

  for nIdx := 0 to SectionList.Count -1 do begin
    AData := tvCat.GetNodeData(RNodes[MAIN_ROOT]);  
    AData.TextValue := AData.TextValue + '[' + SectionList.Strings[nIdx] + ']' + #13#10;
    iniFile.ReadSectionValues(SectionList.Strings[nIdx],tmpList);
    AData.TextValue := AData.TextValue + tmpList.Text;
  end;

  for nIdx := 0 to SectionList.Count -1 do begin

    if pos('Subject 1',SectionList.Strings[nIdx]) <> 0 then begin
      NodeSelected := SUB_1
    end
    else if pos('Subject 2',SectionList.Strings[nIdx]) <> 0 then begin
      NodeSelected := SUB_2;
    end
    else if pos('Subject 3', SectionList.Strings[nIdx]) <> 0 then begin
      NodeSelected := SUB_3;
    end
    else if pos('Subject 4', SectionList.Strings[nIdx]) <> 0 then begin
      NodeSelected := SUB_4;
    end;
   

    ANode := tvCat.AddChild(RNodes[NodeSelected]);
    AData := tvCat.GetNodeData(ANode);
    AData.Caption := SectionList.Strings[nIdx];
    iniFile.ReadSectionValues(SectionList.Strings[nIdx],tmpList);
    AData.TextValue := tmpList.Text;
    AData := tvCat.GetNodeData(RNodes[NodeSelected]);
    if AData.TextValue = '' then
      AData.TextValue := '[' + SectionList.Strings[nIdx] + ']'+ #13#10 + tmpList.Text
    else
      AData.TextValue := AData.TextValue + #13#10 + #13#10 + '[' +
                         SectionList.Strings[nIdx] + ']' + #13#10 + tmpList.Text;

    NodeSelected := -1;
  end;

 
  finally
    FreeAndNil(iniFile);//.Free;
    FreeAndNil(SectionList);//.Free;
    FreeAndNil(tmpList);//.free;
  end;
end;
0
 
LVL 6

Author Comment

by:reddarin
ID: 6386910
Thanks again =)
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6387263
seems to be ok,

glad to helped you
good luck again

thanks for the points :-)

meikl ;-)
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

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…
I found this questions asking how to do this in many different forums, so I will describe here how to implement a solution using PHP and AJAX. The logical flow for the problem should be: Write an event handler for the first drop down box to get …
Viewers will learn one way to get user input in Java. Introduce the Scanner object: Declare the variable that stores the user input: An example prompting the user for input: Methods you need to invoke in order to properly get  user input:
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…

743 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

Need Help in Real-Time?

Connect with top rated Experts

14 Experts available now in Live!

Get 1:1 Help Now