Handling TButton as Custom Control in FNCDataGrid

I'm using FNCDataGrid with TButton as Custom Control.

for I := 1 to FNCDatGrid.RowCount - 1 do
 begin
   BT := TButton.Create(nil);
   BT.Caption := 'Delete';
   FNCDatGrid.Controls[7, I] := BT;
   FNCDatGrid.ManagedObjects[7, I] := BT;
 end;

After clicking TButton I'm deleting record and then I'm getting an Error: Control BT has no parent window. I don't know what could be the cause. Can you give me some hint, please.

Hi,

It could be possible that the button is still active while deleting the row where the button is on. Could you perhaps share some more details on this behavior? Do you call the dataset delete? From which event do you call the code? A possible workaround would be to handle this in a timer.

Hi,

Yes, indeed, Button is still active during deleting the row. I call the dataset delete. I use OnButtonClick to call the deleting procedure.

for I := 1 to FNCDatGrid.RowCount - 1 do
begin
  BT := TButton.Create(nil);
  BT.Caption := 'Delete';
  BT.OnClick := OnButtonClick;
  BT.Tag     := I;
  FNCDatGrid.Controls[7, I] := BT;
  FNCDatGrid.ManagedObjects[7, I] := BT;
end;
procedure OnButtonClick(Sender: TObject);
var
  CR: TTMSFNCDataGridCellCoord;
begin
  CR.Column := 7;
  CR.Row    := (Sender as TButton).Tag;
  GridPacjLegitym.FocusedCell := CR;
  GridDatabaseAdapter.SetActiveRecord(CR.Row);
  Dataset.Delete;
end;

So the issue is that when deleting a row at dataset level, potentially other rows could be affected. We implemented a way to make sure the data is properly loaded, but this means that the cell data is lost during the update. This actually also applies to sorting or filtering. When doing that operation the cell data (properties) are lost. This means the button you have connected to the grid is also lost. When binding to a database adapter you'll need to switch to a different technique.

procedure TForm9.TMSFNCDataGrid1CellButtonClick(Sender: TObject; AColumn,
  ARow: Integer);
var
  CR: TTMSFNCDataGridCellCoord;
begin
  CR := MakeCell(AColumn, ARow);
  TMSFNCDataGrid1.FocusedCell := CR;
  TMSFNCDataGridDatabaseAdapter1.SetActiveRecord(CR.Row);
  ClientDataSet1.Delete;
end;

procedure TForm9.TMSFNCDataGrid1GetCellClass(Sender: TObject; AColumn,
  ARow: Integer; var ACellClass: TTMSFNCDataGridCellClass);
var
  CR: TTMSFNCDataGridCellCoord;
begin
  if (AColumn = 7) and (ARow >= TMSFNCDataGrid1.FixedRowCount) then
    ACellClass := TTMSFNCDataGridButtonCell;
end;

procedure TForm9.TMSFNCDataGrid1GetCellProperties(Sender: TObject;
  ACell: TTMSFNCDataGridCell);
begin
  if ACell.IsButtonCell then
    ACell.AsButtonCell.Button.Caption := 'Delete';
end;

Unfortulatelly is still the same. Maybe third-party components spoil something. I'm using Almediadev StyleControls VCL components: PageViewer and PageControl. I used your demo Biolife ClientDataSet, to implement my method, and it works fine.
Biolife_ClientDataSet.zip (347.2 KB)

With the adapted demo I can indeed not reproduce the issue. Please let me know if I can be of assistance, or you have a reproducible case.

Not sure if you are using the latest version?

I'm using the latest version. I'll investigate the problem at my side. I'll try to prepare a reproducible case. Apart from my problem, different technique you suggested is very clever, I'll switch to it. Thanks.

1 Like

Hi,

I think I recognized my problem. Everything is ok if I working with default style - Windows. After chosing any style in Project Options - Application - Apperance, I'm getting an error: TButton has no parent window. I used your demo Biolife ClientDataSet to implement my problem. Use it please, switch to any style and try do delete records. I'm using the latest version of your components with Delphi 11 and Delphi 13.

Biolife_ClientDataSet.zip (347.3 KB)

Hi,

You can solve the issue with a timer, not ideal I know but a valid workaround nonetheless. I suppose something happens in the ButtonClick event after it has been triggered. Since removing the row also destroys the button, potential button specific messages are still processed causing the error.

procedure TForm130.Timer1Timer(Sender: TObject);
begin
  Timer1.Enabled := False;

  TMSFNCDataGrid1.FocusedCell := FFocusedCell;
  TMSFNCDataGridDatabaseAdapter1.SetActiveRecord(FFocusedCell.Row);

  ClientDataSet1.Delete;
end;

procedure TForm130.TMSFNCDataGrid1CellButtonClick(Sender: TObject; AColumn,
  ARow: Integer);
begin
  FFocusedCell := MakeCell(AColumn, ARow);
  Timer1.Enabled := True;
end;

Thanks a lot, now it works. The timer with Interval 50 is a pretty good solution.

1 Like