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つが考えられます。
- Updownボタンから、TCustomNumberEditの特定のメソッドを呼び出して、TCustomNumberEditに数値を変更してもらう方法
- Updownボタンから、TCustomNumberEditのValueプロパティを直接変更する方法
- 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ボタンを押したというイベントを発生できるようにします。