DelphiXE5のFreeでControlが消えない

解決


iOS初心者  2013-09-25 04:08:08  No: 45329

DelphiXE5  iOSアプリ(iPhone,iPad)にて2つのフォームを作成し、フォーム①でボタン1をクリックするとフォーム②に動的にコントロールを配置し、フォーム②のボタンでFreeを行いCloseさせているのですが、さらにそこからフォーム①のボタン2をクリックすると、フォーム②にボタン1で作成したコントロールが残ります。
Release、Destroyだと一見動作しますが、その後、他の処理を行っているとエラーがでて動かなくなってしまいます。
DelphiにはRelease、Destroyは使わないように書かれておりますので、
対処法をご教授頂けますと幸いです。

フォーム①
unit freebug;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls,freebug2;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  private
    { private 宣言 }
  public
    { public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.fmx}

procedure TForm1.Button1Click(Sender: TObject);
begin
    Form2.Start1(Self);
    Form2.Show;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
    Form2.Start2(Self);
    Form2.Show;
end;

end.

フォーム②
unit freebug2;

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
  FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.Edit,
  FMX.StdCtrls, FMX.ListBox, FMX.Layouts, FMX.Memo;

type
  TForm2 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { private 宣言 }
    zEdit:TMemo;
    zPanel:Tpanel;
  public
    { public 宣言 }
    procedure Start1(Sender: TObject);
    procedure Start2(Sender: TObject);
  end;

var
  Form2: TForm2;

implementation

{$R *.fmx}

procedure TForm2.Button1Click(Sender: TObject);
begin
    zPanel.Free;
    Close;
end;

procedure TForm2.Start1(Sender: TObject);
begin
    zPanel := TPanel.Create(Form2);
    zPanel.Parent := Form2;
    zEdit := TMemo.Create(Form2);
    zEdit.Parent := zPanel;
    zEdit.SetBounds(0, 0, 100, 50);
end;

procedure TForm2.Start2(Sender: TObject);
begin
    zPanel := TPanel.Create(Form2);
    zPanel.Parent := Form2;
    zEdit := TMemo.Create(Form2);
    zEdit.Parent := zPanel;
    zEdit.SetBounds(100, 0, 100, 50);
    zPanel.SetBounds(100, 100, 100, 50);
end;

end.


Harry  2013-09-25 04:48:19  No: 45330

FireMonkeyとかまったく分かりませんが、VCL的感覚で申しますと、
>    zEdit := TMemo.Create(Form2);
このTMemoはOwnerがForm2ですから、親コントロールのTPanelをFreeしても同時にFreeされません。

    zEdit := TMemo.Create(zPanel);
このようにすれば、zPanelがFreeされるときにzEditもFreeされます。(VCLと同じならば、ですが!)

>DelphiにはRelease、Destroyは使わないように書かれておりますので、
どこに書いてあるんですか? 差し支えなければ教えてください。


iOS初心者  2013-09-25 19:50:20  No: 45331

Harryさんご教授ありがとうございます。
zEdit := TMemo.Create(zPanel);
に変更しましたがFreeされませんでした。

>どこに書いてあるんですか? 差し支えなければ教えてください。
Relaseはすみません。どこで見たのか分からなくなってしまいました。
記憶上では非推奨だったと認識しています。
Destroyは
http://docwiki.embarcadero.com/Libraries/XE4/ja/Bde.DBTables.TBatchMove.Destroy
に記載されていることから使用しない方が良いと思っていました。


Harry  2013-09-26 06:50:19  No: 45332

自分の手元で確認できないのに、適当なことを言って済みませんでした。
ハッキリ言って私にはお手上げです。どなたか分かる方いませんか〜!

ヘルプを見てみましたが特にVCLと変わらず、TComponentはVCLと同一ですので、なぜ改善されないのか?です。
http://docwiki.embarcadero.com/Libraries/XE5/ja/FMX.Memo.TMemo.Create

これ、TPanelとTMemo、両方とも使える状態で残っちゃってるんですか?

で、、、なるべく一般的な書き方をしたほうがトラブルが少ないと思いますので、いくつかアドバイスをさせてください。
(懲りずに適当なこと言いますので、話半分でお願いします!)

・ 「フォーム①でボタン1をクリック」 → めっちゃ分かりにくいです。「Form1でButton1をクリック」と記述してください。
  ついでに言うと、丸数字は混乱の元なので一切使わない方が良いですよ。(1)とかどうですか。

・ Form2のStart1、Start2メソッドについて。
現在、↓このようになってますが、
  Form2.Start1(Self);
procedure TForm2.Start1(Sender: TObject);
引数が要らないなら、↓このように出来ます。さらに、括弧は省略してもかまいません。
  Form2.Start1();
procedure TForm2.Start1();

・ いくつかちょっと書き直してみますね。ぜひやってみて欲しいです。
procedure TForm2.Button1Click(Sender: TObject);
begin
  FreeAndNil(zPanel); // オブジェクトの変数を使い回すならFreeした後にnilを代入する。これにより、
                             // (1) nilならば空っぽであると判別できる。クラス内のオブジェクト変数の初期値はnilです。
                             // (2) 誤って何度もFreeしてしまうミスを防げる。nilをFreeしても、スルーされるだけなので。
  Close;
end;

procedure TForm2.Start1();
begin
  if Assigned(zPanel) then Exit; // zPanelが空っぽでない場合は処理しない。

  zPanel := TPanel.Create(Self); // TForm2クラスのメソッドなのでSelfと書けばForm2と同義。
  zPanel.Parent := Self;
  zEdit := TMemo.Create(zPanel); // OwnerをTPanelにしておく。
  zEdit.Parent := zPanel;
  zEdit.SetBounds(0, 0, 100, 50);
end;

>Relaseはすみません。どこで見たのか分からなくなってしまいました。
RelaseはVCLとは何もかも異なるようですね。VCLではフォームはFreeでなくRelaseを使用せよ、とされています。
Destroyはクラスの内部で使うためのものですから、むやみに呼び出しちゃいけないのです。

お役に立てなくて残念ですが、上の落書きをご笑覧いただければと思います。


iOS初心者  2013-09-27 22:49:53  No: 45333

Harryさん。多くのご教授ありがとうございます。
今後の参考にさせて頂きます。

>これ、TPanelとTMemo、両方とも使える状態で残っちゃってるんですか?

使える状態で残ってしまうのです。
ご教示頂きました処理も試してみましたがやはり残ってしまいました。

とりあえずReleaseであれば残らなくなりますので、
その後のエラーの原因を探した方が良いかもしれないですね。
(今回のサンプルには載せてません)


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加