以下のような関数:checkCreatedFormを作成して
チェックしました。
あるフォームを
FormA:=TFormA.Create(Application);
FormA.Show;
として、FormA.FormCloseで
Action:=caFree;
とした後、
res:=checkCreatedForm(FormA);
を呼び出すと、resにTrueを返します。
フォーム生きているか、破棄されたかどうかを
どうやって知ればよいのでしょうか?
function checkCreatedForm(fm:TForm):boolean;
var
i : integer;
begin
Result:=False;
for i:=0 to Screen.FormCount-1 do begin
if Screen.Forms[i] = fm then begin
Result:=True;
break;
end;
end;
end;
FormA破棄時に通知するように設定します。
下記を参考にしてみてください。
type
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
FChildFrm: TForm;
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
public
end;
var
Form1: TForm1;
implementation
uses Unit2;
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
begin
if FChildFrm = nil then
begin
FChildFrm:= TForm2.Create(Self);
FChildFrm.FreeNotification(Self);
FChildFrm.Show;
end;
end;
procedure TForm1.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if (AComponent = FChildFrm) and (Operation = opRemove) then FChildFrm:= nil;
end;
Basserさん、早速ありがとうございます。
参考にさせていただき、.Notificationにて、FormAにnilを代入すると
res:=checkCreatedForm(FormA);
でFalseを返すようになりました。
ありがとうございました。
実は、FormA.FormCloseで
Action:=caFree;
とした後、もうひとつFormBをCreateしShow
した後にTrueを返すような現象が発生しました。
(FormBのCreate,Showをしなければ正しくFalseを返します)
調べてみましたところ、
FormA.NameとFormB.Nameを監視式に追加し、
FormB:=TFormB.Create(Application);
を実行した直後ブレイクポイントをかけて見ると、
FormB.Nameは'FormB'でいいのですが、
FormA.Nameも'FormB'となります。
よって、関数内のif文
if Screen.Forms[i] = fm then begin
で条件が一致しTrueになっています。
なぜFormAにもFormBが入ってしまうのか
分からないのです。
DelphiはDelphi2007 Pro です。
ソースプリーズ
> FormB:=TFormB.Create(Application);
これの前後に FormA.Close しているか書いてないし、情報不足。
FormA,FormB どっちも自動起動 off になってる?
TFormA も TFormB も TForm の派生クラスだから
> if Screen.Forms[i] = fm then begin
で fm が TForm なら区別できないのは当たり前です。
あー、言いたいのは
function checkCreatedForm(fm:TForm):boolean;
はまったく無力。Basser さんのように TFormA も TFormB もインスタンスを一つに
限定したいのなら
private
FChildFrmA: TFormA;
FChildFrmB: TFormB;
protected
のようにして、
If Assigend(FChildFrmA) then
で確認するとよいです。
これ正常に動作するだろ?
function checkCreatedForm(fm:TForm):boolean;
var
i : integer;
begin
Result:=False;
for i:=0 to Screen.FormCount-1 do begin
if Screen.Forms[i] = fm then begin
Result:=True;
break;
end;
end;
end;
>として、FormA.FormCloseで
>Action:=caFree;
>とした後、
>res:=checkCreatedForm(FormA);
>を呼び出すと、resにTrueを返します。
FormA.FormClose 内で res:=checkCreatedForm(FormA); を実行して
Trueを返すと言ってる気がするんだけど・・・
KHE00221 さん
>これ正常に動作するだろ?
ああああ、そうか! 失礼! 前言全面撤回します。
うーん、
>FormA.FormClose 内で res:=checkCreatedForm(FormA); を実行して
>Trueを返すと言ってる気がするんだけど・・・
だとすると、質問者がなにか勘違いしてますね。FormA.FormClose 内で実行するのは
ナンセンスですものね・・
ついでに、FormAは、クラスがTFormAでよいとして、FormBが別のクラス
TFormBなのかTFormAの別の変数なのかわからんな〜
そんなわけで、我はソースを要求する。
遅くなり、みなさんすみません。
・ソース以下3つ(unitMain,unitA,unitB)です。
・FormA,FormBは自動生成フォームから外しています。
・ButnAをクリックして、FormAを表示→閉じるし、
ButnChkをクリックするとFalseと表示します。
・ButnAをクリックして、FormAを表示→閉じるし、
ButnBをクリックして、FormBを表示し、
ButnChkをクリックするとTrueと表示します。
unit unitMain;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TFormMain = class(TForm)
ButnA: TButton;
ButnB: TButton;
ButnChk: TButton;
procedure ButnAClick(Sender: TObject);
procedure ButnBClick(Sender: TObject);
procedure ButnChkClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormMain: TFormMain;
implementation
uses
unitA,unitB;
{$R *.dfm}
function checkCreatedForm(fm:TForm):boolean;
var
i : integer;
begin
Result:=False;
for i:=0 to Screen.FormCount-1 do begin
if Screen.Forms[i] = fm then begin
Result:=True;
break;
end;
end;
end;
procedure TFormMain.ButnAClick(Sender: TObject);
begin
FormA:=TFormA.Create(Application);
FormA.Show;
end;
procedure TFormMain.ButnBClick(Sender: TObject);
begin
FormB:=TFormB.Create(Application);
FormB.Show;
end;
procedure TFormMain.ButnChkClick(Sender: TObject);
begin
if checkCreatedForm(FormA) = True then ShowMessage('True')
else ShowMessage('False');
end;
end.
unit unitA;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TFormA = class(TForm)
procedure FormClose(Sender: TObject; var Action: TCloseAction);
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormA: TFormA;
implementation
{$R *.dfm}
procedure TFormA.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;
end.
unit unitB;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TFormB = class(TForm)
private
{ Private declarations }
public
{ Public declarations }
end;
var
FormB: TFormB;
implementation
{$R *.dfm}
end.
FormAとFormBの指す値を表示してみるとわかりますが、
一度一方のFormを破棄してからFormを再作成すると同じ値になります。
つまりメモリ上の同じ領域が再利用されているわけですね。
変数FormAの値自体はクリアしていないので、チェックした時点で
FormA=FormB となっている。これがTrueになる理由です。
FormA を作成 (アドレス 10000)
FormB を作成 (アドレス 11000)
として両方Free後
FormB を作成すると アドレス (10000) に作成されてしまい
FormA と FormB が同じ アドレス になってしまうので
>なぜFormAにもFormBが入ってしまうのか
>分からないのです。
みないな事が起きます。
(*) アドレスは適当
Notificationでもいいですが
procedure TForm3.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action := caFree;
Form3 := nil;
end;
のように FormClose で自分自身を指す変数に nil を代入でも平気です
こんな感じにしてアドレスを見ればわかると思います。
procedure TForm1.Button1Click(Sender: TObject);
begin
Memo1.Lines.Clear;
Memo1.Lines.Add(IntToStr(Screen.FormCount));
if CheckCreatedForm(Form2) = True then Memo1.Lines.Add ('Form2Createed') else Memo1.Lines.Add ('Form2Free');
Memo1.Lines.Add(IntToStr(Integer(Form2)));
Memo1.Lines.Add(IntToStr(Screen.FormCount));
if CheckCreatedForm(Form3) = True then Memo1.Lines.Add ('Form3Createed') else Memo1.Lines.Add ('Form3Free');
Memo1.Lines.Add(IntToStr(Integer(Form3)));
end;
また、名前で判断させれば Free にさせなくても出来ます
function checkCreatedForm2(fm:String):boolean;
var
i : integer;
begin
Result:=False;
for i:=0 to Screen.FormCount-1 do
begin
if Screen.Forms[i].Name = fm then
begin
Result:=True;
break;
end;
end;
end;
if Assigned(Form3) = True then
begin
if CheckCreatedForm2(Form3.Name) = True then Memo1.Lines.Add ('Form3Createed') else Memo1.Lines.Add ('Form3Free');
end
else
begin
Memo1.Lines.Add ('Form3Free');
end;
tttさん、ありがとうございます。
>一度一方のFormを破棄してからFormを再作成すると同じ値になります。
異なるユニットの異なる変数なのに、そうなってしまうのですね。
KHE00221さん、ありがとうございます。
>のように FormClose で自分自身を指す変数に nil を代入でも平気です
それは知りませんでした。
自身をFormCloseしてる最中に、nilを代入すると、
「私は誰?」になってしまわないのですね。
>こんな感じにしてアドレスを見ればわかると思います。
なるほど、同じ値をさしています。
>また、名前で判断させれば Free にさせなくても出来ます
Nameにすれば、不変になるんですね。
これで判断してみます。
>if Assigned(Form3) = True then
これは何をしているのですか?
> >if Assigned(Form3) = True then
> これは何をしているのですか?
Help読みましょう
・・・さん
>Help読みましょう
すみません。
ヘルプで理解できました。
みなさんありがとうござました。
ツイート | ![]() |