お知らせ

電子会議

ライブラリ

FDelphi サイト全文検索

Delphi FAQ一覧

サンプル蔵



FDelphi FAQ
15番会議室「FAQ編纂委員会」に寄せられた「よくある質問の答え」

[Q]
オブジェクトをコピーしたいのですが,やりかたがわかりません。

[A]
クラス型変数は実はオブジェクトへのポインタです。変数同士で代入しても
ポインタのコピーになって実体はコピーされませんので,別途生成してから
コピーしたいプロパティやメンバを一つづつ代入することが必要です。
 なお,オブジェクトの中にはAssignメソッドを持つものもあって,
このメソッドを使うとたいてい望みのコピー動作をしてくれますが,
コピーされないプロパティもあるので,よく注意して使います。
 TComponent用にすべてのpublishedプロパティのコピーを自動的に
やる手続きを例としてあげておきますので,ビジュアルコンポ
についてはこれを使うと手間が省けます。ただしイベントはコピー
しません。
[例]

 フォームにパネルを一個とパネルの上にTEditを一個貼り付けて
ください。パネルのMouseUpイベントを作ってアタッチして下さい。
パネルをクリックすると次々にコピーされます。

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Edit1: TEdit;
    procedure Panel1MouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

///////////汎用コンポーネントコピー手続き////////////
// DestがnilならSrcと同じクラスで自動生成して返す
// nilでなければ中身をコピーして返す
// 子コントロールも一緒にコピーされる
procedure CopyComponent(const Src: TComponent; var Dest: TComponent);

  // できたコンポにデフォルトの名前をつける
  procedure SetValidName(Compo: TComponent);
  var NewName: string;
    i: integer;
  begin
    if Compo.Owner = nil then Exit;
    with Compo do begin
      i := 0;
      repeat
        inc(i);
        NewName := ClassName + IntToStr(i);
        Delete(NewName,1,1);
      until Owner.FindComponent(NewName) = nil;
      Name := NewName;
    end;
  end;

  // コンポのクラスをシステムのリストに登録
  procedure RegisterChildClass(Component: TComponent);
  var i:integer;
  begin
    if GetClass(Component.ClassName) = nil then begin
      RegisterClass(TPersistentClass(Component.ClassType));
    end;
    if not(Component is TWinControl) then Exit;
    with TWinControl(Component) do begin
      for i := 0 to ControlCount-1 do begin
        RegisterChildClass(Controls[i]);   // recursive call
      end;
    end;
  end;

var Stream: TMemoryStream;
    SrcName: string;
    i,Count: integer;
    ChildCompo: TComponent;
begin
  Stream := TMemoryStream.Create;
  try
    SrcName := Src.Name;
    Src.Name := '';
    RegisterChildClass(Src);
    if Dest = nil then begin
      Dest := TComponentClass(Src.ClassType).Create(Src.Owner);
    end;
    with Stream do begin
      WriteComponent(Src);
      Seek(0,0);
      ReadComponent(Dest);
    end;
    if Dest is TControl then begin
      TControl(Dest).Parent := nil;
    end;
    Src.Name := SrcName;
    if Dest.ComponentCount <> 0 then begin
      SetValidName(Dest);
      with Dest do begin
        Count := ComponentCount;
        for i := 0 to Count-1 do begin
          ChildCompo := Components[0];
          ChildCompo.Name := '';
          RemoveComponent(ChildCompo);
          Owner.InsertComponent(ChildCompo);
          SetValidName(ChildCompo);
        end;
      end;
    end;
  finally
    Stream.Free;
  end;
end;

procedure TForm1.Panel1MouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var Cre,Org: TControl;
    NewPt: TPoint;
begin
  Org := TControl(Sender);
  Cre := nil;
  // コンポーネントのコピー
  CopyComponent(Org, TComponent(Cre));

  NewPt := Org.ClientToScreen( Point(0, 0) );
  NewPt := Self.ScreenToClient(NewPt);
  with TPanel(Cre) do begin
    Left := NewPt.X +10;
    Top  := NewPt.Y + 10;
    Parent := Self;
    OnMouseUp := Panel1MouseUp;
  end;
end;

end.


ここにあるドキュメントは NIFTY SERVEの Delphi Users' Forum FDELPHIに寄せられる質問の中から、よくある質問への回答を FDELPHIのメンバーがまとめたものです。 したがって、これらの回答はボーランド株式会社がサポートする公式のものではなく、掲示されている内容についての問い合わせは受けられない場合があります。

Copyright 1996-1998 Delphi Users' ForumFAQ編纂委員会