動作環境
C++ Builder XE4
処理概要
- Shape1:TShapeからShape2:TShapeへプロパティをコピーしたい
- 線の幅や色などプロパティを一つ一つコピーするのでなく、丸ごとコピーする
参考
RTTIの方法など紹介されている例もあるが、自分の目に留まったのはTMemoryStreamを使った実装。
下記はDelphiでの実装。
それをC++ Builder用に変更した
フォームデザイン
実装
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;
}
動作例
イベントのコピー
に記載があるように、上記の実装では「プロパティ」のコピーはできるが、「イベント」のコピーはできない。
「イベント」のコピーは上記のDelphi実装を参考に別途実装する必要がある。
(2018年12月現在は不要のため、この記事では実装しない)
関連
不具合? > フォーム間で「同じ」名前のコンポーネント間のコピー
- FormA: Shape1
- FormB: Shape1
2つのコンポーネントでコピーをするとどうなるか?
下記のエラーが発生した。
モジュール '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;
}