0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

c++ builder / UI > 1000個のコンポーネントのうち、どれかが変更されたことを確認する > 項目の保存 / 比較

Last updated at Posted at 2016-07-28
動作確認
C++ Builder XE4

関連 http://qiita.com/7of9/items/ea52f618de6b465299ab

背景

  • フォームに1000個のコンポーネントがある
  • そのどれかが変更されたら、「初期値と異なる」とする

1000個のコンポーネントのonChangeメソッドを使うのは面倒そうだ。

方法

ある時点のスナップショットを取る。
そのスナップショットと比較することで、変更があったかどうかを知る。

code v0.1

TEdit, TRadioButton, TCheckBoxの3種類のコンポーネントに対応。
各項目の最大数は100としているが用途によって増やせばいい。

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

# ifndef Unit1H
# define Unit1H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TEdit *Edit1;
	TCheckBox *CheckBox1;
	TRadioButton *RadioButton1;
	TButton *B_save;
	TCheckBox *CheckBox2;
	TEdit *Edit2;
	TRadioButton *RadioButton2;
	TButton *B_check;
	void __fastcall B_saveClick(TObject *Sender);
	void __fastcall FormShow(TObject *Sender);
	void __fastcall B_checkClick(TObject *Sender);
private:	// ユーザー宣言
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)
{
}
//---------------------------------------------------------------------------

static const int kMaxnumItems = 100;
typedef struct tag_Config {
	bool checkBoxChecked[kMaxnumItems];
	int numCheckbox;
	bool radioButtonChecked[kMaxnumItems];
	int numRadioButton;
	String editText[kMaxnumItems];
	int numEdit;
} Config_t;

static Config_t s_config;

static initConfig(void)
{
	s_config.numCheckbox = 0;
	s_config.numRadioButton = 0;
	s_config.numEdit = 0;
}

void __fastcall TForm1::B_saveClick(TObject *Sender)
{
	initConfig();

	for(int idx = 0; idx < ComponentCount; idx++) {
		TComponent *ptarget = Components[idx];

		if (dynamic_cast<TCheckBox *>(ptarget) != NULL) {
			TCheckBox *chkPtr = (TCheckBox *)ptarget;
			int itmidx = (s_config.numCheckbox)++;
			s_config.checkBoxChecked[itmidx] = chkPtr->Checked;
		}
		if (dynamic_cast<TRadioButton *>(ptarget) != NULL) {
			TRadioButton *rdbPtr = (TRadioButton *)ptarget;
			int itmidx = (s_config.numRadioButton)++;
			s_config.radioButtonChecked[itmidx] = rdbPtr->Checked;
		}
		if (dynamic_cast<TEdit *>(ptarget) != NULL) {
			TEdit *edPtr = (TEdit *)ptarget;
			int itmidx = (s_config.numEdit)++;
			s_config.editText[itmidx] = edPtr->Text;
		}
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormShow(TObject *Sender)
{
	initConfig();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::B_checkClick(TObject *Sender)
{
	int chkbxidx = 0; // index for TCheckBox
	int rdbidx = 0; // index for TRadioButton
	int edidx = 0; // index for TEdit

	bool changed = false;

	for(int idx = 0; idx < ComponentCount; idx++) {
		TComponent *ptarget = Components[idx];

		if (dynamic_cast<TCheckBox *>(ptarget) != NULL) {
			TCheckBox *chkPtr = (TCheckBox *)ptarget;
			if (s_config.checkBoxChecked[chkbxidx] != chkPtr->Checked) {
				changed = true;
				break;
			}
			chkbxidx++;
		}

		if (dynamic_cast<TRadioButton *>(ptarget) != NULL) {
			TRadioButton *rdbPtr = (TRadioButton *)ptarget;
			if (s_config.radioButtonChecked[rdbidx] != rdbPtr->Checked) {
				changed = true;
				break;
			}
			rdbidx++;
		}

		if (dynamic_cast<TEdit *>(ptarget) != NULL) {
			TEdit *edPtr = (TEdit *)ptarget;
			if (s_config.editText[edidx] != edPtr->Text) {
				changed = true;
				break;
			}
			edidx++;
		}
	}

	if (changed) {
		ShowMessage(L"Changed");
	} else {
		ShowMessage(L"Same as usual");
	}
}
//---------------------------------------------------------------------------

UI例

qiita.png

B_saveを押した時にスナップショットを取り、B_check押下時に変更があったかどうかを知る。

変更があったら「Changed」が表示され、変更がなかったら「Same as usual」が表示される。

関連

dynamic_cast<>の使用はRemy Lebeauさんに教わった。
http://stackoverflow.com/questions/33060775/how-to-know-the-control-is-tlabel

@shiracamus さんに教わった書き方も拝借。
http://qiita.com/7of9/items/2e6e3c7880fafe8014d4#comment-ae913b64fdeba065f885

備考

Components[]のハッシュ値をとればもっと簡単になるかもしれない。

code v0.2

異なるフォームにて使いまわせるように外部ファイル化した。

外部ファイル

UtilSettingModified.h
//---------------------------------------------------------------------------

# ifndef UtilSettingModifiedH
# define UtilSettingModifiedH

//---------------------------------------------------------------------------

/*
フォーム上のコンポーネントの値が変更されたかをチェックする。
*/

static const int kMaxnumItems = 300;

class CUtilSettingModified {
private:
	typedef struct tag_Config {
	    bool checkBoxChecked[kMaxnumItems];
	    int numCheckbox;
	    bool radioButtonChecked[kMaxnumItems];
	    int numRadioButton;
	    String editText[kMaxnumItems];
	    int numEdit;
	} Config_t;

	Config_t m_config;

	void __fastcall initItems(void);

public:
	void __fastcall DoSave(TForm *formPtr);
	bool __fastcall HasChanged(TForm *formPtr);

	// コンストラクタ
	__fastcall CUtilSettingModified();	
};

# endif
UtilSettingModified.cpp
//---------------------------------------------------------------------------

# include <vcl.h>
# pragma hdrstop

# include "UtilSettingModified.h"

//---------------------------------------------------------------------------
# pragma package(smart_init)

# define DEBUG_DO_PRINT // デバッグ出力

/*
v0.1 2016/07/28
	- HasChanged()追加
	- DoSave()追加
	- initItems()追加
	- コンストラクタ追加
	- debug_outputDebugString()追加
*/

//---------------------------------------------------------------------------
static void debug_outputDebugString(String prefix, String msg)
{
	// あとでまとめてデバッグ出力をコメントアウトするため、関数にしている。

# ifdef DEBUG_DO_PRINT
	String work = L"UtilSettingModified >" + prefix + L": " + msg;
	OutputDebugString(work.c_str()); // @ debug_outputDebugString
# endif
}
//---------------------------------------------------------------------------
__fastcall CUtilSettingModified::CUtilSettingModified()
{
	initItems();
}
//---------------------------------------------------------------------------
void __fastcall CUtilSettingModified::initItems(void)
{
    m_config.numCheckbox = 0;
    m_config.numRadioButton = 0;
    m_config.numEdit = 0;	
}

//---------------------------------------------------------------------------
void __fastcall CUtilSettingModified::DoSave(TForm *formPtr)
{
    initItems();

    for(int idx = 0; idx < formPtr->ComponentCount; idx++) {
        TComponent *ptarget = formPtr->Components[idx];

        if (dynamic_cast<TCheckBox *>(ptarget) != NULL) {
            TCheckBox *chkPtr = (TCheckBox *)ptarget;
            int itmidx = (m_config.numCheckbox)++;
            m_config.checkBoxChecked[itmidx] = chkPtr->Checked;
        }
        if (dynamic_cast<TRadioButton *>(ptarget) != NULL) {
            TRadioButton *rdbPtr = (TRadioButton *)ptarget;
            int itmidx = (m_config.numRadioButton)++;
            m_config.radioButtonChecked[itmidx] = rdbPtr->Checked;
        }
        if (dynamic_cast<TEdit *>(ptarget) != NULL) {
            TEdit *edPtr = (TEdit *)ptarget;
            int itmidx = (m_config.numEdit)++;
            m_config.editText[itmidx] = edPtr->Text;
        }
    }
}

bool __fastcall CUtilSettingModified::HasChanged(TForm *formPtr)
{
    int chkbxidx = 0; // index for TCheckBox
    int rdbidx = 0; // index for TRadioButton
    int edidx = 0; // index for TEdit

    bool changed = false;

    for(int idx = 0; idx < formPtr->ComponentCount; idx++) {
        TComponent *ptarget = formPtr->Components[idx];

        if (dynamic_cast<TCheckBox *>(ptarget) != NULL) {
            TCheckBox *chkPtr = (TCheckBox *)ptarget;
            if (m_config.checkBoxChecked[chkbxidx] != chkPtr->Checked) {
                changed = true;
                break;
            }
            chkbxidx++;
        }

        if (dynamic_cast<TRadioButton *>(ptarget) != NULL) {
            TRadioButton *rdbPtr = (TRadioButton *)ptarget;
            if (m_config.radioButtonChecked[rdbidx] != rdbPtr->Checked) {
                changed = true;
                break;
            }
            rdbidx++;
        }

        if (dynamic_cast<TEdit *>(ptarget) != NULL) {
            TEdit *edPtr = (TEdit *)ptarget;
            if (m_config.editText[edidx] != edPtr->Text) {
                changed = true;
                break;
            }
            edidx++;
        }
    }

    return changed;
}

使用コード

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

# ifndef Unit1H
# define Unit1H
//---------------------------------------------------------------------------
# include <System.Classes.hpp>
# include <Vcl.Controls.hpp>
# include <Vcl.StdCtrls.hpp>
# include <Vcl.Forms.hpp>

# include "UtilSettingModified.h"

//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TCheckBox *CheckBox1;
	TCheckBox *CheckBox2;
	TCheckBox *CheckBox3;
	TCheckBox *CheckBox4;
	TCheckBox *CheckBox5;
	TCheckBox *CheckBox6;
	TButton *B_save;
	TButton *B_check;
	void __fastcall B_saveClick(TObject *Sender);
	void __fastcall B_checkClick(TObject *Sender);
private:	// ユーザー宣言
	CUtilSettingModified *m_settingModified;
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
	__fastcall ~TForm1();
};
//---------------------------------------------------------------------------
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)
{
	m_settingModified = new CUtilSettingModified();
}
__fastcall TForm1::~TForm1()
{
	if (m_settingModified != NULL) {
		delete m_settingModified;
		m_settingModified = NULL;
	}
}
//---------------------------------------------------------------------------
void __fastcall TForm1::B_saveClick(TObject *Sender)
{
	m_settingModified->DoSave(this);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::B_checkClick(TObject *Sender)
{
	if (m_settingModified->HasChanged(this)) {
		ShowMessage(L"Changed");
	} else {
     	ShowMessage(L"Same as before");
	}
}
//---------------------------------------------------------------------------

外部ファイル化することでUnit1自体の実装はすっきりするようになった。
ロジックをUIと分離できたかと思う。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?