動的に生成したフォームへの値の渡し方

解決


老かも  2009-11-02 06:53:28  No: 36046

再びお世話になります。よろしくお願いします。つまずいているのは次の通りです。
1,メインフォームとサブフォームはデザイン時に設定。
2,実行時にサブフォームの複製を何個か生成する。(全くのコピー)。
3,元のサブフォームと複製したフォームにそれぞれメインフォームから異なっ  た値を渡す。
4,具体的には、各サブフォーム上にチャートを置き、メインフォームで作成し  たデータを種類別に各サブフォームのグラフに表示させるというものです。
  データ1はサブフォーム0へ、データ2はサブフォーム1へという感じです。
コードは以下の通りです。

****メインフォーム於いて******

....
implementation
uses
 Subfrm (サブフォーム側ではMainfrm)
var
 n     : integer; // サブのコピー生成数
 SForm : TSubfrm; //サブのコピー
 K     : integer; //データカウンタ

//サブのコピー生成 //
procedure TForm1.CloneClick(Sender: TObject);
begin
 SForm := TSubfrm.Create(Application);
 with SForm do
 begin
   Width   := Subfrm. Width;
   Height  := Subfrm.Height;
   Name    := 'Subfrm' + IntToStr(n);
   Caption := Name;
 end;
   SForm.Show;
   Inc(n);
end;

//サブフォームに渡す //
procedure TForm1.TESTClick(Sender: TObject);
var
 i     : Integer;
 FName : string; //複製フォーム名
begin
 for i := 0 to Screen.FormCount-1 do
 begin
   FName := 'SForm' + IntToStr(i);
   if Screen.Forms[i].Name = FName then
     SForm.AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続
   end;
.......

これでは上手くいきません。呼び出すフォームがこれでは確定できないからだと思うのですが、確定する方法が解りません。
そもそも、この思想ではダメなのでしょうか?
どなたかよろしくお願いします。


igy  2009-11-02 07:11:30  No: 36047

>   Name    := 'Subfrm' + IntToStr(n);

>   FName := 'SForm' + IntToStr(i);
で一致してないとか・・・


igy  2009-11-02 07:15:36  No: 36048

あと、

for i := 0 to Screen.FormCount-1 do
 begin
    for j := 1 to n - 1 do   // 追加
    begin                    // 追加
       FName := 'SForm' + IntToStr(j);
       if Screen.Forms[i].Name = FName then
         SForm.AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続
    end;                     // 追加
 end;

のようにしてほうがいいかもしれません。


tor  2009-11-02 07:34:27  No: 36049

そもそもSFormという変数が一個しかないので、その一つにしかデータを渡せていないような…

var
  SForms: array of TSubfrm;
...
SetLength(SForms, n + 1);
SForms[n] := TSubfrm.Create(Application);

のように配列にして入れておけば、いちいちNameで検索しなくても
for i := 0 to Length(SForms) do SForms[i].AddPoint(...);
とできるんじゃないでしょうか。


igy  2009-11-02 07:58:15  No: 36050

先ほどの訂正です。
コメント
  // 変更:i を j に
を追加しました。

for i := 0 to Screen.FormCount-1 do
 begin
    for j := 1 to n - 1 do   // 追加
    begin                    // 追加
       FName := 'SForm' + IntToStr(j);  // 変更:i を j に
       if Screen.Forms[i].Name = FName then
         SForm.AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続
    end;                     // 追加
 end;


老かも  2009-11-02 08:01:40  No: 36051

igyさま、早速有り難うございます。
1,
  >   Name    := 'Subfrm' + IntToStr(n);と
  >   FName := 'SForm' + IntToStr(i);一致してないとか
  済みません、コピペミスでした。
2,ご指摘の通り早速試してみたのですが、例えば3枚フォームを作ると3枚目  だけに、3系列が表示されてしまいます。

>  if Screen.Forms[i].Name = FName then
>     SForm.AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続

この部分ですが、名前が一致してもやはり、呼び出すフォームが決まらないた
めなのか、最後のフォームにまとめて書き込んでいるようです。
うーむ!特定する方法はあるはずなんでしょうが???


老かも  2009-11-02 08:41:09  No: 36052

torさま、igyさまほんとに有り難うございます。
torさまのご指摘の通り配列に入れることで解決しました。助かりました。
最近やっとクラスについて解りだしたところで、元のサブフォームのインスタンスに名前を付ければ、名前で管理できるので、配列にしなくてもと考えた訳です。わざわざ教えて頂いていて、大変恐縮なのですが、やはり配列にするしか解決方法は無いのでしょうか?今回は全く同じ機能のクローンでしたが、少しずつ機能を違えた場合でも配列で解決できるのでしょうか?そもそも、このような疑問が、解ってない証拠かもしれませんが。

ご教授下されば幸いです。よろしくお願いいたします。


igy  2009-11-02 08:56:43  No: 36053

>>  if Screen.Forms[i].Name = FName then
>>     SForm.AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続
>
>この部分ですが、名前が一致してもやはり、呼び出すフォームが決まらないた
>めなのか、最後のフォームにまとめて書き込んでいるようです。

で、
>     SForm.AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続

     Screen.Forms[i].AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続

にしたらよさそうな気もします。


igy  2009-11-02 09:02:43  No: 36054

>     Screen.Forms[i].AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続
>
>にしたらよさそうな気もします。

確認してませんが、もしエラーが出るようなら、
     TSubfrm(Screen.Forms[i]).AddPoint(K-1,Random(100),clRed); //  サブのAddPoint手続
のような感じにしないといけないかもしれません。


tor  2009-11-02 11:12:17  No: 36055

> 元のサブフォームのインスタンスに名前を付ければ、名前で管理できるので、配列にしなくてもと考えた訳です。
NameというのはCaptionと同じく単なる文字列ですから、Nameで検索できたとしても
プログラマが自分でそのフォームの型を特定して変換してやるという手間をかけないとメソッドにはアクセスできません。
手間が増えるだけで、大してメリットはなさそうですね。

特定の型のフォームに一括して処理を行いたいだけなら
for i := 0 to Screen.FormCount - 1 do
  if Screen.Forms[i] is TSubfrm then
    (Screen.Forms[i] as TSubfrm).AddPoint(...)
のようにすれば目的は達せられます。

> 今回は全く同じ機能のクローンでしたが、少しずつ機能を違えた場合でも配列で解決できるのでしょうか?
継承を適切に使えば解決できると思いますよ。


HOta  2009-11-02 16:42:08  No: 36056

生成したフォームをリストで管理すれば、いいのではないでしょうか。


老かも  2009-11-02 18:35:44  No: 36057

皆様貴重なアドバイスほんとに有り難うございます。最近はdelphi解説書の数もめっきり減っているようで、私の様な初心者にとっては、このサイトでの皆さんのアドバイスは大変貴重なものです。
*igyさま、度々有り難うございます。
  >Screen.Forms[i].AddPoint(K-1,Random(100),clRed); //  サブの・・・
  は試してみていたのですが、やはりエラーでダメでした。
  >TSubfrm(Screen.Forms[i]).AddPoint(K-1,Random(100),clRed); //  
  こうすればいいんですね。試したところGOODでした。すごい!Screenの意味  がよく解ってなかったみたいです。勉強します。有り難うございました。
*torさま、解決策を教えて頂いておきながら、ほんとに申し訳ありません。
  >(Screen.Forms[i] as TSubfrm).AddPoint(...)
  そうか、こうすればいいんですね。でも、確かに配列にした方が、すっきり  解りやすいです。ほんとに有り難うございました。
*HOtaさま。アドバイス有り難うございます。
  実は自分でもLISTで管理を試してみていたのですが、どういう訳か上手くい  かなくて、投稿させて頂いた次第でした。
  .....
  List := TList.Create;
  .....
  List.Add(SubFrm);
  .....
  Subfrm(List(i)).Addpoint....
 と言う具合にやってみたのですが、途中のコードがミスっていたのか、上手  くいきませんでした。でも、考え方としてLISTで管理というやり方もあるん  ですね。もう少し検証してみます。有り難うございました。

皆様ほんとに有り難うございました。おかげで解決できました。最後にもう一つお願いがあります。今回の投稿で、私のレベルを推測して頂くことが出来たのではないかと思います。全くの入門から、少し中に言ったところと思っております。そんな私に、お奨めの解説書を教えて頂けないでしょうか?delphi(ObjectPascal)の機能、構造を俯瞰出来るようなものと言ったらいいのでしょうか。HelpやエンバカのHPのリファレンスを観てもどうも解りにくく、冒頭書きましたように、解説書も少なく(かなり検索して捜してみたのですが)この先更に先に行くには、良い参考書が必要と思っている次第です。
何か、お奨めがございましたら、よろしくお願いいたします。


D  2009-11-03 03:57:18  No: 36058

> Subfrm(List(i)).Addpoint....

  Subfrm(List[i]).AddPoint...

これでうまくいくのではないかと思います。
こちらでテストした結果ではうまくいっています。

あと、Nameプロパティから特定するやり方としてFindCompoentを使う手もあります。

procedure TForm1.TESTClick(Sender: TObject);
var
  i: Integer;
  l_Component: TComponent;
begin
  for i := 0 to Application.ComponentCount-1 do begin
    l_Component := Application.FindComponent('Subfrm' + IntToStr(i));
    if (l_Component is TSubfrm) then begin
      TSubfrm(l_Component).AddPoint(K-1, Random(100), clRed); //サブのAddPoint手続
    end;
  end;
end;

参考までに。


老かも  2009-11-03 05:24:41  No: 36059

Dさま、アドバイス有り難うございます。
FindCompoentが使えるんですね。そうかー。コンポーネントの配列化で使ったことがありますが、ここで使えるとは。
やはり、サンプルのコピペばっかりで乗り切ってくるとダメですね。応用が利きません。判ってやらないと。いつまでたっても初心者マークで。
アドバイス有り難うございました。


igy  2009-11-03 07:21:01  No: 36060

>お奨めの解説書を教えて頂けないでしょうか?

現在、入手できるかわかりませんが、

Delphi関連書籍
http://edn.embarcadero.com/article/33535

のなかから挙げると・・・

・Delphi 6 プログラミングバイブル 
・Delphiコンポーネント設計&開発 完全解説

とか。

あとは、
・Delphiオブジェクト指向プログラミング
  塚越 一雄 (著) 
など。


老かも  2009-11-03 10:08:31  No: 36061

igyさま、早速有り難うございます。
ご照会頂いた物は、手元に持ってないものばかりです。早速購入したいと思います。
改めて、有り難うございました。


D  2009-11-03 11:12:31  No: 36062

TListを使った場合

>> Subfrm(List(i)).Addpoint....
>
>  Subfrm(List[i]).AddPoint...

  ではなくて

  TSubfrm(List[i]).AddPoint...

の間違いでした。失礼しました。


老かも  2009-11-03 17:35:59  No: 36063

Dさま、訂正有り難うございます。私のテストコードも同じでした。ここがひっかかっていたんですね。
お陰でいろいろなやり方があることがよーく判りました。最近になってやっとdelphi(ObjectPascal)が美しい言語、だと言われる所以が判ってきたよう思います。
皆様、お世話になりました。有り難うございました。
これにて一件落着とさせて頂きます。


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

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






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