Link to home
Start Free TrialLog in
Avatar of Paer Toernell
Paer ToernellFlag for Thailand

asked on

Strange behavior when a form is closed

The program have two forms, MainForm and Subform. The Mainform Button1 creates new subforms. If a few subforms is created, when they are closed (and freed) the window behind get focus, BUT not if its the mainform . Why?

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,System.Contnrs, Unit2;

type
  TMainForm = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    Button2: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    List: TComponentList;
  end;

var
  MainForm: TMainForm;

implementation

{$R *.dfm}

procedure TMainForm.Button1Click(Sender: TObject);
  Var
   T : Tform;

begin
     List.OwnsObjects:=True;
     T:=TForm2.Create(Nil);
     List.Add(T);
     T.Show;
end;

procedure TMainForm.Button2Click(Sender: TObject);
  var
    Antal : Integer;

begin
    Antal:=List.Count;
    Memo1.Lines.Add('Forms Count '+IntToStr(Antal));
end;

procedure TMainForm.FormCreate(Sender: TObject);
begin
     ReportMemoryLeaksOnShutdown:=True;
     List:= TComponentList.Create;
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
    List.Free;
end;

end.

object MainForm: TMainForm
  Left = 0
  Top = 0
  Caption = 'MainForm'
  ClientHeight = 303
  ClientWidth = 641
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object Button1: TButton
    Left = 32
    Top = 16
    Width = 105
    Height = 25
    Caption = 'New Window'
    TabOrder = 0
    OnClick = Button1Click
  end
  object Memo1: TMemo
    Left = 192
    Top = 16
    Width = 433
    Height = 273
    Lines.Strings = (
      'Memo1')
    TabOrder = 1
  end
  object Button2: TButton
    Left = 32
    Top = 55
    Width = 105
    Height = 25
    Caption = 'Info'
    TabOrder = 2
    OnClick = Button2Click
  end
end

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TSubForm = class(TForm)
    Label1: TLabel;
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  SubForm: TSubForm;

implementation

{$R *.dfm}

procedure TSubForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
    Hide;
    Action := caFree;

end;

end.


object SubForm: TSubForm
  Left = 0
  Top = 0
  Caption = 'SubForm'
  ClientHeight = 299
  ClientWidth = 635
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnClose = FormClose
  PixelsPerInch = 96
  TextHeight = 13
  object Label1: TLabel
    Left = 120
    Top = 48
    Width = 60
    Height = 13
    Caption = 'Second form'
  end
end

Open in new window

Avatar of Geert G
Geert G
Flag of Belgium image

because of the nil in this line :
T:=TForm2.Create(Nil);

Open in new window


it should read
T:=TForm2.Create(Self);

Open in new window


there is no point in maintaining your own Componentlist
the Screen has this property

after you have created TForm2, you can find it like this in the screen object
this routine frees all TForm2 type forms

procedure TMainForm.CloseAllForm2(Sender: TObject);
var I: Integer;
  frm: TForm2;
begin
  for I := Screen.FormCount-1 downto 0 do 
    if Screen.Forms[I] is TForm2 then 
    begin
      frm := Screen.Forms[I] as TForm2;
      frm.Free;
    end;
end;

Open in new window

Avatar of Paer Toernell

ASKER

There is need for Component list because there will be more than one class of sub-forms and the user need to be able to navigate between them. I want them to be kept separate. By a different popuplists in mainform the user will navigate.

Questoin, if I use Mainform as owner (or componentlist) wont the subforms all be destroyed when the owner is destroyed?
you want a stay-on-top form which displays all the forms available in your app ?
you don't need an extra component to display that

if an owner is destroyed, then it first destroys all it's child components
that's just good housekeeping
ASKER CERTIFIED SOLUTION
Avatar of Geert G
Geert G
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
freeing a subform depends on the usage

if you would have an invoice form, with a floating form for some detail
there is no point in leaving the floating form open upon closing the invoice form
closing the floating form should not result in closing of the invoice form
Thanx, i added this function to extract a list of all form of a particula type, havet tested it yet but i think it will work.

procedure TfrmList.ListFormsOfType(AObjectList: TObjectList; aClass: TClass);
  Var
    I: Integer;

begin
  if AObjectList=Nil then begin
      AObjectList:=TObjectList.Create;
      AObjectList.OwnsObjects:=False;
  end;
  AObjectList.Clear;
  for I := 0 to Screen.FormCount -1 do
  Begin
    if True then
     if Screen.Forms[I] is aClass then Begin
        AObjectList.Add(Screen.Forms[I]);
     End;
  End;
end;

Open in new window