ライブラリにあるFormに値をSet


JUN  2010-03-10 20:43:49  No: 37978

ちょっと伝えづらく解りづらいかもしれませんが、よろしくお願いします。

ライブラリにFormを作成してそのFormを各Plojectから使用したいと考えています。
ライブラリにあるLibForm.pasには多くの数値やコメントを書く場所があり、各Ploject毎に内容の違うものを数値やコメントにいれていきたいと考えています。

現在考えているのは、LibForm.pasに関数Setを用意して、
そのSetの引数を
Set(Def1、Def2、Def3、Def4、Def5:Integer;
    Float1、Float2、Float3  :Double;
    Comment1、Comment2、Comment3:String;);
としています。それをかくPlojectでセットしてあげます。

あまりに引数が多いのでどうかと思うのですが。

またもう一つの方法として、
各Plojectで
  LibForm  := LibForm.Create(nil);
  LibForm.Def1  :=  2;
  LibForm.Def2  :=  5;
       .
       .
       .
  LibForm.Comment3 := 'Test';

とする方法です。
どちらも何か手間を感じますし、普通ライブラリに置いといてこういったやりかたってどうなんでしょうか?

またわからないことはCreateしたものをどのタイミングでFreeにしてあげるかよくわからないです。これを値をセットしたあとFreeにしてしまうとLibFormの画面が閉じてしまういますし。
PlojectをDestroyのときにFreeにする感じですかね?なんか変なこと聞いてますかね...。初心者ですいません

みなさんはこういった状況でどのように作成しますか、意見聞かせてください。
よろしくお願いします。


JUN  2010-03-10 22:26:16  No: 37979

すいません二つ投稿してしまいました


HOta  2010-03-10 22:37:49  No: 37980

なさりたいことは、フォームの統一だと思うのですが、継承を使えばどうでしょう?
VCLのCreateは親が有れば親を消すときに一緒に消えます。親が無ければ自前で用意します。


JUN  2010-03-10 23:28:02  No: 37981

HOtaさん

ありがとうございます。
そうですね、継承すれば、使用できますね。

勉強不足で申し訳ないのですが、
LibFormを継承してLibForm内でCreateをしないと使用できませんか?

上で書いたように
  LibForm  := LibForm.Create(nil);
  LibForm.Def1  :=  2;
  LibForm.Def2  :=  5;

の部分を継承すると
  Def1  :=  2;
  Def2  :=  5;
こう書けて、コンパイルも通りますが。
実際実行するとDef1の部分でエラーになります。

これはCreateできていないからだと思うのですが、どのようにしなければならないのでしょうか?
この辺が理解不足なので教えて下さい。

よろしくお願いします。


D  2010-03-11 00:29:25  No: 37982

Formの雛形を作っておいて、色々なProjectから使いまわしたいということだと思うのですが。
(例えばプログラムのバージョン情報を表示するフォームなど)

>みなさんはこういった状況でどのように作成しますか、意見聞かせてください。

  私はそのような場合継承ではなく必要な変数の数だけグローバルな関数と手続きをいちいち書いています。

>Set(Def1、Def2、Def3、Def4、Def5:Integer;
>    Float1、Float2、Float3  :Double;
>    Comment1、Comment2、Comment3:String;);

なら、

interface

function  GetDef1: Integer;
procedure SetDef1(Value: Integer);
function  GetDef2: Integer;
procedure SetDef2(Value: Integer);

   ...

function  GetComment2: String;
procedure SetComment2(Value: String);
function  GetComment3: String;
procedure SetComment3(Value: String);

そして呼び出す側でいちいち汎用フォームをCreateしなくてもすむように、これらの関数・手続きの中で汎用フォームがCreateされていなかったらCreateするようにしています。

implementation

procedure CreateForm;
//フォームがCreateされていなければCreateする
var
  i: Integer;
begin
  if not(Assigned(LibForm)) then begin
    LibForm := TLibForm.Create(Application);
  end else begin
    for i := 0 to Screen.CustomFormCount-1 do begin
      if (Screen.CustomForms[i].ClassName = TLibForm.ClassName) then Exit;
    end;
    LibForm := TLibForm.Create(Application);
  end;
end;

function GetDef1: Integer;
begin
  CreateForm;
  Result := LibForm.Def1;
end;

procedure SetDef1(Value: Integer);
begin
  CreateForm;
  LibForm.Def1 := Value;
end;

  ...

こんな感じで。

>CreateしたものをどのタイミングでFreeにしてあげるかよくわからないです。
  ShowModalで表示させる場合は別ですが、汎用FormのOnCloseイベントでActionをcaFreeにすれば汎用フォームを閉じたら自動でFreeされるようになります。


JUN  2010-03-11 18:07:05  No: 37983

Dさん

サンプルありがとうございます。Assignで見ておけば、エラーが出たりすることなくちゃんとCreateできますね。

>Formの雛形を作っておいて、色々なProjectから使いまわしたいということ
>だと思うのですが。
そういうことです。

>ShowModalで表示させる場合は別ですが、汎用FormのOnCloseイベントで?
>ActionをcaFreeにすれば汎用フォームを閉じたら自動でFreeされるように
>なります。
とありますが例えばそれがただ単に
Free;
とするのはだめなんでしょうか?

また
各Plojectで
LibForm  := LibForm.Create(nil);
とし、そのPlojectではCreateするだけで、
LibFormのActionをcaFreeにしてあげれば各ProjectでCreateしたものはFreeになるということでよいのですよね?

よろしくお願いします。


D  2010-03-12 07:14:49  No: 37984

>とありますが例えばそれがただ単に
>Free;
>とするのはだめなんでしょうか?

procedure TLibForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Self.Free;
end;

ということでしょうか?
詳しいわけではないのでだめなのか良いのか断言できませんが、ヘルプには「コンポーネントのイベントハンドラ内で明示的にコンポーネントを解放したり,コンポーネントが所有するか,またはコンポーネントに含まれているコンポーネントのイベントハンドラからコンポーネントを解放したりしないようにしてください。」とありますので多分だめなんじゃないでしょうか。

また「フォームを解放するには,Release メソッドを使います。」ともあるので、なおさらだめなんじゃないでしょうか。

>LibForm  := LibForm.Create(nil);
>とし、そのPlojectではCreateするだけで、
>LibFormのActionをcaFreeにしてあげれば各ProjectでCreateしたものはFreeになるということでよいのですよね?

  Createするだけで、明示的にFree(Release)を呼ばずとも良いのを望むのならば

  LibForm := TLibForm.Create(Application);

とすれば良いのではないでしょうか。
Createの引数にApplicationを指定すればApplicationが終了するとき(プログラムが終了するとき)に自動でLibFormは解放されます。

ActionにcaFreeをセットするのはそれとはちょっと違います。
LibFormを閉じたときに解放するようにしたい場合です。

例えばButton1のOnClickイベントでLibFormをShowModalで表示するならLibFormを閉じるまで制御はもどってこないのでそのOnClickイベントで

  LibForm.Release;

とすることで呼び出し側で明示的に解放できます。
でもShowで表示するとすぐに戻ってきてしまうのでLibFormを解放するタイミングがつかめません。
そこでLibFormが閉じられたときに自分で解放してくれるようにする、というのがActionにcaFreeをセットする目的です。

例えばLibFormがバージョン情報を表示するフォームだと、閉じてしまえば必要のないフォームでしょうから閉じた時点で解放して欲しいのでActionをcaFreeにします。

LibFormが設定用のフォームなどで一度生成したらプログラム終了までは解放しないで置きたい場合ならActionにcaFreeはセットしません。

そんな感じです。


Dさん  2010-03-12 18:31:27  No: 37985

Dさん

私が多分こうではないかなと思っていたことがわかってとてもすっきりしました。
わかりやすい説明ありがとうございます。

私のほうで試してみたところ、caFreeでOnclose後に開放されていました。
たしかにバージョン情報ならそいつ自体で開放しちゃっていいですよね。

ただ私はいつもFreeを使用していたので、Releaseとの違いがいまいちよくわかりませんが、

>また「フォームを解放するには,Release メソッドを使います。」ともある
>ので、なおさらだめなんじゃないでしょうか。

と書いてあるようにLibForm.Release;を今回のケースでは使用し、
フォームの解放でなければ
LibForm.Free;でよいという理解でいいのでしょうか?


JUN  2010-03-12 18:32:28  No: 37986

すいません
自分の名前がDさんになっていました  ↑


D  2010-03-13 00:08:39  No: 37987

>ただ私はいつもFreeを使用していたので、Releaseとの違いがいまいちよくわかりませんが、

  そのへんは私もきっちり理解しているわけではないのでDelphiのヘルプを読んでみてください。
Releaseのヘルプには「フォームのイベントハンドラでは Free のかわりに Release を使う必要があります。そうしないと,アクセス違反例外が生成されることがあります。」とあります。
Freeを使った場合は、うまくいくこともあるけれど場合によってはアクセス違反のエラーが出ることもある、という結構やっかいなエラーの原因になってしまうということなのではないでしょうか。

かくいう私も思い当たる節があってコードを見直してみたらReleaseではなくFreeを使っていて、多分それが原因でたまにエラーが起きていたのがありました。

>フォームの解放でなければ
>LibForm.Free;でよいという理解でいいのでしょうか?

  そうだと思います。
というか、TCustomFormを継承していないコントロールにはReleaseメソッドはないのでそうするしかないという感じでしょうか。


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

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






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