Search code examples
delphifiremonkeydelphi-xe8

Load database field of all records into ListView Item Detail Object


Using Delphi XE8 I'm currently testing functionality with Firemonkey TListViews.

One thing I'm trying to do is to load a field of all records from a TFDMemtable component into a Listview Item, specifically into the DetailObject of the ListView Item.

For example, I have 3 records in a table (db field is called 'Name'):

Record 1 = Name 1  
Record 2 = Name 2  
Record 3 = Name 3  

There is only 1 DetailObject property per ListView Item so my question is, would I be able to add all of the fields (Name 1, Name 2, Name 3) into that one DetailObject?

Below is what I've attempted so far but no luck. Not 100% sure what I need to do.

procedure MainForm.BuildList;
var LItem : TListViewItem;
begin
  ListView1.BeginUpdate;
  try
    ListView1.CLearItems;
    LItem := ListView1.Items.Add;
    LItem.Objects.DetailObject.Visible := True;
    with memtable do
    begin
      while not eof do
      begin
        LItem.Detail := FieldByName('Name').AsString;
      end;
    end;
  finally
    ListView1.EndUpdate;
  end;
end;

I'm sorry if this isn't clear enough, please let me know.

Any help would be great.


Solution

  • I think I should warn you that before seeing your q, I'd never done anything with FMX ListViews and Master/Detail datasets. The Following is a little rough around the edges, and the layout isn't ideal, but it shows one way to populate a ListView from Master + Detail datasets. I have no idea whether there are better ways. Personally, I would see if I could use Live Bindings to do the job.

    procedure TMasterDetailForm.BuildList;
    var
      LItem : TListViewItem;
      DetailItem : TListViewItem;
      ListItemText : TListItemText;
      DetailIndex : Integer;
    begin
      ListView1.BeginUpdate;
      ListView1.ItemAppearanceObjects.ItemEditObjects.Text.TextVertAlign := TTextAlign.Leading;  // The default 
      //  seems to be `Center`, whereas we want the Master field name to be at the top of the item
    
      try
        ListView1.Items.Clear; //Items;
        Master.First;
        while not Master.eof do begin
          LItem := ListView1.Items.Add;
          LItem.Text := Master.FieldByName('Name').AsString;
          LItem.Height := 25;
    
          Detail.First;
          DetailIndex := 0;
          while not Detail.Eof do begin
            Inc(DetailIndex);
            ListItemText := TListItemText.Create(LItem);
            ListItemText.PlaceOffset.X := 100;
            ListItemText.PlaceOffset.Y := 25 * (DetailIndex - 1);
            ListItemText.TextAlign := TTextAlign.Leading;
            ListItemText.Name := 'Name' + IntToStr(DetailIndex); //Detail.FieldByName('Name').AsString;
            LItem.Data['Name' + IntToStr(DetailIndex)] := Detail.FieldByName('Name').AsString;
            Detail.Next;
          end;
          LItem.Height := LItem.Height * (1 + DetailIndex);
    
          Master.Next;
        end;
      finally
        ListView1.EndUpdate;
      end;
    end;
    

    TListItemText is one of a number of "drawable" FMX objects that can be added to do the TListViewItem. They seem to need unique names so that they can be accessed via the Names property.

    FWIW, I used 2 TClientDataSets as the Master and Detail in my code.

    Also FWIW, for FMX newbies like me, populating an FMX TreeView is a lot more like what you'd do in a VCL project:

    procedure TMasterDetailForm.BuildTree;
    var
      PNode,
      ChildNode : TTreeViewItem;
    begin
      TreeView1.BeginUpdate;
      try
        TreeView1.Clear;
        Master.First;
        while not Master.eof do begin
          PNode := TTreeViewItem.Create(TreeView1);
          TreeView1.AddObject(PNode);
          PNode.Text := Master.FieldByName('Name').AsString;
    
          Detail.First;
          while not Detail.Eof do begin
            ChildNode := TTreeViewItem.Create(TreeView1);
            ChildNode.Text := Detail.FieldByName('Name').AsString;
            PNode.AddObject(ChildNode);
            Detail.Next;
          end;
          Master.Next;
        end;
      finally
        TreeView1.EndUpdate;
      end;
    end;
    

    Btw, in your code you should have been calling

    memtable.Next;
    

    in your while not eof loop, and memtable.First immediately before the loop.