Shambhala
Shambhala

Reputation: 1169

How to add from a TStringList to a VirtualTreeView?

Here is what I am "trying" to achieve

I have a function to generate passwords which I then add into a TStringList after this I should populate the VirtualTreeView with the items but I am having no luck in getting anywhere fast with doing so. How should it be done the correct way? I am still learning and am not a professional.

My function for generating the passwords:

function Generate(AllowUpper,AllowLower,AllowNumbers,AllowSymbols:Boolean; PassLen:Integer):String;
const
  UpperList  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  LowerList  = 'abcdefghijklmnopqrstuvwxyz';
  NumberList = '0123456789';
  SymbolList = '!#$%&/()=?@<>|{[]}\*~+#;:.-_';
var
  MyList  : String;
  Index   : Integer;
  i       : Integer;
begin
  Result:='';
  MyList:='';
   //here if the flag is set the elements are added to the main array (string) to process
   if AllowUpper   then MyList := MyList + UpperList;
   if AllowLower   then MyList := MyList + LowerList;
   if AllowNumbers then MyList := MyList + NumberList;
   if AllowSymbols then MyList := MyList + SymbolList;

   Randomize;
   if Length(MyList)>0 then
   for i := 1 to PassLen do
   begin
    Index := Random(Length(MyList))+1;
    Result := Result+MyList[Index];
  end;
end;

Here is how I am calling it

procedure TMain.Button3Click(Sender: TObject);
var
  i: integer;
  StrLst: TStringList;
// Timing vars...
  Freq, StartCount, StopCount: Int64;
  TimingSeconds: real;
begin
  vst1.Clear;
  Panel2.Caption := 'Generating Passwords...';
  Application.ProcessMessages;
// Start Performance Timer...
  QueryPerformanceFrequency(Freq);
  QueryPerformanceCounter(StartCount);

  StrLst := TStringList.Create;
  try
  for i := 1 to PassLenEd.Value do
   StrLst.Add(Generate(ChkGrpCharSelect.Checked[0],ChkGrpCharSelect.Checked[1],
    ChkGrpCharSelect.Checked[2],ChkGrpCharSelect.Checked[3],20));
// Stop Performance Timer...
    QueryPerformanceCounter(StopCount);
    TimingSeconds := (StopCount - StartCount) / Freq;
// Display Timing... How long it took to generate
    Panel2.Caption := 'Generated '+IntToStr(PassLenEd.Value)+' passwords in '+
    FloatToStrF(TimingSeconds,ffnumber,1,3)+' seconds';

// Add to VirtualTreeList - here???
finally
    StrLst.Free;
  end;
end;

I expect that I am doing this completely the wrong way, I have been trying for 2 days now, it would be great if someone could put me straight with how I should go about it.

Chris

Upvotes: 1

Views: 1709

Answers (3)

user532231
user532231

Reputation:

Or if you really want VirtualTreeView, you can use something like this ... I'm not sure if this is absolutely clear solution, I'm familiar with records, not only one single variables.

procedure TMain.Button3Click(Sender: TObject);
var i: integer;
    p: PString;
    Freq, StartCount, StopCount: Int64;
    TimingSeconds: real;

begin
  Panel2.Caption := 'Generating Passwords...';
  Application.ProcessMessages;

  QueryPerformanceFrequency(Freq);
  QueryPerformanceCounter(StartCount);

  vst1.BeginUpdate;
  vst1.Clear;

  for i := 1 to PassLenEd.Value do
    begin
      p := VirtualStringTree1.GetNodeData(VirtualStringTree1.AddChild(nil));
      p^ := Generate(ChkGrpCharSelect.Checked[0],ChkGrpCharSelect.Checked[1], ChkGrpCharSelect.Checked[2],ChkGrpCharSelect.Checked[3],20);
    end;

  vst1.EndUpdate;

  QueryPerformanceCounter(StopCount);
  TimingSeconds := (StopCount - StartCount) / Freq;
  Panel2.Caption := 'Generated '+IntToStr(PassLenEd.Value)+' passwords in '+
  FloatToStrF(TimingSeconds,ffnumber,1,3)+' seconds';
end;

And you need to implement OnGetNodeDataSize and OnGetText events to initialize node data size and to display the text.

procedure TMain.vst1GetNodeDataSize(
  Sender: TBaseVirtualTree; var NodeDataSize: Integer);
begin
  NodeDataSize := SizeOf(string);
end;

procedure TMain.vst1GetText(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
  var CellText: string);
begin
  CellText := PString(VirtualStringTree1.GetNodeData(Node))^;
end;

Edit 1: I've corrected data types UnicodeString -> String

Upvotes: 2

Linas
Linas

Reputation: 5545

You better store your stringlist somewhere else in your code to use it "virtually", e.g. in the form's private section. When after populating it, just set:

vst1.Clear;
vst1.RootNodeCount := StrLst.Count;

And on tree's get text event:

procedure TForm1.vst1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex;
  TextType: TVSTTextType; var CellText: string);
begin
  CellText := StrLst[Node.Index];
end;

Upvotes: 3

David Heffernan
David Heffernan

Reputation: 613592

I'd probably stick with TListView but turn it into a virtual list view. Like this:

procedure TMyForm.FormCreate;
begin
  ListView.OwnerData := True;
  ListView.OnData = ListViewData;
  ListView.Items.Count := StringList.Count;
end;

procedure TMyForm.ListViewData(Sender: TObject; ListItem: TListItem);
begin
  ListItem.Caption := StringList[ListItem.Index];
end;

You can put millions of items in there in an instant.

Upvotes: 7

Related Questions