How to access FieldName from FNCGrid's OnGetCellLayout

  1. I using a TTMSFNCGrid with the DatabaseAdapter. Is there a way to access the DatabaseAdapter's FieldName from inside the OnGetCellLayout event of the grid?

  2. Also, Is there a way to access the value of the data field in OnGetCellLayout?

I want to change the color of the cell depending of the name of the field or the value of the data field.

Hi,

Yes, you can access the FieldName with:

  TMSFNCGridDatabaseAdapter1.Columns[ACol - TMSFNCGrid1.FixedColumns].FieldName;

Or the field directly with

  TMSFNCGridDatabaseAdapter1.Columns[ACol - TMSFNCGrid1.FixedColumns].Field;

I must be missing something. When I try the first way (FieldName) it aways returns '' . The second way gives a nil for the field object. I am using the HTMLTemplate to display the fields, does that have something to do with it?

I found a partial way to make this work. AutoCreateColumns is false, so I create the columns. I was only setting the HTMLTemplate property when creating the column. I added the setting of the FieldName property also and now the FieldName property is not blank.

And I can also access a TField object as described above. But it appears that the TField object always points to the first record.

I need to be able to access the value of a cell from within the OnGetCellLayout event. For example if the payment status is unpaid I want to change the background color for that cell.

How can I accomplish that?

Thanks.

What you can do is set the active record before accessing the data, please see the complete same based on the biolife.xml database inside a TClientDataSet

type
  TTMSFNCGridDataBaseAdapterOpen = class(TTMSFNCGridDatabaseAdapter);

procedure TForm13.TMSFNCGrid1GetCellLayout(Sender: TObject; ACol, ARow: Integer;
  ALayout: TTMSFNCGridCellLayout; ACellState: TTMSFNCGridCellState);
var
  d: TTMSFNCGridDataBaseAdapterOpen;
  ar, c, r: Integer;
  f: TField;
  i: Integer;
begin
  r := ARow;

  if (r <= TMSFNCGrid1.FixedRows - 1) then
    Exit;

  c := ACol - TMSFNCGrid1.FixedColumns;

  if (c >= 0) and (c <= TMSFNCGrid1.Columns.Count - 1) then
  begin
    d := TTMSFNCGridDataBaseAdapterOpen(TMSFNCGridDatabaseAdapter1);
    if d.CheckDataSet then
    begin
      ar := d.DataLink.ActiveRecord;
      try
        d.SetActiveRecord(ARow);
        f := d.FieldAtColumn[c];
        if Assigned(f) then
        begin
          i := 0;
          if TryStrToInt(f.AsString, i) then
          begin
            if i > 50 then
            begin
              ALayout.Fill.Color := gcRed;
            end;
          end;
        end;
      finally
        d.DataLink.ActiveRecord := ar;
      end;
    end;
  end;
end;

I plugged the code above into my test program. The TField (f) is always nil. In my situation I create the columns manually and use a DatabaseAdapter. I also tried using the Autocreate = true for the columns, still got a nil for the TField object.

Also of note, is I create the TMSFNCGridDataBaseAdapter in code then set the appropriate properties. The grid is dropped on the form at design time, but everything else is created, set and connected at runtime.

We have tested the code here, which is working as expected. What you could also do is access the field from the dataset instead of going through the database adapter. It's the same field, you just need to access it with the correct column index.

For access outside of the database adapter, this is what I initially tried. The "row" accessed is always the first record in the query/table. I would need to use the ARow to somehow navigate to the correct record.

Maybe if you could sent a complete demo (I don't see one in your stock demos) for using the adapter this way I could see what I'm doing wrong.

Thanks.

There is a database adapter demo in the public documents\tmssoftware\TMS FNC UI Pack Demos folder. I have manipulated the TClientDataSet demo that uses the field approach and the code snippet I posted above.

UDemo.zip (922.3 KB)

Pieter,

Thanks for the Demo, that helped a lot. I found out why it wasn't working for me. It has to do with manually creating the columns and using the HTMLTemplate property for the columns. I have modified the demo you sent to reflect the problem. I'm not sure what to do next because I want to use the HTMLTemplate.

David

UDemoDavidProblem.zip (922 KB)

This is by design. The function FieldAtColumn ignores the FieldName & Field, because theoretically the HTMLTemplate can contain multiple fields. You can use the Field property instead, directly at column level:

f := d.Columns[c].Field;

That did the trick. Thanks.

Now I have an additional need concerning the OnGetCellLayout. I need to be able to see the value of other fields in the current record.

Example: if the "Payment Status" field value is 'Pending', change the Fill.color of the "Amount" field to Yellow.

You can just access the field directly on Dataset level, by using the field name or by using the correct index.

That works! Thanks.

Just so I understand the code correctly...

if d.CheckDataSet then <- what does this do?

ar := d.DataLink.ActiveRecord; <- This saves some (meaningless to me) table/grid position

d.SetActiveRecord(ARow); <- this "synchronizes" the grid to the current record in the data table

// I can now access the field object or the data table directly between the above line and the line below

d.DataLink.ActiveRecord := ar;<- restore the previous saved position


Is that correct?

Correct. ActiveRecord synchronisation is necessary to loop through the data of the visible rows, and then resets its back to the actually first record in the buffer. CheckDataSet is used to make sure the dataset is active, and connected to the grid database adapter