john nash
john nash

Reputation: 49

How to iterate a DBGrid like a matrix in delphi

I have a DBGrid which fills with access database. All I want is to iterate that data like a matrix eg cell 00 , 01 ,02 , 10, 11, 12,

Upvotes: 2

Views: 4699

Answers (2)

MartynA
MartynA

Reputation: 30715

You've already had and accepted a good answer (which I've +1d, btw) to your q, but as I'd nearly finished this, I thought I might as well post it, if only to fill in a few details of how you could access a dataset in a [Row, Column] sort of way, if you really must. That's not to say it's a good idea to do that, of course.

So, the following is intended purely as a supplement to the other answer, not to "complete" with it and is subject to similar caveats:

  • Not all TDataSet descendants implement RecNo meaningfully

  • Ditto with DataSet.RecordCount (esp ones for Sql servers)

  • Performance will be dire a) for a dataset of any non-trivial size and b) absolutely dire if you attempt to access it by Column then Row "for" loops (because the DataSet has to jump all over the place!).

It uses a TDataArray class to wrap (and hide) the dataset but permit access to its field data like so:

    {Something which can receive a variant} := DataArray[Row, Column];

Btw, it's the "default" on the class's DataProperty that allows you to avoid having to write

    {Something ...} := DataArray.Data[Row, Column];

You asked about accessing a DBGrid in a matrix style by that's not really a good idea for several reasons, as mentioned in earlier comments. You might as well "cut out the middle-man" and access the dataset which is populating the grid.

Code

  TForm1 = class(TForm)
    CDS1: TClientDataSet;
    procedure FormCreate(Sender: TObject);
  private
    procedure SetUp;
  end;

  TDataArray = class
  private
    FDataSet : TDataSet;
    function GetData(Row, Column: Integer): Variant;
  public
    constructor Create(ADataSet : TDataSet);
    function RowCount : Integer;
    function ColumnCount : Integer;
    property Data[Row, Column : Integer] : Variant read GetData; default;   //NB 1-based
  end;
[...]

function TDataArray.ColumnCount: Integer;
begin
  Result := FDataSet.FieldCount;
end;

function TDataArray.RowCount: Integer;
begin
  Result := FDataSet.RecordCount;
end;

constructor TDataArray.Create(ADataSet: TDataSet);
begin
  inherited Create;
  FDataSet := ADataSet;
end;

function TDataArray.GetData(Row, Column: Integer): Variant;
var
  MoveBy : Integer;
begin
  Assert((Row > 0) and (Row <= FDataSet.RecordCount));  // check Column, too, if you want
  MoveBy := Row - FDataSet.RecNo;
  if MoveBy <> 0 then begin
    FDataSet.DisableControls;
    try
      FDataSet.MoveBy(MoveBy);
    finally
      FDataSet.EnableControls;
    end;
  end;
  Result := FDataSet.Fields[Column - 1].Value;
end;

procedure TForm1.SetUp;
var
  DataArray : TDataArray;
  Row,
  Column : Integer;
  AValue : Variant;
begin
  CDS1.FieldDefs.Add('ID', ftInteger);
  CDS1.FieldDefs.Add('Name', ftString, 20);
  CDS1.FieldDefs.Add('Value', ftString, 80);
  CDS1.CreateDataSet;

  CDS1.InsertRecord([1, 'A', 'A Value']);
  CDS1.InsertRecord([2, 'B', 'B Value']);
  CDS1.InsertRecord([3, 'C', 'C Value']);

  DataArray := TDataArray.Create(CDS1);
  try
    for Row := 1 to DataArray.RowCount do begin
      for Column := 1 to DataArray.ColumnCount do begin
        AValue := DataArray[Row, Column];
      end;
    end;
  finally
    DataArray.Free;
  end;
end;

Upvotes: 1

bummi
bummi

Reputation: 27377

A DBGrid is just a visual representation of the data. The native way would be to iterate over the dataset and the fields.
If your Dataset does support RecNo you might access the values using RecNo and the index of the field.(*)
Make sure not to access Rows above RecordCount - 1 and Fields above FieldCount -1

var
  i: Integer;
begin
  Dataset.DisableControls;
  try
    Dataset.First;
    While not Dataset.EOF do
    begin
      for i := 0 to Dataset.FieldCount - 1 do
      begin
        //Access your Field of the current row by depending of your intention by Value/String whatever you need
        //DoSomeThingWith(Dataset.Fields[i].Value); // make sure to handle NULL values
        DoSomeThingWith(Dataset.Fields[i].asString);
      end;
      Dataset.Next;
    end;
  finally
    Dataset.EnableControls;
  end;
end;

//(*)
Function GetFieldValue(Dataset:TDataset;Row:Integer;FieldIndex:Integer):Variant;
begin
  Dataset.RecNo :=  Row;
  Result := Dataset.Fields[FieldIndex].Value;
end;

Upvotes: 7

Related Questions