(追記 2017/09/06)
下記に記載事項は「ビルド環境」「OS環境」により再現しないかもしれません。
環境が変わった時点でバグとなる可能性が考えられるため、お薦めの方法ではありません。
なんらかの参考にはなるかもしれないため、記事としては残しておきます。
動作環境
C++ Builder XE4
- TTrackBarを使ったスライダー表示
- TEditを用いた数値の入力
上記を同期させるとする。
失敗編
方法
- TTrackBarのOnChangeイベントでTEditの値を変更する
- TEditのOnExitイベントでTTrackBarの値を変更する
こうした場合、TEditの値を変更してフォーカスをはずしたとき、以下となる。
- TEditのOnExitイベントが発生
- => TTrackBarの値が変更される
- => TTrackBarのOnChangeイベントが発生
- => TEditの値が変更される
- => TTrackBarのOnChangeイベントが発生
- => TTrackBarの値が変更される
回避案
方法
- TTrackBarのOnChangeイベントでTEditの値を変更する
- 変更条件: 変更終了時のみ
- TEditのOnExitイベントでTTrackBarの値を変更する
こうした場合、TEditの値を変更してフォーカスをはずしたとき、以下となる。
- TEditのOnExitイベントが発生
- => TTrackBarの値が変更される
- 変更終了時(i.e., 値がpreと同値)でないためTTrackBarのOnChangeイベントは発生しない
- => TTrackBarの値が変更される
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;
で実行。
- (1)の部分: TrackBar1の値を2から24に上げた
- 途中の変更がイベント処理されてしまう
- (2)の部分: TEditからフォーカスをはずした
- OnExitイベントに加えて、TrackBar1:OnChangeイベントが発生してしまう
成功編
kCatchEndChange = true;
で実行。
- (1)の部分: TrackBar1の値を2から45に上げた
- 最後の二回のイベントが発生
- (2)の部分: TEditからフォーカスをはずした
- OnExitイベントのみ発生