1

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?

RickyBelmont
  • 619
  • 4
  • 11
  • Thank you for reminding (updated). I did your suggestion, see below, but I get the same Access Violation.. if Assigned(CanvassGrid) then begin FreeAndNil(CanvassGrid); end; – RickyBelmont Jul 30 '20 at 10:07
  • 1
    You must use a global variable to store the grid, so that its address is preserved between invocations of this method. That's the problem. (Currently, `TGrid1` (a very strange name of an object instance variable since it starts with `T`!) is a local variable of an unmanaged type, so it is uninitialized at the beginning of the method. Hence, it is a random pointer!) And then you should do `MyGrid.Free`, or -- even better -- `FreeAndNil(MyGrid)`. No need for `if Assigned(...)`, because `Free` does that check itself. – Andreas Rejbrand Jul 30 '20 at 10:08
  • Perfect! I used global variable, removed if assigned and now it works! Please post your answer and will mark it as answered. Many thanks. – RickyBelmont Jul 30 '20 at 10:16

1 Answers1

1

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.

Andreas Rejbrand
  • 105,602
  • 8
  • 282
  • 384
  • Sorry about confusions but already updated my question. Actually, I am using TeeGrid but I made it simpler TGrid here but it is the same. In less than 15 minutes this case is solved. Thank you so much! – RickyBelmont Jul 30 '20 at 10:21
  • @RickyBelmont: No problem! Glad I could help. – Andreas Rejbrand Jul 30 '20 at 10:22
  • One last thing. I just tried running it in iOSSimulator but after 8 clicks it freeze a while like 2-3 minutes or longer with more clicks, the same issue. Does this solution work straight with iOS and Android? – RickyBelmont Jul 30 '20 at 10:35
  • 1
    @RickyBelmont: I don't know iOS and Android, but most likely that issue is unrelated to the code discussed in this Q and A. Hence, we cannot help you without seeing your other code. – Andreas Rejbrand Jul 30 '20 at 10:39
  • You are right I might have to check again my query. It seems I need to limit the number of columns to be created at runtime because there is indeterminate number of columns created per click of the button. I have to limit it 10 columns only. This might solve my problem. Thank anyway. – RickyBelmont Jul 30 '20 at 22:11