6String_Coder
6String_Coder

Reputation: 547

Build TListView programmatically not using livebindings

I have a cross platform app which contains a TFDMemtable(FireDAC).

My question is, how would one manually build a TListView from the records in this table?

The table I have contains a list of male forenames in alphabetical order.

e.g. Adam, Anthony, Alan, Brian, Bill, Bob, Ben, Charlie, Craig, Christopher, Colin and so on.

I want the listview to include groupings for the names, so A,B,C etc.

I have the following so far:

procedure BuildNameList;
var Litem : TListViewItem;
c : Char;
begin
  ListView1.BeginUpdate;
  try
   ListView1.ClearItems;

  for c := 'A' to 'Z' do
  begin
    with ListView1.Items.Add do
    begin
      Text := char(c);
      Purpose := TListItemPurpose.Header;
    end;

  with dmod.tableNames do
  begin
    First;
   while not Eof do
    begin
      Litem := ListView1.Items.Add;         
      Litem.Text := dmod.tableNames.FieldByName('ForeName').AsString;
      Next;
    end;
  end;
  end;
  finally
    ListView1.EndUpdate;
end;

The above code doesn't give me the result I'm after, what happens is I get every name duplicated under every letter group(A-Z).

Any suggestions/help would be much appreciated. Thanks

Upvotes: 4

Views: 1436

Answers (1)

Ken White
Ken White

Reputation: 125757

You need to change your logic somewhat to add first the header, and then the names under that header, and then the next header and set of names. Here's a full test app that demonstrates. You'll need to drop a FMX TListView and a TClientDataSet on your form and connect up the FormCreate event to see it work. (Note that the index is needed on the ClientDataSet in order to ensure the names are in the proper order; if they're not alphabetized, the code won't work, because it won't find the data as needed to add to the section.)

unit Unit3;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.ListView.Types, Data.DB,
  Datasnap.DBClient, FMX.ListView;

type
  TForm3 = class(TForm)
    ListView1: TListView;
    CDS: TClientDataSet;
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
    procedure BuildNameList;
  public
    { Public declarations }
  end;

var
  Form3: TForm3;

implementation

{$R *.fmx}

procedure TForm3.BuildNameList;
var
  Item: TListViewItem;
  Ch: Char;
begin
  ListView1.BeginUpdate;
  CDS.First;
  try
    ListView1.ClearItems;
    for Ch := 'A' to 'Z' do
    begin
      Item := ListView1.Items.Add;
      Item.Text := Ch;
      Item.Purpose := TListItemPurpose.Header;

      while (CDS.FieldByName('SurName').AsString[1] = Ch) and (not CDS.Eof) do
      begin
        Item := ListView1.Items.Add;
        Item.Text := CDS.FieldByName('SurName').AsString + ', ' +
                     CDS.FieldByName('ForeName').AsString;

        CDS.Next;
      end;
    end;
  finally
    ListView1.EndUpdate;
  end;
end;

procedure TForm3.FormCreate(Sender: TObject);
begin
  // Create some test data
  CDS.FieldDefs.Add('ForeName', ftString, 20);
  CDS.FieldDefs.Add('SurName', ftString, 30);
  CDS.CreateDataSet;
  CDS.Open;
  CDS.AppendRecord(['John', 'Smith']);
  CDS.AppendRecord(['Jane', 'Doe']);
  CDS.AppendRecord(['Ralph', 'Richards']);
  CDS.AppendRecord(['Fred', 'Fredericks']);
  CDS.AppendRecord(['Sam', 'Samuels']);
  CDS.AppendRecord(['Walter', 'Williams']);
  CDS.AppendRecord(['Ann', 'Anderson']);
  CDS.AppendRecord(['Bob', 'Barnes']);

  // Index it to put it in alphabetical order
  CDS.IndexDefs.Add('Names', 'SurName;ForeName', []);
  CDS.IndexName := 'Names';
  BuildNameList;
end;

end.

Here's a screenshot of a center section of that sample app's ListView, so you can see the results:

ListView displaying alpha list with section headers

Upvotes: 3

Related Questions