喫茶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;



[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 のところも見てくれるのではないか,
という期待感から掲載したつもりです.

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


[▼次のスレッド]
INCM/CMT
Cyclamen v3.82