[廃版] C++ Builder > TTrackBar と TEdit > 値の同期 > TTrackBar:OnChange | TEdit:OnExit

(追記 2017/09/06)
<font color=red>
下記に記載事項は「ビルド環境」「OS環境」により再現しないかもしれません。
環境が変わった時点でバグとなる可能性が考えられるため、お薦めの方法ではありません。
なんらかの参考にはなるかもしれないため、記事としては残しておきます。
</font>

<hr>

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

- TTrackBarを使ったスライダー表示
- TEditを用いた数値の入力

上記を同期させるとする。

### 失敗編

方法

- TTrackBarのOnChangeイベントでTEditの値を変更する
- TEditのOnExitイベントでTTrackBarの値を変更する

こうした場合、TEditの値を変更してフォーカスをはずしたとき、以下となる。

- TEditのOnExitイベントが発生
    - => TTrackBarの値が変更される
        - => TTrackBarのOnChangeイベントが発生
            - => TEditの値が変更される
                
### 回避案

方法

- TTrackBarのOnChangeイベントでTEditの値を変更する
    - 変更条件: 変更終了時のみ
        - 実装: [C++ Builder > TTrackBar > 値変更中にOnChange()が繰返し実行される > 変更終了の検知案](http://qiita.com/7of9/items/6f13b78702f9186af345)
- TEditのOnExitイベントでTTrackBarの値を変更する

こうした場合、TEditの値を変更してフォーカスをはずしたとき、以下となる。

- TEditのOnExitイベントが発生
    - => TTrackBarの値が変更される
        - 変更終了時(i.e., 値がpreと同値)でないためTTrackBarのOnChangeイベントは発生しない
    
## code

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

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ComCtrls.hpp>
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TEdit *Edit1;
	TTrackBar *TrackBar1;
	TMemo *Memo1;
	void __fastcall TrackBar1Change(TObject *Sender);
	void __fastcall Edit1Exit(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;
//---------------------------------------------------------------------------


static const bool kCatchEndChange = true;  // true: TrackBar1の最後の変更(+1)だけ検知する

__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	TrackBar1->Min = 0;
	TrackBar1->Max = 100;
	TrackBar1->Frequency = 10;

	Memo1->Clear();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::TrackBar1Change(TObject *Sender)
{
	static int pre = -1;

	if (kCatchEndChange) {
		if (pre == TrackBar1->Position) {
			Memo1->Lines->Add(L"TrackBar1Change [" + IntToStr(TrackBar1->Position) + L"] " + DateTimeToStr(Now()));
			Edit1->Text = IntToStr(TrackBar1->Position);
		}

		pre = TrackBar1->Position;
		return;
	}

	Memo1->Lines->Add(L"TrackBar1Change [" + IntToStr(TrackBar1->Position) + L"] " + DateTimeToStr(Now()));
	Edit1->Text = IntToStr(TrackBar1->Position);
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Edit1Exit(TObject *Sender)
{
	Memo1->Lines->Add(L"Edit1Exit [" + Edit1->Text + L"] " + DateTimeToStr(Now()));

	int val = StrToIntDef(Edit1->Text, -1);
	if (val > 0) {
        TrackBar1->Position = val;
	}
}
//---------------------------------------------------------------------------
```

## 実行例

### 失敗編

`kCatchEndChange = false;`で実行。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/5ff39715-a3a0-3dfa-5a26-a70e27cc5037.png)

- (1)の部分: TrackBar1の値を2から24に上げた
    - 途中の変更がイベント処理されてしまう
- (2)の部分: TEditからフォーカスをはずした
    - OnExitイベントに加えて、TrackBar1:OnChangeイベントが発生してしまう

### 成功編

`kCatchEndChange = true;`で実行。

![qiita.png](https://qiita-image-store.s3.amazonaws.com/0/32870/8b3124d4-5f0b-a09e-864e-c4bf0515c1dd.png)

- (1)の部分: TrackBar1の値を2から45に上げた
    - 最後の二回のイベントが発生
- (2)の部分: TEditからフォーカスをはずした
    - OnExitイベントのみ発生