How to Create and Destroy TGrid at Runtime in Firemonkey — Android and iOS App Dev

127 views Asked by At

I have a TGrid created at runtime. The procedure requires that I should destroy TGrid before I can re-create at "add item and refresh" button click. I noticed that if I don't destroy TGrid before re-creating it, heavy overheads cause to freeze my App on over 8 or more times of doing it.

I tried the following codes but no avail:

procedure TformMain.AddItemRefreshClick(Sender: TObject);
var
  TGrid1 : TTGrid;
begin
  if Assigned(TGrid1) then
  begin
    TGrid1.DisposeOf;
    {TGrid1.Free;    Tried this also but not working}
    {TGrid1 := nil;  Tried this also but not working}
  end;

  TGrid1 := TTGrid.Create(formMain);
  With TGrid1 do
  begin
    Parent := formMain;
    Align := TAlignLayout.Client;
    Margins.Top := 5;
    Margins.Left := 5;
    Margins.Right := 5;
    Margins.Bottom := 5;
    ScrollBars.Visible := True;
    Header.Format.Font.Size := 11;
    Cells.Format.Font.Size := 11;
    TabOrder := 0;
  end;
end;

I am getting Access Violation at Address... Sounds heave error!

Is there a simpler way that I can create and destroy visual component like TGrid at runtime?

1

There are 1 answers

5
Andreas Rejbrand On BEST ANSWER

You must use a non-local variable to store the grid, so that its address is preserved between invocations of this method.

Currently, TGrid1 is a local variable. That essentially means that it is a variable that is created each time the routine is called. Its value isn't saved between invocations. And in Delphi, local variables of unmanaged types are not initialised, so that this is basically a random pointer. It is very dangerous to work with it! (And Assigned won't help you, since a random pointer might well be non-zero because it is ... well, random.)

(As an aside, the variable name TGrid1 is very confusing, since it starts with T. Usually only type names start with T.)

So instead add a private field to your form class:

  private
    FMyGrid: TGrid;

(I don't know that the class name is: in your Q, you write both TTeeGrid and TTGrid.)

Then you can do

procedure TformMain.AddItemRefreshClick(Sender: TObject);
begin

  // Free old grid
  FreeAndNil(FMyGrid);

  // Create new grid
  FMyGrid := TGrid.Create(formMain);
  with FMyGrid do
  begin
    Parent := formMain;
    Align := TAlignLayout.Client;
    Margins.Top := 5;
    Margins.Left := 5;
    Margins.Right := 5;
    Margins.Bottom := 5;
    ScrollBars.Visible := True;
    Header.Format.Font.Size := 11;
    Cells.Format.Font.Size := 11;
    TabOrder := 0;
  end;

end;

FreeAndNil(FMyGrid) basically does FMyGrid.Free and also sets the pointer to nil so that you won't end up with a dangling pointer in case the TGrid.Create constructor should raise an exception.

Furthermore, there is no need for the if Assigned(FMyGrid) then part, because FMyGrid.Free does that check.

Also notice that FMyGrid now is a member of a class, and as such it is initialised to nil from the beginning.