Prefixプロパティを作成します。Prefixプロパティに任意の文字列を設定すると、プレフィックスを表示できるようにします。プレフィックスとは、数字の先頭に表示される語句です。

プレフィックス
また、プレフィックスの表示をON/OFFできるよう、VisiblePrefixプロパティも作成したいと思います。
プレフィックスの実装方法
プレフィックスを数値の前に表示する方法を考えておきます。この方法には3とおりが考えられます。
1つめの方法
1つめの方法は、単純にPrefixとValueをつなげて、1つの文字列にしてしまう方法です。プログラムで書くと以下のようになります。
Text := FPrefix + FloatToStr(Value);
この方法は表示が簡単ですが、ユーザーの入力をチェックする際は手間がかかります。また、ユーザーによっては数値を入力する際、プレフィックを消さないようにと余計な気を遣うことがあるかもしれません。
2つめの方法
2つめの方法は、背景の一部として描画する方法です。単なる背景の一部として描画されるので、ユーザーが選択したり編集したりできません。ユーザーが入力の際に、余計な気を遣うこともないでしょう。ただし、描画されたプレフィックスと、編集可能な数値が重なって表示されないように工夫が必要です。
この方法ではコントロールのキャンバスに文字列を描画することになるため、キャンバスへのアクセス方法を用意しなければなりません。TCustomControlクラスの派生クラスであれば、Canvasプロパティによってキャンバスへアクセスできますが、TCustomEditクラスにCanvasプロパティはありません。これを自前で実装する必要があります。
3つめの方法
3つめの方法は、ラベルコントロールなどを編集ボックスの内側に配置する方法です。編集ボックス内に Align := alLeft
で配置すれば、表示や幅の変更が手軽に行えます。ユーザーがプレフィックスの文字列を編集することもありません。Updownボタンを内側に配置したのと同じ方法です。
TNumberEditでは3つめの方法を採用します。
プレフィック用ラベルコントロールの定義
プレフィックの表示にはラベルコントロールを使用します。既存のTLabelを使用することもできますが、プロパティの調整が最小で済むようにTCustomLabelから派生した独自のラベルコントロールを作成します。
TPrefixLabelクラスの定義
プレフィックスに使用するラベルコントロールは、名前を TPrefixLabel にします。なお、これは後の Suffix プロパティの実装にも使用します。コードは以下のとおりです。
// プレフィックス・サフィックス用ラベル
TPrefixLabel = class(TCustomLabel)
private
protected
public
end;
必要な機能はすべてそろっているので、追加するプロパティやメソッドなどはありません。ただし、あとでプロパティの初期値を調整する必要はあるかもしれません。
Prefixプロパティの追加
FPrefixLabelフィールドの追加
TPrefixLabelのインスタンスを保持しておくために、FPrefixLabelフィールドをTCustomNumberEditクラスに追加します。以下のように記述します(32行目)。
TCustomNumberEdit = class(TCustomEdit)
private
{ Private 宣言 }
FComma: Boolean;
FDigits: Integer;
FIncrement: Extended;
FOnUpdownClick: TNotifyEvent;
FPrefixLabel: TPrefixLabel;
CreatePrefixLabelメソッドの追加
ラベルを表示させるには、TPrefixLabelのインスタンスを生成する必要があります。このインスタンスを生成するためのメソッドを、先に作成しておきましょう。メソッド名を CreatePrefixLabel とします。
CreatePrefixLabelメソッドの定義
定義は以下のようになります(36行目)。
TCustomNumberEdit = class(TCustomEdit)
private
{ Private 宣言 }
FComma: Boolean;
FDigits: Integer;
FIncrement: Extended;
FOnUpdownClick: TNotifyEvent;
FPrefixLabel: TPrefixLabel;
FUpdown: TInnerUpdown;
FValue: Extended;
procedure AdjustUpDown;
procedure CreatePrefixLabel;
CreatePrefixLabelメソッドの実装
CreatePrefixLabelメソッドではTPrefixLabelクラスのインスタンスを生成します。また、親(Parent)を自分自身(TCustomNumberEdit)に設定して、内側に表示されるよう設定します。コードは以下のとおりです。
procedure TCustomNumberEdit.CreatePrefixLabel;
begin
if FPrefixLabel <> nil then Exit;
FPrefixLabel := TPrefixLabel.Create(Self);
FPrefixLabel.Parent := Self;
FPrefixLabel.Align := alLeft;
end;
Prefixプロパティの定義
Prefixプロパティを定義します。スコープは public にします。定義は以下のとおりです(67行目)。
public
{ Public 宣言 }
property Comma: Boolean read FComma write SetComma;
property Digits: Integer read FDigits write SetDigits;
property Prefix: string read GetPrefix write SetPrefix;
GetPerfixメソッド
プロパティの読み取りは、GetPrefixメソッドを使用します。
GetPrefixメソッドの定義
GetPrefixメソッドは privete 部で以下のように定義します(39行目)。
procedure CreateUpDown;
function GetPrefix: string;
function GetVisibleUpdown: Boolean;
GetPrefixメソッドの実装
実装は以下のとおりです。
function TCustomNumberEdit.GetPrefix: string;
begin
if FPrefixLabel = nil then
Result := ''
else
Result := FPrefixLabel.Caption;
end;
SetPrefixメソッド
続いてSetPrefixメソッドを作成します。
SetPrefixメソッドの定義
SetPrefixメソッドの定義は以下のとおりです(43行目)。
procedure SetDigits(const Value: Integer);
procedure SetPrefix(const Value: string);
procedure SetValue(const Value: Extended);
SetPrefixメソッドの実装
SetPrefixメソッドではFPrefixLabelのキャプションに文字列を設定したあと、ラベルと数値が重なって表示されないように、編集領域を調整する必要があります。
SetPrefixメソッドの実装部分を記述します。コードは以下のとおりです。AdjustEditRectメソッドはこのあと作成します。
procedure TCustomNumberEdit.SetPrefix(const Value: string);
begin
CreatePrefixLabel;
FPrefixLabel.Caption := Value;
AdjustEditRect;
end;
AdjustEditRectメソッドの作成
編集ボックス内の編集可能な領域を、AdjustEditRectメソッドで調整します。
編集可能な領域は、プレフィックスのほか、Updownボタンと、あとで作成するSuffixプロパティも考慮する必要があります。そのため、AdjustEditRectメソッドで一括して調整した方が効率がよくなります。
AdjustEditRectメソッドの定義
AdjustEditRectメソッドは protected スコープで定義します(49行目)。
protected
{ Protected 宣言 }
procedure AdjustEditRect;
AdjustEditRectメソッドの実装
AdjustEditRectメソッドの実装部分は、以下のとおりです。
procedure TCustomNumberEdit.AdjustEditRect;
var
R: TRect;
begin
R := AdjustUpdown;
if FPrefixLabel <> nil then R.Left := R.Left + FPrefixLabel.Width;
SendMessage(Handle, EM_SETRECT, 0, LPARAM(@R));
end;
97行目、AdjustUpdownメソッドは手続きなので、戻り値はありません。このままでは例外が発生するので、AdjustUpdownメソッドを修正します。
AdjustUpdownメソッドの修正
定義の修正
まず、定義部分を修正します。以下のようになります。
function AdjustUpDown: TRect;
procedure を function に変更し、戻り値に TRect 型を指定します。
実装部の修正
AdjustUpdownメソッドの実装は、以下のように修正します(104、139行目)。
function TCustomNumberEdit.AdjustUpDown: TRect;
var
BtnRect: TRect;
EditRect: TRect;
BorderWid: Integer;
begin
// コントロールのハンドルがないときは処理しない
if not HandleAllocated then Exit;
// ボーダーの幅を取得
if Ctl3D then
BorderWid := GetSystemMetrics(SM_CXEDGE)
else
BorderWid := GetSystemMetrics(SM_CXBORDER);
// ボタンの位置とサイズ
if FUpdown = nil then
begin
BtnRect.Left := Width - (Width - ClientWidth) div 2 - BorderWid;
BtnRect.Right := BtnRect.Left;
BtnRect.Top := 0;
BtnRect.Bottom := ClientHeight;
end
else
begin
BtnRect.Left := Width - (Width - ClientWidth) div 2 - BorderWid -
FUpdown.Width;
BtnRect.Right := BtnRect.Left + FUpdown.Width;
BtnRect.Top := 0;
BtnRect.Bottom := ClientHeight;
FUpdown.BoundsRect := BtnRect;
end;
// 編集領域の調整
EditRect := Rect(0, 0, BtnRect.Left - 2, ClientHeight + 1);
Result := EditRect;
end;
その他の修正
編集領域の調整を AdjustEditRect メソッドで行うようになったため、今まで AdjustUpdown メソッドを呼び出していた部分を修正する必要があります。
CreateHandleメソッドの修正
CreateHandleメソッドの実装部を、以下のように修正します(206行目)。
procedure TCustomNumberEdit.CreateHandle;
begin
inherited;
AdjustEditRect;
end;
SetVisibleUpdownメソッドの修正
SetVisibleUpdownメソッドの実装部を、以下のように修正します(401行目)。
procedure TCustomNumberEdit.SetVisibleUpdown(const Value: Boolean);
begin
if Value then
begin
if FUpdown = nil then CreateUpDown;
FUpdown.Visible := True;
end
else
if FUpdown <> nil then FUpdown.Visible := False;
AdjustEditRect;
end;
TPrefixLabelの調整
ここまででプレフィックを表示できるようになりました。テストして若干気になる部分がありますので、調整しましょう。
気になる箇所は1つだけで、プレフィックスの縦方向の文字配置です。縦方向の配置はLayoutプロパティで指定でき、Layoutプロパティの初期値は tlTop です。初期値を tlTop から tlCenter に変更します。
Createコンストラクターの定義
プロパティの初期値を設定するのは Create コンストラクターが適しています。Createコンストラクターをオーバーライドして、Layoutプロパティの初期値を変更します。
Createコンストラクターの定義は以下のとおりです(22行目)。
TPrefixLabel = class(TCustomLabel)
private
protected
public
constructor Create(AOwner: TComponent); override;
end;
Createコンストラクターの実装
実装は以下のとおりになります。
constructor TPrefixLabel.Create(AOwner: TComponent);
begin
inherited;
Layout := tlCenter;
end;
これで、TPrefixLabelのLayoutの初期値が tlCenter になりました。
VisiblePrefixプロパティの作成
VisiblePrefixプロパティを作成します。VisiblePrefixプロパティは Boolean 型のプロパティです。Trueでプレフィックスを表示し、Falseでプレフィックスを隠します。
VisiblePrefixプロパティの定義
VisiblePrefixプロパティを public スコープで定義します。コードは以下のとおりです(70行目)。
public
{ Public 宣言 }
property Comma: Boolean read FComma write SetComma;
property Digits: Integer read FDigits write SetDigits;
property Prefix: string read GetPrefix write SetPrefix;
property Value: Extended read FValue write SetValue;
property VisiblePrefix: Boolean read GetVisiblePrefix write SetVisiblePrefix;
GetVisiblePrefix、SetVisiblePrefixメソッドの定義
read部の GetVisiblePrefix メソッドと、writer部の SetVisiblePrefix メソッドの定義は以下のとおりです。
function GetPrefix: string;
function GetVisiblePrefix: Boolean;
function GetVisibleUpdown: Boolean;
procedure SetComma(const Value: Boolean);
procedure SetDigits(const Value: Integer);
procedure SetPrefix(const Value: string);
procedure SetValue(const Value: Extended);
procedure SetVisiblePrefix(const Value: Boolean);
procedure SetVisibleUpdown(const Value: Boolean);
GetVisiblePrefixメソッドの実装
GetVisiblePrefixメソッドの実装は以下のとおりです。
function TCustomNumberEdit.GetVisiblePrefix: Boolean;
begin
if FPrefixLabel = nil then
Result := False
else
Result := FPrefixLabel.Visible;
end;
SetVisiblePrefixメソッドの実装
SetVisiblePrefixメソッドの実装は以下のとおりです。
procedure TCustomNumberEdit.SetVisiblePrefix(const Value: Boolean);
begin
CreatePrefixLabel;
FPrefixLabel.Visible := Value;
AdjustEditRect;
end;
AdjustEditRectメソッドの修正
AdjustEditRectメソッドではプレフィックスの表示・非表示状態を考慮していませんでしたので、これを修正します(101-103行目)。
procedure TCustomNumberEdit.AdjustEditRect;
var
R: TRect;
begin
R := AdjustUpdown;
if FPrefixLabel <> nil then
if FPrefixLabel.Visible then
R.Left := R.Left + FPrefixLabel.Width;
SendMessage(Handle, EM_SETRECT, 0, LPARAM(@R));
end;
以上で、プレフィックスの実装が完了しました。