C++ Builder XE4 > configuration > フォーム上の項目を変更した時にUnsaved changesを表示する仕組みの実装 > シリアライズ

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

### やりたいこと

- フォーム上に様々なコンポーネントがある
- いずれかのコンポーネントに関して変更があったとき
    - <font color=red>Unsaved changes</font>と表示したい

### 実装案

- TCheckBox->Checked, TEdit->Text, TComboBox->ItemIndexすべてをString型にする
    - 「シリアライズ」と呼ぶこととする
- フォーム表示時のシリアライズ値と、任意のタイミングのシリアライズ値の差異を検知する

### 実装

```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 で管理されるコンポーネント
	TCheckBox *CheckBox1;
	TCheckBox *CheckBox2;
	TCheckBox *CheckBox3;
	TEdit *Edit1;
	TEdit *Edit2;
	TEdit *Edit3;
	TComboBox *ComboBox1;
	TTimer *Timer1;
	TComboBox *ComboBox2;
	TComboBox *ComboBox3;
	TLabel *L_unchanged;
	void __fastcall FormShow(TObject *Sender);
	void __fastcall Timer1Timer(TObject *Sender);
	void __fastcall ComboBoxKeyDown_general(TObject *Sender, WORD &Key, TShiftState Shift);

private:	// ユーザー宣言
	String __fastcall serializeAllComponents(void);
	String __fastcall serializeEachComponent(TControl *ctrlPtr);
	String m_onShowSerial; // Form OnShow時にシリアル
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)
{
	// 変更チェックのインターバル設定
	Timer1->Enabled = false;
	Timer1->Interval = 300; // msec
	Timer1->Enabled = true;

	// 全てのコンポボックスに同じ処理をする (BackSpaceキー処理)
	ComboBox1->OnKeyDown = ComboBoxKeyDown_general;
	ComboBox2->OnKeyDown = ComboBoxKeyDown_general;
	ComboBox3->OnKeyDown = ComboBoxKeyDown_general;
}
//---------------------------------------------------------------------------
// シリアルライズ関連の処理
//
String __fastcall TForm1::serializeAllComponents(void)
{
	String res = L"";
	for (int idx=0; idx < this->ControlCount; idx++) {
		res += serializeEachComponent(this->Controls[idx]);
	}
	return res;
}

String __fastcall TForm1::serializeEachComponent(TControl *ctrlPtr)
{
	if (dynamic_cast<TEdit *>(ctrlPtr) != NULL) {
		TEdit *edPtr = (TEdit *)ctrlPtr;
		return edPtr->Text;
	}
	if (dynamic_cast<TCheckBox *>(ctrlPtr) != NULL) {
		TCheckBox *chkPtr = (TCheckBox *)ctrlPtr;
		return BoolToStr(chkPtr->Checked);
	}
	if (dynamic_cast<TComboBox *>(ctrlPtr) != NULL) {
		TComboBox *cmbPtr = (TComboBox *)ctrlPtr;
		return IntToStr(cmbPtr->ItemIndex);
	}

	return L"";
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
	m_onShowSerial = serializeAllComponents();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
	String work = serializeAllComponents();

	L_unchanged->Visible = (work != m_onShowSerial);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::ComboBoxKeyDown_general(TObject *Sender, WORD &Key, TShiftState Shift)
{
	TComboBox *cbPtr = (TComboBox *)Sender;
	if (Key == VK_BACK) {
		SendMessageA(cbPtr->Handle, CB_SHOWDROPDOWN, 0, 0); // Close ComboBox
		cbPtr->ItemIndex = -1; // deselect
	}
}
//---------------------------------------------------------------------------

```

### 動作例

ソフト起動直後
![2019-03-05_19h19_05.png](https://qiita-image-store.s3.amazonaws.com/0/32870/afc98837-bd02-2cd1-d033-f84554961617.png)

項目内用を変更後
![2019-03-05_19h19_24.png](https://qiita-image-store.s3.amazonaws.com/0/32870/1873d466-c3d3-da13-a440-b04ae683a60e.png)

項目内用を元に戻した後
![2019-03-05_19h19_38.png](https://qiita-image-store.s3.amazonaws.com/0/32870/17d7c9be-e733-83a9-5e9d-18072d9bd825.png)