動作環境
C++ Builder XE4
やりたいこと
- フォーム上に様々なコンポーネントがある
- いずれかのコンポーネントに関して変更があったとき
- Unsaved changesと表示したい
実装案
- 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
}
}
//---------------------------------------------------------------------------


