C++ Builder XE4 > TControl > プロパティのコピー > Shape1からShape2へプロパティをコピーする 

```txt:動作環境
C++ Builder XE4
```

### 処理概要

- Shape1:TShapeからShape2:TShapeへプロパティをコピーしたい
    - 線の幅や色などプロパティを一つ一つコピーするのでなく、丸ごとコピーする

### 参考

RTTIの方法など紹介されている例もあるが、自分の目に留まったのはTMemoryStreamを使った実装。

下記はDelphiでの実装。

- [[delphi] 実行時にコンポーネントを複製する](https://code.i-harness.com/ja/q/3a59a)

それをC++ Builder用に変更した

### フォームデザイン

![2018-12-26_17h20_30.png](https://qiita-image-store.s3.amazonaws.com/0/32870/b77711a2-c482-f6ec-4fdb-b6e06b44c65c.png)


### 実装

```Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TShape *Shape1;
	TShape *Shape2;
	TButton *Button1;
	void __fastcall Button1Click(TObject *Sender);
private:	// ユーザー宣言
	void __fastcall copyProperties(TControl *srcCtrl, TControl *dstCtrl);
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};


//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
```

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	//　
	copyProperties((TControl *)Shape1, (TControl *)Shape2);

	// 重なっているため
	Shape2->Left = Shape1->Left + 150;
}

void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
	// 元の名前を保持
	String orgName_src = srcCtrl->Name;
	String orgName_dst = dstCtrl->Name;

	// プロパティコピー
	TMemoryStream *strm = new TMemoryStream;
	Shape1->Name = L"";  // to avoid source collision
	try {
		strm->WriteComponent(srcCtrl);
		strm->Position = 0;
		strm->ReadComponent(dstCtrl);
	}
	__finally
	{
		delete strm;
	}

	srcCtrl->Name = orgName_src;
	dstCtrl->Name = orgName_dst;
}
```


### 動作例

ソフト起動直後
![2018-12-26_17h21_11.png](https://qiita-image-store.s3.amazonaws.com/0/32870/f430c6ba-ad6f-acc3-0cfe-f788d2a4a8d5.png)

Button1押下後
![2018-12-26_17h21_23.png](https://qiita-image-store.s3.amazonaws.com/0/32870/d00ff13d-8231-96ab-6b6a-06f9336882c8.png)



### イベントのコピー

- [[delphi] 実行時にコンポーネントを複製する](https://code.i-harness.com/ja/q/3a59a)

に記載があるように、上記の実装では「プロパティ」のコピーはできるが、「イベント」のコピーはできない。
「イベント」のコピーは上記のDelphi実装を参考に別途実装する必要がある。

（2018年12月現在は不要のため、この記事では実装しない）

### 関連

- [C++ Builder XE4 > Assign() > Error: TShapeをTShapeに代入することはできません。 > overrideして使う?](https://qiita.com/7of9/items/65e6f3745c39cadd4616)



### 不具合? > フォーム間で「同じ」名前のコンポーネント間のコピー

- FormA: Shape1
- FormB: Shape1

２つのコンポーネントでコピーをするとどうなるか?
下記のエラーが発生した。

> モジュール 'XXX.exe'のアドレス XXXでアドレスXXXに対する読取り違反がおきました。

名前は同じだとダメなのだろうか。

試しに名前を違うようにして実行したが、同じエラーとなった。

失敗理由が分かった。

### v0.2 

copyProperties()内の`srcCtrl->Name = L"";`を`srcCtrl->Name = L"";`に修正。

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	//　
	copyProperties((TControl *)Shape1, (TControl *)Shape2);

	// 重なっているため
	Shape2->Left = Shape1->Left + 150;
}

void __fastcall TForm1::copyProperties(TControl *srcCtrl, TControl *dstCtrl)
{
	// 元の名前を保持
	String orgName_src = srcCtrl->Name;
	String orgName_dst = dstCtrl->Name;

	// プロパティコピー
	TMemoryStream *strm = new TMemoryStream;
	srcCtrl->Name = L"";  // to avoid source collision
	try {
		strm->WriteComponent(srcCtrl);
		strm->Position = 0;
		strm->ReadComponent(dstCtrl);
	}
	__finally
	{
		delete strm;
	}

	srcCtrl->Name = orgName_src;
	dstCtrl->Name = orgName_dst;
}
```