Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delphi TFrame Create/Destroy

How to create (when I want to show it) and destroy (when I want to hide it) frames on the main TForm? Frames' align = alClient.

I tried this:

The form:

unit main;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, uFrame1, uFrame2;

type
  TFormMain = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    f1: TFrame1;
    f2: TFrame2;
  end;

var
  FormMain: TFormMain;

implementation

{$R *.dfm}

procedure TFormMain.FormCreate(Sender: TObject);
begin
  f1 := TFrame1.Create(Self);
  f1.Parent := Self;
end;

end.

First frame:

unit uFrame1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TFrame1 = class(TFrame)
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

implementation

{$R *.dfm}

uses main, uFrame2;

procedure TFrame1.btn1Click(Sender: TObject);
begin
  Self.Free;
  FormMain.f2 := TFrame2.Create(FormMain);
  FormMain.f2.Parent := FormMain;
end;

end.

Second frame:

unit uFrame2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;

type
  TFrame2 = class(TFrame)
    lbl1: TLabel;
    btn1: TButton;
    procedure btn1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

implementation

{$R *.dfm}

uses main, uFrame1;

procedure TFrame2.btn1Click(Sender: TObject);
begin
  Self.Free;
  FormMain.f1 := TFrame1.Create(FormMain);
  FormMain.f1.Parent := FormMain;
end;

end.

but it crashes with access vialataions when I click button on FrameStart or Frame1 (TForm FormCreate works fine i.e. it creates and shows FrameStart).

Delphi 7.

With the first frameWith the second frame

like image 724
Alex P. Avatar asked May 15 '12 20:05

Alex P.


1 Answers

You can't call Self.Free in those event handlers. When the event handler returns, the VCL code that executes next still uses a reference to an object that you just freed. And that's where the access violation comes from. If you had been running with FastMM in full debug mode then you would have been shown a helpful diagnostic message.

These frames will have to kill themselves in a more roundabout manner. Post a CM_RELEASE message to the frame asking it to call Free on the frame. You post the message, rather than sending it, so that all the in flight messages are processed first. You'll need to add a message handler to the frame to respond to the message.

like image 120
David Heffernan Avatar answered Sep 16 '22 20:09

David Heffernan