How to loop through records on a cxgrid - Delphi xe2

9.5k views Asked by At

How do you loop through a cxgrids records? i.e. make delphi program go through/check each record in the cxgrid from top to bottom.

I have a cxgrid which is displaying records from a tadquery which is talking to a database table if this helps in anyway.

2

There are 2 answers

0
MartynA On

Sample code to do this for a TcxGridDBTableView in a TcxGrid, and also to iterate an DataSet below. Both of these samples will work regardless of whether the DataSet is filtered or not.

The sample for the TcxGrid assumes you've pulled the grid from the palette, added a TcxDBTableView to it, added the dataset's columns to it and left all grid properties in the Object Inspector at their defaults, except the KeyFieldNames of the TableView, which needs setting to the DataSet's primary key, in my case "FilesID". This is so as to be able to identify the dataset record for a given row in the TableView - you obtain the key value, ID, for the row like so:

      ID := cxGrid1DBTableView1.DataController.GetRecordId(TopRowIndex + Row);

The ID value is then used by the call to CDS1.Locate() to retrieve the record.

The TBookmark is used to note the current CDS record before the operation and to return to it afterwards. The calls to DisableControls and EnableControls are to prevent the cxGrid (and any other DB-aware controls connected to the CDS) from being changed while the operation is in progress.

procedure TForm1.IterateVisibleGridRows;
var
  BM : TBookmark;
  TopRowIndex : Integer;
  VisibleCount : Integer;
  Row : Integer;
  ID : Integer;
  Controller : TcxGridTableController;
  ViewInfo : TcxGridTableViewInfo;
begin
  BM := CDS1.GetBookmark;
  try

    Controller := cxGrid1DBTableView1.Controller;
    ViewInfo := TcxGridTableViewInfo(Controller.ViewInfo);

    TopRowIndex := Controller.TopRowIndex;
    VisibleCount := ViewInfo.RecordsViewInfo.VisibleCount;

    CDS1.DisableControls;

    Row := 0;
    while Row < VisibleCount do begin
      ID := cxGrid1DBTableView1.DataController.GetRecordId(TopRowIndex + Row);
      if CDS1.Locate('FilesID', ID, []) then begin
        // Do what you want here
      end;
      Inc(Row);
    end;

  finally
    CDS1.GotoBookmark(BM);
    CDS1.FreeBookmark(BM);
    CDS1.EnableControls;
  end;
end;

Btw, I know this is not what you asked, but if you want to iterate a dataset without doing it using a TcxGrid, it's actually much simpler:

procedure IterateDataSetRows(DataSet : TDataSet);
var
  BM : TBookmark;
begin
  BM := CDS1.GetBookmark;
  try
    // delete the following 2 lines and the one in the finally block if you don't want a "Wait" cursor
    Screen.Cursor := crSqlWait;
    Screen.ActiveForm.Update;

    DataSet.DisableControls;
    DataSet.First;

    while not DataSet.Eof do begin
        // Do what you want here
      DataSet.Next;
    end;

  finally
    DataSet.GotoBookmark(BM);
    DataSet.FreeBookmark(BM);
    DataSet.EnableControls;
    Screen.Cursor := crDefault;
  end;
end;
0
Jens Borrisholt On

You didn't say where it was all records in your grid or just the visible ones:

Any how heres is an example for doing both:

This example uses a form with a cxGrid, cxButton and a cxMemo. Plus a dxMemdataset

Here is the DFM code:

object Form20: TForm20
  Left = 0
  Top = 0
  Caption = 'Form20'
  ClientHeight = 299
  ClientWidth = 462
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  DesignSize = (
    462
    299)
  PixelsPerInch = 96
  TextHeight = 13
  object cxGrid1: TcxGrid
    Left = 0
    Top = 0
    Width = 299
    Height = 299
    Align = alLeft
    TabOrder = 0
    ExplicitHeight = 635
    object cxGrid1DBTableView1: TcxGridDBTableView
      Navigator.Buttons.CustomButtons = <>
      DataController.DataSource = DataSource1
      DataController.Summary.DefaultGroupSummaryItems = <>
      DataController.Summary.FooterSummaryItems = <>
      DataController.Summary.SummaryGroups = <>
      object cxGrid1DBTableView1RecId: TcxGridDBColumn
        DataBinding.FieldName = 'RecId'
        Visible = False
      end
      object cxGrid1DBTableView1Field1: TcxGridDBColumn
        DataBinding.FieldName = 'Field1'
      end
      object cxGrid1DBTableView1Field2: TcxGridDBColumn
        DataBinding.FieldName = 'Field2'
      end
    end
    object cxGrid1Level1: TcxGridLevel
      GridView = cxGrid1DBTableView1
    end
  end
  object cxButton1: TcxButton
    Left = 305
    Top = 8
    Width = 154
    Height = 25
    Caption = 'Do the trick'
    TabOrder = 1
    OnClick = cxButton1Click
  end
  object cxMemo1: TcxMemo
    Left = 305
    Top = 39
    Anchors = [akLeft, akTop, akRight, akBottom]
    Lines.Strings = (
      'cxMemo1')
    TabOrder = 2
    Height = 260
    Width = 154
  end
  object dxMemData1: TdxMemData
    Indexes = <>
    SortOptions = []
    Left = 160
    Top = 144
    object dxMemData1Field1: TIntegerField
      FieldName = 'Field1'
    end
    object dxMemData1Field2: TIntegerField
      FieldName = 'Field2'
    end
  end
  object DataSource1: TDataSource
    DataSet = dxMemData1
    Left = 168
    Top = 152
  end
end

First thing first at form create I generate some random Data:

procedure TForm20.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  randomize;
  dxMemData1.DisableControls;
  try
    dxMemData1.Open;
    for i := 0 to 999 do
      dxMemData1.AppendRecord([i, Random(500), Random(500)]);
  finally
    dxMemData1.EnableControls;
  end;
end;

Since my grid is bound to the dataset data will show up on screen.

Here is my form definition:

type
  TForm20 = class(TForm)
    dxMemData1: TdxMemData;
    dxMemData1Field1: TIntegerField;
    dxMemData1Field2: TIntegerField;
    cxGrid1DBTableView1: TcxGridDBTableView;
    cxGrid1Level1: TcxGridLevel;
    cxGrid1: TcxGrid;
    DataSource1: TDataSource;
    cxGrid1DBTableView1RecId: TcxGridDBColumn;
    cxGrid1DBTableView1Field1: TcxGridDBColumn;
    cxGrid1DBTableView1Field2: TcxGridDBColumn;
    cxButton1: TcxButton;
    cxMemo1: TcxMemo;
    procedure FormCreate(Sender: TObject);
    procedure cxButton1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

Then you just have to push the button:

procedure TForm20.cxButton1Click(Sender: TObject);
var
  RecNo, i: Integer;
  cxCustomGridRecordViewInfo: TcxCustomGridRecordViewInfo;
  s: string;
begin
  s := Format(
    'You have' + sLineBreak +
    '  %d records in your Dataset' + sLineBreak +
    '  %d records in your grid' + sLineBreak +
    '  %d VISIBLE records in your grid'
    , [
    cxGrid1DBTableView1.DataController.RecordCount,
      cxGrid1DBTableView1.DataController.FilteredRecordCount,
      cxGrid1DBTableView1.ViewInfo.VisibleRecordCount
      ]
      );

  MessageDlg(s, mtInformation, [mbOK], 0);

  cxMemo1.Lines.BeginUpdate;
  cxMemo1.Lines.Clear;

  cxMemo1.Lines.Add(' *** Filtered Records ***');

  for i := 0 to cxGrid1DBTableView1.DataController.FilteredRecordCount - 1 do
  begin
    RecNo := cxGrid1DBTableView1.DataController.FilteredRecordIndex[i];
    cxMemo1.Lines.Add(cxGrid1DBTableView1.DataController.Values[RecNo, 1]);
  end;

  cxMemo1.Lines.Add(' *** Visible Records ***');

  for i := 0 to cxGrid1DBTableView1.ViewInfo.VisibleRecordCount - 1 do
  begin
    cxCustomGridRecordViewInfo := cxGrid1DBTableView1.ViewInfo.RecordsViewInfo[i];
    cxMemo1.Lines.Add(cxCustomGridRecordViewInfo.GridRecord.Values[1]);
  end;

  cxMemo1.Lines.EndUpdate;
end;

So there you see Filtered records are the one you have in your grid after possibly after a filter had been applyed. Visible Record are the onec actually visible on the screen.