喫茶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はやはり必要ですね。


[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;



[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