喫茶XRAYトップページ


[11137] コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/22 (土) 22:52:45 taki
コンポーネントの登録先はFormなんですね。

複数個のコンポーネントを動的に生成する時、配列を用意して

PanelArray[i] := TPanel.Create(Self);

なんて記述するので、てっきり配列に登録するんだと思っていました。

複数個のコンポーネントを生成後、配列にnilを代入してもコンポーネントは
消えないし、クリックすると反応するし。

http://mrxray.on.coocan.jp/Delphi/plSamples/161_CreateComponent_List.htm

02_複数のパネルを作成 ( 配列を使用 ) の一部を使いテストしました。

Button2はForm1のControlCountを表示します。
パネルを生成する前は4で、生成後は9になります。ここに登録されるんですね。

Button3は配列にnilを代入しています。
それでも、生成したpanelをクリックすると色が変わります。


unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    Button2: TButton;
    Label1: TLabel;
    Button3: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
    procedure Button3Click(Sender: TObject);
  private
    { Private 宣言 }
  //作成する個数が決まっている場合用の配列(静的配列)
    FPanelArray1 : array[0..4] of TPanel;
    procedure PanelClickEvent(Sender : TObject);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  LWidth : Integer;
  LHeight: Integer;
  i      : Integer;
begin
  //パネルを作成
  LWidth  := 100;
  LHeight := 28;

  for i := 0 to High(FPanelArray1) do begin
    FPanelArray1[i] := TPanel.Create(Self);

    //Parent(配置場所)をSelf,つまりこのForm1とする
    //これがないと配置場所不明で表示されない
    FPanelArray1[i].Parent   := Self;

    FPanelArray1[i].Left     := 90;
    FPanelArray1[i].Width    := LWidth;
    FPanelArray1[i].Height   := LHeight;
    FPanelArray1[i].Top      := 40 + (LHeight + 3) * (i - 1);
    FPanelArray1[i].Color    := clSilver;
    FPanelArray1[i].Caption  := 'Panel ' + IntToStr(i + 1);

    //これがないとTPanelのColorプロパティの設定が反映されない場合がある
    FPanelArray1[i].ParentBackground := False;

    //OnClickイベントをPanelClickEventというメソッドに割当てる
    FPanelArray1[i].OnClick := PanelClickEvent;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  label1.Caption := inttostr(Self.ControlCount);
end;

procedure TForm1.Button3Click(Sender: TObject);
var
  i:integer;
begin
  for i := 0 to High(FPanelArray1) do begin
    FPanelArray1[i] := nil;
  end;
end;

procedure TForm1.PanelClickEvent(Sender: TObject);
begin
  TPanel(Sender).Color := RGB(Random(255), Random(255), Random(255));
end;

end.

でも、Panelを簡単に操作するにはFPanelArray1はやはり必要ですね。


[11139] Re:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/23 (日) 08:41:14 Mr.XRAY
▼ takiさん
> Button3は配列にnilを代入しています。
> それでも、生成したpanelをクリックすると色が変わります。


ですね.
配列はあくまで管理用です.
コンポーネントのインスタンス(実体) そのものは存在しますから.

> でも、Panelを簡単に操作するにはFPanelArray1はやはり必要ですね。

です.
いちいちループで操作目的のコンポーネントを探すよりは便利かと.


[11140] Re2:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/23 (日) 10:18:20 taki
▼ Mr.XRAYさん
> ▼ takiさん
> > Button3は配列にnilを代入しています。
> > それでも、生成したpanelをクリックすると色が変わります。
>
> ですね.
> 配列はあくまで管理用です.
> コンポーネントのインスタンス(実体) そのものは存在しますから.
>
> > でも、Panelを簡単に操作するにはFPanelArray1はやはり必要ですね。
>
> です.
> いちいちループで操作目的のコンポーネントを探すよりは便利かと.


Formという教室があり、そこにはコンポーネントという学生が存在する。
そこへ転入生という学生が入ってくる。
Formの名簿はControls[]であり、転入生の名簿はFPanelArray1[]という感じ
でしょうか。
両方ともただの名簿なんですね。学生はそこにいるのだから。

まあ、大学の講義には実体の無い学生もいましたがね。


[11141] Re3:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/23 (日) 11:11:31 Mr.XRAY
▼ takiさん

> Formという教室があり、そこにはコンポーネントという学生が存在する。
> そこへ転入生という学生が入ってくる。
> Formの名簿はControls[]であり、転入生の名簿はFPanelArray1[]という感じ
> でしょうか。
> 両方ともただの名簿なんですね。学生はそこにいるのだから。


taki さん,うまい !! 座布団 2 枚 !!
 
> まあ、大学の講義には実体の無い学生もいましたがね。

ギクッ...
彼の大島みち子さんが,大学に入学して,大学の授業には失望した.
なんてことを日記に書いていました.

今日は,本当に穏やかな休日です.
お花見も終わったし.


[11142] Re3:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/23 (日) 11:15:20 Mr.XRAY
▼ takiさん

> Formの名簿はControls[]であり、転入生の名簿はFPanelArray1[]という感じ

へへへっ,これ使える.
サンプルの記事の説明用に使わせてね.


[11143] Re:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/24 (月) 01:01:44 taka
▼ takiさん
> Button3は配列にnilを代入しています。
> それでも、生成したpanelをクリックすると色が変わります。


Button3変数
変数は ここにありますよという、封筒の宛先にすぎませんので
Button3 にnilをいれても 封筒の宛先を砂消しで消すことにしかなりませんので宛先の住所地はなくなりません。
Button3本体を消滅させるのは巡航ミサイルの Free 手続きです
ミサイルを飛ばした後は、だれが撃ったかわからないようにButton3変数を焼却します

変数(封筒)がなくても、建物にはなんら影響はありません
封筒がなくても住所地建物は存在します。廃墟の場合もあります。

子コントロールをFreeしたあとに 間違って呼び出すと 宛先不明・不在でエラーとして返送されますので
念のためnilを代入しておきます

> Delphiヘルプより引用
> アプリケーションでは RemoveControl メソッドを直接呼び出さないでください。
> 実行時には,子コントロールの Parent プロパティを使って Controls 配列から削除できます。


手動でコントロールの消滅を強制執行したい場合は
コントロール.Free;

if Not(csDestroyingHandle in ControlState) And Assigned(Button3) then
begin
  FreeAndNil(Button3);
end;

PanelArray[i]に登録したものを動的に破棄したい場合は、
if Not(csDestroyingHandle in ControlState) And Assigned(PanelArray[i]) then
begin
  // try exceptでくくったほうが安全
  FreeAndNil(PanelArray[i]);
 // 同じ配列内で親子関係のパネルがネストされている場合は注意
end;



[11144] Re2:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/24 (月) 08:39:42 Mr.XRAY
▼ takaさん
>
> if Not(csDestroyingHandle in ControlState) And Assigned(Button3) then


おおっ !

>procedure TForm1.Button3Click(Sender: TObject);

では配列要素を削除しているということですから,
その時に実体である,基本的には生成したコンポーネントも破棄ですね.

で,サンプルとしては掲載してはいますが,
このように複数の同じコンポーネントを生成して管理する場合,
配列よりもリストの方がいいと思います.
TComponentList, TList<T> の方が扱いやすいと思いますね.

記事の履歴は削除してしまいましたが,
この配列を使用するサンプルは後から追加した記憶があります.

検索エンジンで「コンポーネント 配列」というのがあり,
このページがヒットすれば,TComponentList のところも見てくれるのではないか,
という期待感から掲載したつもりです.

ただし,今回のような,
入れ物と中身である実体の動作を確認するには,配列はいい見本かも知れません.


[11145] Re2:コンポーネントの登録先はForm … 何を今さら。返信 削除
2017/4/24 (月) 12:43:03 taki
▼ takaさん

> Button3変数
> 変数は ここにありますよという、封筒の宛先にすぎませんので
> Button3 にnilをいれても 封筒の宛先を砂消しで消すことにしかなりませんので宛先の住所地はなくなりません。
> Button3本体を消滅させるのは巡航ミサイルの Free 手続きです
> ミサイルを飛ばした後は、だれが撃ったかわからないようにButton3変数を焼却します


 
> PanelArray[i]に登録したものを動的に破棄したい場合は、
> if Not(csDestroyingHandle in ControlState) And Assigned(PanelArray[i]) then
> begin
>   // try exceptでくくったほうが安全
>   FreeAndNil(PanelArray[i]);
>  // 同じ配列内で親子関係のパネルがネストされている場合は注意
> end;
>


配列にnilを代入していたコードを以下のように変更しました。
procedure TForm1.Button3Click(Sender: TObject);
var
  i:integer;
begin
  for i := 0 to High(FPanelArray1) do begin
    if Not(csDestroyingHandle in ControlState) And Assigned(FPanelArray1[i]) then begin
      FreeAndNil(FPanelArray1[i]);
    end;
  end;
end;

5枚のパネルは消えて、Self.ControlCountの値も9から4に戻りました。

基本は自分で生成したコンポーネントは自分で始末するべきなんでしょうね。
でも、もし忘れていてもForm(Owner)が知っているのでFormが始末してくれるんですね。

勉強になりました。ありがとうございます。


INCM/CMT
Cyclamen v3.82