C++ Builder > { コンポーネントの[Tag]値の範囲 > NativeInt型 } | { Tagを使った共通実装: TTrackBar値, TEdit値の同期, XXX設定 }

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

### コンポーネントのTagプロパティ

コンポーネントのTagプロパティ。
これをうまく使うと共通処理が実装できる。

Tagには数値を入力可能だが、どういう値が使えるのか?

http://ht-deko.com/tech006.html
> 　XE2 以降では、Tag プロパティは NativeInt 型になりました。これにより、32bit / 64bit アプリケーションに関わらず、ポインタを型キャストして利用する事が可能となっています。

@ht_deko さん
情報感謝です。

http://docwiki.embarcadero.com/Libraries/XE4/ja/System.NativeInt
> NativeInt は整数の部分集合を表します。NativeInt の範囲は、現在のプラットフォームによって異なります。32 ビット プラットフォームでは、NativeInt は Integer 型と同等です。64 ビット プラットフォームでは、NativeInt は Int64 型と同等です。

## 用途 > 共通処理 v0.1 > TTrackBarのみ

以下のようにして処理を共通化できる。

- 各TTrackBarのTagプロパティに変更したい設定項目のレジスタ値を設定しておく
- 全てのTTrackBarのOnChangeをTrackBarChange_general()で共通化
- TimerCheckChangeTimer()にてTag値を用いて処理


### code

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

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include "editex.h"
#include "numedit.h"
#include <Vcl.ComCtrls.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TTrackBar *TrackBar1;
	TTrackBar *TrackBar2;
	TTimer *TimerCheckChange;
	TMemo *Memo1;
	TTrackBar *TrackBar3;
	void __fastcall TrackBarChange_general(TObject *Sender);
	void __fastcall TimerCheckChangeTimer(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 link "editex"
#pragma link "numedit"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

// 別ファイルで定義されているとする
#define REG_XXX (1024)
#define REG_YYY (2048)
#define REG_ZZZ (3072)

//

static TTrackBar *s_trbPtr = NULL;

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	Memo1->Clear();

	// タグの割付
	TrackBar1->Tag = REG_XXX;
	TrackBar2->Tag = REG_YYY;
	TrackBar3->Tag = REG_ZZZ;

	//
	TrackBar1->OnChange = TrackBarChange_general;
	TrackBar2->OnChange = TrackBarChange_general;
	TrackBar3->OnChange = TrackBarChange_general;

	//
	TimerCheckChange->Enabled = false;
	TimerCheckChange->Interval = 300; // msec
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TrackBarChange_general(TObject *Sender)
{
	// 共通処理

	if (TimerCheckChange->Enabled) {
		return;
	}

	s_trbPtr = (TTrackBar *)Sender;

	TimerCheckChange->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TimerCheckChangeTimer(TObject *Sender)
{
	if (s_trbPtr == NULL) {
		TimerCheckChange->Enabled = false;
		return;
	}

	int regval = s_trbPtr->Tag; // register value

	String msg = L"Change register of [" + IntToStr(regval) + L"]";
	Memo1->Lines->Add(msg);

	s_trbPtr = NULL;
	TimerCheckChange->Enabled = false;
}
//---------------------------------------------------------------------------

```

### 実行例

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/4e098822-0d55-0033-d295-5b7cbdfecab9.png)

- (1) : TrackBar1を変更時
- (2) : TrackBar2を変更時
- (3) : TrackBar3を変更時

TrackBarのPositionの値を用いて、TrackBarのTag値のレジスタ内容を変更するというような共通処理を実装できる。

## 用途 > 共通処理 v0.2 > TTrackBarとTEdit + XXX設定

- コンポーネント1変更
    - コンポーネント2変更
    - XXX設定変更

という流れを考えてきたが、以下でもいいかもしれない。

- コンポーネント1変更
    - XXX設定変更
    - コンポーネント2変更
        - XXX設定から読出し

### code

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

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include "editex.h"
#include "numedit.h"
#include <Vcl.ComCtrls.hpp>
#include <Vcl.ExtCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TTrackBar *TrackBar1;
	TTrackBar *TrackBar2;
	TTimer *TimerCheckChange;
	TMemo *Memo1;
	TTrackBar *TrackBar3;
	TEdit *Edit1;
	TEdit *Edit2;
	TEdit *Edit3;
	void __fastcall TrackBarChange_general(TObject *Sender);
	void __fastcall TimerCheckChangeTimer(TObject *Sender);
	void __fastcall EditKeyDown_general(TObject *Sender, WORD &Key, TShiftState Shift);
	void __fastcall EditExit_general(TObject *Sender);
private:	// ユーザー宣言
	// XXXの設定と読込み
	void __fastcall XXX_SetValue(int regval, int value);
	void __fastcall XXX_GetAllValuesToComponents(void);
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 link "editex"
#pragma link "numedit"
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------


// { XXXの設定
//     別ファイルで定義されているとする
#define REG_XXX (1024)
#define REG_YYY (2048)
#define REG_ZZZ (3072)

typedef struct {
	int xval;
	int yval;
	int zval;
} SENSOR_SETTING_t;

static SENSOR_SETTING_t s_setting = { 0, 0, 0 };
// } XXXの設定


static TTrackBar *s_trbPtr = NULL;

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	Memo1->Clear();

	// タグの割付
	TrackBar1->Tag = REG_XXX;
	TrackBar2->Tag = REG_YYY;
	TrackBar3->Tag = REG_ZZZ;
	Edit1->Tag = REG_XXX;
	Edit2->Tag = REG_YYY;
	Edit3->Tag = REG_ZZZ;

	// イベント処理の共通化
	TrackBar1->OnChange = TrackBarChange_general;
	TrackBar2->OnChange = TrackBarChange_general;
	TrackBar3->OnChange = TrackBarChange_general;
	Edit1->OnKeyDown = EditKeyDown_general;
	Edit2->OnKeyDown = EditKeyDown_general;
	Edit3->OnKeyDown = EditKeyDown_general;
	Edit1->OnExit = EditExit_general;
	Edit2->OnExit = EditExit_general;
	Edit3->OnExit = EditExit_general;

	//
	TimerCheckChange->Enabled = false;
	TimerCheckChange->Interval = 300; // msec
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TrackBarChange_general(TObject *Sender)
{
	// 共通処理
	if (TimerCheckChange->Enabled) {
		return;
	}

	s_trbPtr = (TTrackBar *)Sender;

	if (s_trbPtr->Focused() == false) { // 他のコンポーネントからの値の変更
		return;
	}

	TimerCheckChange->Enabled = true;
}

void __fastcall TForm1::TimerCheckChangeTimer(TObject *Sender)
{
	if (s_trbPtr == NULL) {
		TimerCheckChange->Enabled = false;
		return;
	}

	int regval = s_trbPtr->Tag; // register value
	XXX_SetValue(regval, s_trbPtr->Position);

	XXX_GetAllValuesToComponents(); // 毎回全部の項目を読むため、処理は重い

	// debug
	String msg = L"TrackBar: Change register of [" + IntToStr(regval) + L"]";
	Memo1->Lines->Add(msg);

	s_trbPtr = NULL;
	TimerCheckChange->Enabled = false;
}

void __fastcall TForm1::EditExit_general(TObject *Sender)
{
	TEdit *srcPtr = (TEdit *)Sender;

	int setval = StrToIntDef(srcPtr->Text, -1);
	if (setval < 0) {
		return; // error
	}

	int regval = srcPtr->Tag; // register value
	XXX_SetValue(regval, setval);

	XXX_GetAllValuesToComponents(); // 毎回全部の項目を読むため、処理は重い

	// debug
	String msg = L"Edit: Change register of [" + IntToStr(regval) + L"]";
	Memo1->Lines->Add(msg);
}

void __fastcall TForm1::EditKeyDown_general(TObject *Sender, WORD &Key, TShiftState Shift)
{
	if (Key != VK_RETURN) {
		return;
	}

	EditExit_general(Sender);
}

//---------------------------------------------------------------------------
// { XXXの設定と読込み
void __fastcall TForm1::XXX_SetValue(int regval, int value)
{
	switch(regval) {
	case REG_XXX:
		s_setting.xval = value;
		break;
	case REG_YYY:
		s_setting.yval = value;
		break;
	case REG_ZZZ:
		s_setting.zval = value;
		break;
	};
}

void __fastcall TForm1::XXX_GetAllValuesToComponents(void)
{
	Edit1->Text = String(s_setting.xval);
	Edit2->Text = String(s_setting.yval);
	Edit3->Text = String(s_setting.zval);

	TrackBar1->Position = s_setting.xval;
	TrackBar2->Position = s_setting.yval;
	TrackBar3->Position = s_setting.zval;
}
// } XXXの設定と読込み
```

### 実行例

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/82fc3f5c-c454-7246-8781-d4d97d129cdb.png)

XXX_GetAllValuesToComponents()を毎回実行するのは無駄な処理ではある。

変更があったものだけを読直すように処理をすれば、なお良い。