Fill Combobox in FNCDatagrid

i want to have a combobox in a column of the fncdatagrid.
This combobox should fill with the distinct Text-Values of this column.
if i edit this column i want to input a new text in the field or choose a text from the combobox, and then post this value to the underlying Database.
The grid is bound to a datasource with the gridDatabaseAdapter.

Is there a easy way to fill the combobox in the Datagrid?

For inserting the combobox i use the GridKosten.Columns[3].Editor:=getComboEdit;

You can try by using this code, involving OnGetInplaceEditorProperties (TTMSFNCDataGrid) and OnDataToField (TTMSFNCDataGridDatabaseAdapter):

procedure TForm1.FormCreate(Sender: TObject);
begin
  TMSFNCDataGrid1.Columns[3].Editor := getComboEdit;
  TMSFNCDataGrid1.Columns[2].AddSetting(gcsEditor);
end;

procedure TForm1.TMSFNCDataGrid1GetInplaceEditorProperties(Sender: TObject;
  ACell: TTMSFNCDataGridCellCoord; AInplaceEditor: TTMSFNCDataGridInplaceEditor;
  AInplaceEditorType: TTMSFNCDataGridInplaceEditorType);
var
  cbo: TTMSFNCDataGridComboEdit;
  sl: TStringList;
begin
  if (ACell.Column = 3) and (AInplaceEditor is TTMSFNCDataGridComboEdit) then
  begin
    cbo := (AInplaceEditor as TTMSFNCDataGridComboEdit);
    sl := TStringList.Create;
    try
      sl.Duplicates := TDuplicates.dupIgnore;
      sl.Sorted := True;
      TMSFNCDataGridDatabaseAdapter1.LoadValuesFromField(TMSFNCDataGridDatabaseAdapter1.FieldAtColumn[ACell.Column], sl);
      cbo.Items.Assign(sl);
    finally
      sl.Free;
    end;
  end;
end;

procedure TForm1.TMSFNCDataGridDatabaseAdapter1DataToField(Sender: TObject;
  ACell: TTMSFNCDataGridCellCoord; AMasterField, AField: TField;
  AInplaceEditor: TTMSFNCDataGridInplaceEditor;
  ACellValue: TTMSFNCDataGridCellValue; var Handled: Boolean);
var
  cbo: TTMSFNCDataGridComboEdit;
begin
  if (ACell.Column = 3) and (AInplaceEditor is TTMSFNCDataGridComboEdit) then
  begin
    cbo := (AInplaceEditor as TTMSFNCDataGridComboEdit);
    AField.AsString := cbo.Text;
    Handled := True;
  end;
end;

Thank you for the Code, but with this i dont get a combobox in Column 3 or any other column.
There is only a normal editField.
And what is the ```
TMSFNCDataGrid1.Columns[2].AddSetting(gcsEditor);

for.
The 3,4 and 5 Column should be a ComboField at the End.

 if (ACell.Column = 3) and (AInplaceEditor is TTMSFNCDataGridComboEdit) then
is not true at any time

This are all my Events of the Grid:

// Nachdem das Grid gezeichnet wurde
procedure TfrmKosten.grdKostenAfterDrawGrid(Sender: TObject; AGraphics: TTMSFNCGraphics; ARect: TRectF);
Var
  lUmsatz,lKosten: Double;
begin
  // Summe der Kosten Spalte RechBetrag in edtSumKosten eintragen
  lKosten:=grdKosten.ColumnSum(5);
  edtSumKosten.Text := FormatFloat('#,##0.00', lKosten) + ' €';

  // Summe der Rechnungsbeträge aus der Rechnungstabelle zusammenrechnen und in edtUmsatz schreiben
  DM.q1.sql.Clear;
  DM.q1.sql.Text := 'Select Sum(RBetrag) As Umsatz from Rechnungen ' + lWhere;
  DM.q1.Open;
  lUmsatz := DM.q1.FieldByName('Umsatz').AsFloat;
  DM.q1.Close;
  edtSumUmsatz.Text := FormatFloat('#,##0.00', lUmsatz) + ' €';

  // Differenz zwischen Umsatz und Kosten = Gewinn in edtSumGewinn eintragen
  edtGewinn.Text := FormatFloat('#,##0.00', lUmsatz-lKosten) + ' €';
end;

procedure TfrmKosten.grdKostenGetCellFormatting(Sender: TObject; ACell: TTMSFNCDataGridCellCoord; AData: TTMSFNCDataGridCellValue; var AFormatting: TTMSFNCDataGridDataFormatting;
  var AConvertSettings: TFormatSettings; var ACanFormat: Boolean);
begin
  if ACell.Row > 0 then
  begin
    if ACell.Column = 5 then
    begin
      ACanFormat := True;
      AFormatting.&Type := gdftFloat;
      AFormatting.Format := '0.00';
    end;
  end;
end;

procedure TfrmKosten.grdKostenGetCellLayout(Sender: TObject; ACell: TTMSFNCDataGridCell);
begin
  if ACell.Row > 0 then
    if ACell.Column in [0, 1, 5, 6] then
      ACell.Layout.TextAlign := gtaTrailing; // RechtsbĂĽndige Ausrichtung
end;



procedure TfrmKosten.grdKostenGetInplaceEditorProperties(Sender: TObject; ACell: TTMSFNCDataGridCellCoord;
  AInplaceEditor: TTMSFNCDataGridInplaceEditor; AInplaceEditorType: TTMSFNCDataGridInplaceEditorType);
var
  cbo: TTMSFNCDataGridComboEdit;
  sl: TStringList;
begin
  if (ACell.Column in [2,3,4]) and (AInplaceEditor is TTMSFNCDataGridComboEdit) then
  begin
    cbo := (AInplaceEditor as TTMSFNCDataGridComboEdit);
    sl := TStringList.Create;
    try
      sl.Duplicates := TDuplicates.dupIgnore;
      sl.Sorted := True;
      GridDatabaseAdapterKo.LoadValuesFromField(GridDatabaseAdapterKo.FieldAtColumn[ACell.Column], sl);
      cbo.Items.Assign(sl);
    finally
      sl.Free;
    end;
  end;
end;

procedure  TfrmKosten.GridDatabaseAdapterKoDataToField(Sender: TObject;
  ACell: TTMSFNCDataGridCellCoord; AMasterField, AField: TField;
  AInplaceEditor: TTMSFNCDataGridInplaceEditor;
  ACellValue: TTMSFNCDataGridCellValue; var Handled: Boolean);
var
  cbo: TTMSFNCDataGridComboEdit;
begin
  if (ACell.Column = 3) and (AInplaceEditor is TTMSFNCDataGridComboEdit) then
  begin
    cbo := (AInplaceEditor as TTMSFNCDataGridComboEdit);
    AField.AsString := cbo.Text;
    Handled := True;
  end;
end;

At Form.Create there ist this:

  GrdKosten.Columns[2].Editor := getComboBox;
  GrdKosten.Columns[3].Editor := getComboBox;
  GrdKosten.Columns[4].Editor := getComboBox;

  GrdKosten.Columns[2].AddSetting(gcsEditor);
  GrdKosten.Columns[3].AddSetting(gcsEditor);
  GrdKosten.Columns[4].AddSetting(gcsEditor);

a empty combobox appears if i click in one of this combofields.

found an error.
At Form.Create i used the wrong Name.

  GrdKosten.Columns[2].Editor := getComboEdit;
  GrdKosten.Columns[3].Editor := getComboEdit;
  GrdKosten.Columns[4].Editor := getComboEdit;

  GrdKosten.Columns[2].AddSetting(gcsEditor);
  GrdKosten.Columns[3].AddSetting(gcsEditor);
  GrdKosten.Columns[4].AddSetting(gcsEditor);

With this it works.

1 Like

Some Problems appear at work:
When the user cklick to a combofield, this is empty and when he click to an other field the data in the previos field is cleared and this emty field is saved.

One solution is to fill the Combofield.text with the data from the datarecordfield of this Column.
(Where do I enter this in previous code)

An other way is to only allow the user to use this feature if i make a new data record with a button NewDataRecord.
So how to activate this function only when i append a new datarecord, and deactivate it in normal readonly mode of the grid?

Whe connected to a dataset, it will always try to save the value of the field when navigating to another record when that record is in edit mode. Edit mode starts when editing a cell. So you can block editing mode with the OnCanEditCell event. You can indeed try to fill the value of the combobox before starting which can be done in the OnCellEditGetData. If the value is empty, you can prefill it to something else.

Thank you for your Help.
I set a Global Var GridEditMode to False at FormCreate.
With a Button "Insert" i append a NewLine and set the GridEditMode to True and then let the user edit the new line with 3 Columns.

Now the Problem:
in what event can i set the GridEditMode to False, so that the user cant edit in the Grid after editing the new line.

Supposedly, you can use dataset specific events such as OnAfterPost

That is possible because there are 6 Fields in one Row to change and every Field will do a post.
So i dont know whether the Customer is ready with the DataRow to change;

For the Moment i use a Button "AddRow" and change its caption to "Save" so the user have to press save if he is ready.
At AddRow i set EdtitMode of the Grid to True, When Save is Pressed i set the EditMode of the Grid to False. So the user should only in editMode when insert new Data.
But if he dont press the save Button than the EditMode still is on.

The only thing that could help where a RowChange Event, but if we are in the last row and end the input there is no new Row i think and therefor no RowChange.

With TTMSFNCDataGridDatabaseAdapter, the OnAfterPost is called when the row changes. Supposedly you are not using the database adapter?

Yes i use the TTMSFNCDataGridDatabaseAdapter but i thougth that it will not fire because i go to no other Row.
I will try this out.

1 Like

There is no event OnAfterPost in the TTMSFNCDataGridDatabaseAdapter see Picture.

The OnAfterPost is at TDataSet level

i cannot use AfterPost of the query to set editMode to false because it fires at the append row and then i cannot change anything in the new row. Also if i change a field in the row it will fire and i cannot edit the next field.

How are you adding a row? directly by using Append on dataset level? If so, isn't it sufficient to check the dataset state? Shouldn't it be in insert or append mode?

i do a query.Append and then fill some fields.

Supposedly, the dataset will be in another state than just editing. PLease check DataSet.State

This is the procedure for Adding a new record:

// ****************************************************************************
// * Neuen datensatz hinzufĂĽgen                                               *
// ****************************************************************************
procedure TfrmKosten.KostenAddLine;
begin
  if GridEditMode then
  begin
    GridEditMode := False; // EditMode wieder ausschalten da hinzufĂĽgen abgeschlossen ist
    btnAdd.Caption:='HinzufĂĽgen';
  end
  else
  begin
    GridEditMode := True;
    btnAdd.Caption:='Speichern';
    // Neuen datensatz in Kosten anlegen und vorbelegen
    grdKosten.Options.Editing.Enabled := True;

    DM.qKosten.Append;
    DM.qKosten.FieldByName('RechDatum').AsDateTime := Date;
    DM.qKosten.FieldByName('ZahlDatum').AsDateTime := Date;
    DM.qKosten.FieldByName('RechBetrag').AsFloat := 0;
    // DM.qKosten.FieldByName('USt').AsFloat := StrToInt(edtEMwst.Text);
    DM.qKosten.FieldByName('Bar').AsBoolean := False;

    // Nächste Belegnummer für KostenBeleg berechnen und eintragen
    DM.q1.sql.Clear;
    DM.q1.sql.Text := 'Select Max(BelegNr) As MaxBelegNr from Kosten';
    DM.q1.Open;
    // Neue BelegNr in Datensatz einfĂĽgen
    DM.qKosten.FieldByName('BelegNr').AsInteger := DM.q1.FieldByName('MaxBelegNr').AsInteger + 1;
    DM.q1.Close;

    // Datensatz speichern in DB
    DM.qKosten.Post;

   Var x:TDatasetState;
   x:= DM.qKosten.State; // The DatasetState here is dsBrowse
 
  end;
end;

You might want to track the previous state of the dataset during editing (before the post). If that differs from the actual state you know it has been in insert mode