別のフォームのクラスのPublic内に定義した関数を呼び出す際、
誤ってそのフォームをCreateせずに呼び出したにもかかわらず、
正常に動作します。別途以下のようなサンプルを作成し、実行
してみましたが、やはり、正常に動作しています。
Createをしなくても呼び出せるのでしょうか?
なお、Form2はプロジェクトオプションで、使用可能フォーム
の方へ移動しています。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
procedure FormShow(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses
Unit2;
{$R *.dfm}
procedure TForm1.FormShow(Sender: TObject);
begin
Form2:=nil;
end;
//本当は、Button1をClickする前に
//Form2:=TForm2.Create(Application);とするつもり
//だったのを、忘れてしまった。
procedure TForm1.Button1Click(Sender: TObject);
var
res : integer;
begin
res:=Form2.sub(100,200);
Label1.Caption:=IntToStr(res);
end;
end.
unit Unit2;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm2 = class(TForm)
Label1: TLabel;
private
{ Private declarations }
public
{ Public declarations }
function sub(a,b:integer):integer;
end;
var
Form2: TForm2;
implementation
{$R *.dfm}
function TForm2.sub(a,b:integer):integer;
begin
Result:=a+b;
end;
end.
プロジェクト->オプション->フォーム
TForm2が自動生成の対象になってるだけでしょう。
プロジェクト->ソースの表示
でプロジェクトファイル内で生成されていると思われます。
monaaさん、早速ありがとうございます。
自動生成の対象から、使用可能フォームへ移動しています。
プロジェクト->ソースの表示で
プロジェクトファイル内を表示しましたが、
以下のように表示されました。
program Project1;
uses
Forms,
Unit1 in 'Unit1.pas' {Form1},
Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
>実行してみましたが、やはり、正常に動作しています。
>Createをしなくても呼び出せるのでしょうか?
メソッドだけの呼び出しなら一応問題なし。
ただし、Form2にメンバー変数をおいて使ったトタンに
それは破綻する。
それはさんありがとうございます。
なるほど、subを
function TForm2.sub(a,b:integer):integer;
begin
Label1.Caption:='';
Result:=a+b;
end;
のように、Lable1.Caption:='';を追加するとこけました。
クラスもtype宣言なので、Createされて、はじめて、
メソッドも含め、すべてが使えるようになると思っていました。
なぜ問題なにのか?私にはよくわからないのですが、
Createしてから使うのが王道ですよね。
蛇足ですが、
「どこかのクラスに所属させたいが、今回のようにそのクラスの変数には触れない」
という関数は、クラスメソッドとすることでインスタンスを生成することなく使用できます。
定義はprocedureやfunctionの前に"class"と書き、使う際は変数ではなくクラス名から呼び出します。
今回の例で言えばこの様な感じです。
type
TForm2 = class(TForm)
...
class function sub(a,b:integer):integer; { static; }
end;
class function TForm2.sub(a,b:integer):integer;
begin
Result:=a+b;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
res : integer;
begin
res:=TForm2.sub(100,200); // Form2ではなくTForm2
Label1.Caption:=IntToStr(res);
end;
jazzinさん、
class定義を追加すると、Label1.Caption:='';で
コンパイルエラーが出ましたので以下のように修正しました。
class function TForm2.sub(a,b:integer):integer;
begin
//Label1.Caption:='';コンパイルエラーなのでコメントにした
Result:=a+b;
end;
私の方法でも、jazzinさんのクラスメソッドの方法でも、クラス変数に
触れない限りは、実行すると同じ結果が得られます。
しかし、私の方法では、subが自身をCreateされているか否か
わかならいので、触れてしまった場合、実行時エラーとなり、
将来的にバグが見つけにくくなりそうです。
クラスメソッドの方法では、コンパイル時エラー
となるので、バグになるまえに発見できると理解しました。
ありがとうございました。
ツイート | ![]() |