Updownボタンでインクリメント/デクリメントできるようにする – Delphiカスタムコンポーネントの作成 14

投稿者: | 2018年4月7日

Updownボタンを表示できるようになったので、このボタンで実際に数値を変更できるようにします。

Incrementプロパティの作成

ボタンをクリックしたとき、数値をどの程度増減させるかをIncrementプロパティで指定できるようにします。
プロパティ値を保存するために、FIncrement フィールドを宣言します(23行目)。

TCustomNumberEdit = class(TCustomEdit)
  private
    { Private 宣言 }
    FComma: Boolean;
    FDigits: Integer;
    FIncrement: Extended;

Incrementプロパティは、protected スコープで定義します(45行目)。

    // プロパティ
    property Increment: Extended read FIncrement write FIncrement;
    property VisibleUpdown: Boolean read GetVisibleUpdown write SetVisibleUpdown;

Incrementプロパティは今まで作成したプロパティと異なり、write で FIncrement フィールドに直接値を書き込みます(メソッドを介さない)。これは Increment プロパティが変更されても、画面表示が変わったり、特別な処理を行ったりする必要がないためです。

Updownボタンが押されたことを検知する

Updownボタンが押されたことを検知する方法は、以下の3つが考えられます。

  1. Updownボタンから、TCustomNumberEditの特定のメソッドを呼び出して、TCustomNumberEditに数値を変更してもらう方法
  2. Updownボタンから、TCustomNumberEditのValueプロパティを直接変更する方法
  3. Updownボタンのイベントにイベントハンドラーを設定しておき、そのイベント内で数値を変更する方法

どの方法がよいかは好みでしょう。今回は3番目の、イベントハンドラーを使う方法を採用します。
Updownボタンを押したとき発生するイベントのうち、使用するのは OnChangingEx イベントです。理由は2つあります。上下どちらのボタンが押されたかが分かることと、Positionプロパティの変更をキャンセルできることです。
Positionプロパティは Updown ボタンが持つプロパティで、ボタンをクリックすることで増減します。イベントハンドラー内でPositionプロパティの変更をキャンセルし、予測外のエラーが発生することを防止します。

イベントハンドラーの作成

OnChangingExイベントのイベントハンドラーを作成します。TCustomNumberEditのprotected部に、UpdownChanging という名前でメソッドを作成します。これがOnChangingExのイベントハンドラーになるので、イベントの型と定義を合わせる必要があります。定義は以下のとおりです(44-45行目)。

    function TextToValue(const S: string): Extended; virtual;
    procedure UpdownChanging(Sender: TObject; var AllowChange: Boolean;
      NewValue: Integer; Direction: TUpDownDirection);

実装は以下のとおりです。

procedure TCustomNumberEdit.UpdownChanging(Sender: TObject;
  var AllowChange: Boolean; NewValue: Integer; Direction: TUpDownDirection);
begin
  // 数値のインクリメント・デクリメント
  case Direction of
    TUpDownDirection.updUp:
      Value := Value + FIncrement;

  else
    Value := Value - FIncrement;
  end;

  // TCustomUpDownのPosition変更の抑制
  AllowChange := False;
end;

押されたボタン方向によって数値をインクリメント、またはデクリメントします。
最後に、AllowChange引数をFalseに設定することで、UpdownボタンのPositionプロパティが変化することを抑制します。

Updownボタンとイベントハンドラーを結びつける

イベントハンドラーを作成しただけでは、イベントが処理されません。Updownボタンの OnChangingEx イベントと、イベントハンドラーを結びつける必要があります。Updownボタンのオブジェクトが作成されたタイミングで、イベントとイベントハンドラーを結びつける処理を追加します。
CreateUpdownメソッドを、以下のように修正します(182行目を追加)。

procedure TCustomNumberEdit.CreateUpDown;
begin
  if FUpdown = nil then
  begin
    FUpdown := TInnerUpDown.Create(Self);
    FUpdown.Parent := Self;
    FUpdown.OnChangingEx := UpdownChanging;
  end;
end;

Incrementプロパティにデフォルト値を設定する

ここでTCustomNumberEdit (TNumberEdit) をテストしてみましょう。VisibleUpdownプロパティをTrueにして、Updownボタンをクリックします。結果は、何も変化しません。これはIncrementプロパティ値が 0.0 になっているためです。いくらUpdownボタンをクリックしても値が増減しないのは、当然です。この 0.0 はどこから来たのかというと、FIncrement フィールドの初期値(デフォルト値)になります。数値型のフィールドはクラスが生成されたとき、0 で初期化されることになっています。
しかし、Incrementプロパティには初期値として、0.0 以外の値が入っていた方が自然だと思います。この初期値を変更するには、コンストラクターを使用します。コンストラクターとはクラスを初期化するための特別なメソッドです。
たとえば、TBitmapクラスからオブジェクトを生成するとき、TBitmap.Create と記述するはずです。この Create がコンストラクターです。TCustomNumberEdit クラスにも Create コンストラクターがあります。これは、上位のTCustomEditクラスから継承したものです。
コンポーネントの Create コンストラクターは仮想メソッドなのでオーバーライドできます。これをオーバーライドすることで、独自の初期化処理を記述できるようになります。

Createコンストラクターのオーバーライド

TCustomNumberEditのCreateコンストラクターは、以下のように定義します(54行目)。

public
    { Public 宣言 }
    property Comma: Boolean read FComma write SetComma;
    property Digits: Integer read FDigits write SetDigits;
    property Value: Extended read FValue write SetValue;
    constructor Create(AOwner: TComponent); override;
  published

コンストラクターは通常のメソッドと異なり、constructor 句で始まります。
Createコンストラクターの実装は以下のとおりです。

constructor TCustomNumberEdit.Create(AOwner: TComponent);
begin
  inherited;
  // フィールドの初期化
  FIncrement := 1.0;
end;

Updownボタンのテスト

さて、これでUpdownボタンが機能するはずです。テストしてみましょう。上向きのボタンを押すと、数値が 1 ずつ増加します。また、下向きのボタンを押すと 1 ずつ減少します。うまくいきました。

せっかくUpdownボタンを押したことを感知できるようになったので、ボタンを押したことを示すイベントを発生させられると、より利用価値が高まります。次回は、Updownボタンを押したというイベントを発生できるようにします。

ADs
 

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)