8

How can I access a TDBGrid column by name instead of Index?

For example, now I use:

 grdInvoiceItems.Columns[2].Visible := False;

but it would be much better to write something like:

 grdInvoiceItems.Columns['UnitPrice'].Visible := False;

In the mean time I use a for cycle like in:

  for idx := 0 to grdInvoiceItems.Columns.Count - 1 do
    begin
    if (
         (grdInvoiceItems.Columns[idx].FieldName = 'UnitPrice') or
         (grdInvoiceItems.Columns[idx].FieldName = 'Discount') or
         (grdInvoiceItems.Columns[idx].FieldName = 'SecretCode')
       ) then
      grdInvoiceItems.Columns[idx].Visible := False;
    end;

Using colum name is IMO much better tham column index since index is subject to change more often than name.

Any idea on how to encapsulate it better?

Fabio Vitale
  • 2,257
  • 5
  • 28
  • 38
  • Possible duplicate of [Get Column Object for DataSet Field](http://stackoverflow.com/questions/31310442/get-column-object-for-dataset-field) – Val Marinov Jun 16 '16 at 08:04
  • Depending on how the columns are created, you can use directly the field behind the column to make it visible or not. Take a look at http://stackoverflow.com/questions/24527027/proper-way-to-hide-show-columns-on-dbgrid – RBA Jun 16 '16 at 13:02

3 Answers3

14

You could try something like this:

function ColumnByName(Grid : TDBGrid; const AName : String) : TColumn;
var
  i : Integer;
begin
  Result := Nil;
  for i := 0 to Grid.Columns.Count - 1 do begin
  if (Grid.Columns[i].Field <> Nil) and (CompareText(Grid.Columns[i].FieldName, AName) = 0) then begin
       Result := Grid.Columns[i];
       exit;
     end;
  end;
end;

Of course, if you are using a version of Delphi which is recent enough to support Class Helpers, you could wrap this function into a Class Helper for TDBGrid, like this

type
  TGridHelper = class helper for TDBGrid
    function ColumnByName(const AName : String) : TColumn;
  end;
[...]

function TGridHelper.ColumnByName(const AName: String): TColumn;
var
  i : Integer;
begin
  Result := Nil;
  for i := 0 to Columns.Count - 1 do begin
     if (Columns[i].Field <> Nil) and (CompareText(Columns[i].FieldName, AName) = 0) then begin
       Result := Columns[i];
       exit;
     end;
  end;
end;

Then, you could do this

Col := DBGrid1.ColumnByName('SomeName');

Obviously, you could write a similar function which searches by the column's title, rather than the associated Field's FieldName.

MartynA
  • 30,454
  • 4
  • 32
  • 73
1

You could create a mapping between column name and grid index e.g. as a dictionary and use that. Note that not every column in a dataset is necessarily visible in a dbgrid. In addition there might be calculated fields in the dataset, so don't forget these. The safest way to create the mapping would be to iterate trough the columns of the dbgrid and store their field names together with the column index. This way you won't get any invalid entries and any field that's not in the mapping does not have a dbgrid column.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
  • Yes please I would really appreciate a small sample code: your approach is intresting – Fabio Vitale Jun 17 '16 at 08:57
  • @Fabio: You don't need a dictionary if you use the technique in the other answer and, unlike this one, it is self-maintaining because it will only ever find columns which actually exist. What if you create a dictionary, the sometime later, remove a column but forget to update the dictionary? – Alex James Jun 18 '16 at 10:45
0

I wanted to to the similar thing, but i was thinking if the dbgrid doesn't know the colmuns by name (for this case), maybe one else (speaking of components) does know it allready.

In my case i use a fdquery -> Datasource -> DBgrid connection. The FDQuery knows the fields by name and by id.

So considering you use similar components you can do

dbgrid1.Columns[fdquery1.FieldByName('UnitPrice').Index].visible:=false;