UI
cppBuilder
#migrated

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

(追記 2017/09/06)

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


動作環境
C++ Builder XE4
  • TTrackBarを使ったスライダー表示
  • TEditを用いた数値の入力

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

失敗編

方法

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

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

  • TEditのOnExitイベントが発生
    • => TTrackBarの値が変更される
      • => TTrackBarのOnChangeイベントが発生
        • => TEditの値が変更される

回避案

方法

こうした場合、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

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

成功編

kCatchEndChange = true;で実行。

qiita.png

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