1

Let's say, I have a set of TField objects and want to change their visibility in some DBGrid dynamically. I also want to allow users to change column order in this DBGrid, and have some fixed columns.

I know proper way to hide/show columns on DBGrid, but there is a big, big design flaw in VCL: having Column object, one can travel to it's Field object, but cannot find way back.

All I want is just kind of Column property inside Field object, so I can type something like this:

Field.Column.Visible := False;

and hide any column inside DBGrid with assigned Columns property.

I know I can just create HashSet or Collection with Columns and quickly find corresponding columns, but is there exist more straight way to do this?

Community
  • 1
  • 1
Danatela
  • 349
  • 8
  • 28
  • 4
    There is absolutely no way why a TField should know about a visual representation like a TDBGrid or a TColumn. What would you expect from such a property when the dataset and that field is visible in more than one grid at the same time? – Uwe Raabe Jul 09 '15 at 07:45
  • Hmm... I would hide or show that column in all connected grids. – Danatela Jul 09 '15 at 08:17
  • Property `Field.Visible` determines whether the field appears in a data grid. I do not understand why it can not be used. – Val Marinov Jul 09 '15 at 09:21
  • @ValMarinov yep it can... if columns are not stored. Though I already found a solution and writing answer now. – Danatela Jul 09 '15 at 09:27
  • Actually the TColumn doesn't store a link to the TField instance either. It only stores the Fieldname and does a lookup for that to get the field instance. This is not significantly more work than iterating the columns with the Fieldname to find the corresponding column for a field in a grid. – Uwe Raabe Jul 09 '15 at 11:12

2 Answers2

6

If column are stored, may use something like:

function FindFieldColumn(Grid : TDBGrid; const FieldName: String):  TColumn;
var
  i: Integer;
begin
  Result := nil;
  for i := 0 to Grid.Columns.Count - 1 do
    if AnsiCompareText(Grid.Columns[i].FieldName, FieldName) = 0 then
      begin
         Result := Grid.Columns[i];
         Break;
      end;
end;

procedure SetVisibleColumn(Grid : TDBGrid; AFieldName : string; AVisible : boolean);
var
  Column : TColumn;
begin
  Column := FindFieldColumn(Grid,AFieldName);
  if Assigned(Column) then
     Column.Visible := AVisible;
end; 

Call

SetVisibleColumn(MyGrid,MyField.Name, myField.Visible);
Val Marinov
  • 2,705
  • 17
  • 22
  • Thanks Val, but I consider such solution is expensive. – Danatela Jul 09 '15 at 10:02
  • 1
    Not more expensive than code running due to mouse movement. – NGLN Jul 09 '15 at 10:51
  • @NGLN if I have 20 columns and want to dynamically hide half of them, I will run this cycle 10 times and execute string comparison at least 100 times. I don't want to have any visual delays, and computers in my company are slow enough to make it noticeable. – Danatela Jul 10 '15 at 03:06
  • 2
    @Danatela In your answer in the first decision you use OnDrawColumnCell. How many times OnDrawColumnCell will be executed? Actualy the code above should be executed only when DBGrid is created and when the user changes visibility of fields. – Val Marinov Jul 10 '15 at 06:46
  • Code cost <> visual lag. – NGLN Jul 10 '15 at 06:47
  • @Val I just realized that and did some optimizations... Though I consider now that creating HashSet was the greatest idea. – Danatela Jul 10 '15 at 08:46
1

@UweRaabe has already explained that what you're asking is not in general possible, basically because DGGrids know which fields they're connected to but not vice versa. So to do what you want, you're going to have to code it yourself, if you're using persistent columns in your grid.

I don't know whether you're aware, but for the benefit of other readers, a TField has Visible and Index properties.

A Field's Visible property can be used by DBGrids to control whether the field's Column in the DBGrid is visible, but only when the Columns are auto-created by setting the grid's DefaultFields to true.

Likewise, a Field's Index defines its column number in DBGrids, but again only when the DBGrid's DefaultFields is True.

In a DBGrid wih DefaultFields = True, you can change the visibility an column number of a Field at run-time.

So, although you can't centrally control the visibility and number of a column in a DBGrid which has persistent Columns, you can if you set DefaultFields to True and leave it to the grid(s) to create the columns.

MartynA
  • 30,454
  • 4
  • 32
  • 73