前回、VisibleUpdown
プロパティを作成し、編集ボックス内にUpdownボタンを表示できるようにしました。
これが正しく動作できるか確認したいのですが、VisibleUpdown
プロパティのスコープをprotected
にしたので、プロパティを変更する手段がありません。
VisibleUpdownプロパティのスコープを変更する
スコープが protected
だからプロパティを変更できないのなら、スコープを public
か published
に変更すればよいのですが、テストのたびにスコープを変えていたのでは非効率です。
現在コーディングしているのは TCustomNumberEdit
クラスです。しかし、実際にアプリケーションで使用するのは、TNumberEdit
クラスになります。TNumberEdit
クラスではアプリケーションから VisibleUpdown
プロパティを変更できるようにしなければ、プロパティを作った意味がありません。
そこで、TCustomNumberEdit
クラスの VisibleUpdown
プロパティはprotected
スコープのままで、TNumberEdit
クラスでスコープを変更すれば、動作テストも可能になります。そもそも、TNumberEdit
クラスでは VisibleUpdown
プロパティのスコープを変更する必要があるのは、前にも述べたとおりです。
プロパティの再定義
親のクラスで定義されているプロパティを、子のクラスでスコープ変更する場合、プロパティを再定義します。プロパティの再定義は、以下のように変更したいスコープ部分で、プロパティの宣言を行うだけです(publishedに変更する場合)。
子クラス = class(親クラス)
published
property プロパティ名;
end;
VisibleUpdownプロパティの再定義
VisibleUpdown
プロパティを、TNumberEdit
クラスで再定義し、スコープを published
に変更します。コードは以下のようになります。
TNumberEdit = class(TCustomNumberEdit)
published
property VisibleUpdown;
end;
52行目末尾のセミコロンが削除されていることに注意してください。
元のスコープを、どのスコープにも変更できるわけではありません。スコープを公開する方向へは変更できますが、スコープを隠す方向へは変更できません。元のスコープと、変更可能なスコープを表にまとめました。
元のスコープ (親クラス) | 変更(再定義)可能なスコープ |
---|---|
private | なし (privateは下位クラスも含めて外部から見えない = 存在しないと同じ)なので、子クラスで再定義はできない。 |
protected | protected / public / published |
public | public / published |
published | published |
動作テスト
VisibleUpdownプロパティの動作テストができるようになりました。
実際に動かしてみるとUpdownボタンは表示されますが、2つほど問題があります。
一つは、ボタンをクリックしても、数値が変更されないことです。今はまだボタンを表示しているだけで、ボタンのクリックに対する処理を記述していませんので、数値が変わらないのは仕方ありません。これは次回から修正します。
もう一つは、ボタンに数字が重ならないようにしたにもかかわらず、重なって表示されてしまうことです。
編集領域の調整
ボタンが数字に重ならないようにするため、SendMessage
関数で EM_SETRECT
をコントロールのウィンドウに送信しています(101行目付近)。
実はこの EM_SETRECT で編集領域を調整するには、条件があります。それは、編集ボックスがマルチライン(複数行編集可能)の場合に限られます。TCustomEdit クラスやその下位クラス(TEditなど)は、編集ボックスがシングルライン(1行だけの編集ボックス)に設定されているため、EM_SETRECT
が無効なのです。EM_SETRECT
で編集領域を調整するには、TCustomNumberEdit
クラスの編集ボックスをマルチラインに変更する必要があります。
CreateParamsメソッドの追加
ウィンドウコントロール(親に TWinControl
クラスを持つコントロール)の場合、ウィンドウハンドルが作成される前に CreateParams
メソッドが実行され、ウィンドウコントロールのパラメーターが作成されます。このCreateParams
メソッドをオーバーライドすることで、ウィンドウコントロールのパラメーターを、自分のコンポーネントに合うよう調整できます。
CreateParams
メソッドはスコープが protected
ですので、以下のように protected
部で定義します(36行目)。
protected
{ Protected 宣言 }
procedure Change; override;
procedure CreateParams(var Params: TCreateParams); override;
function IsValidChar(const Key: Char): Boolean; virtual;
実装は以下のとおりです。
procedure TCustomNumberEdit.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.Style := Params.Style or ES_MULTILINE;
end;
CreateParams
メソッドの params
引数が、ウィンドウコントロールに渡されるパラメーターを持っています。params
引数を初期化するために、inherited
を最初に必ず実行します。
そのあと、Params
引数の Style
メンバーに ES_MULTILINE
を追加することで、マルチラインの編集ボックスが作成されるようになります。
編集ボックスがマルチラインになっても、複数行が入力されてしまう心配はありません。なぜなら、KeyPress
メソッドで入力可能な文字を制限しており、Enterキーで改行を入力できないからです。また、クリップボードからの貼り付けにも制限をかけていますので、改行を含む文字列が貼り付けられることもありません。
これで、数字がUpdownボタンと重なって表示されることがなくなりました。
もう一つ、ついでに処理を追加しておきましょう。
ウィンドウハンドルが作成されたときの処理を追加する
SendMessage
関数は、ウィンドウハンドルが存在するときだけ実行できます。そのため、タイミングによってはSendMessage
関数が実行されないため、編集領域がうまく設定されないことも考えられます。このような事態がないように、ウィンドウハンドルが作成されたタイミングで、編集領域が調整されるようにします。
ウィンドウハンドルが作成されると、CreateHandle
メソッドがコンポーネント内部で実行されます。この CreateHandle
メソッドをオーバーライドして、編集領域の調整処理を追加します。
CreateHandle
メソッドはprotected
で、以下のように定義します。
protected
{ Protected 宣言 }
procedure Change; override;
procedure CreateHandle; override;
procedure CreateParams(var Params: TCreateParams); override;
実装は以下のとおりです。
procedure TCustomNumberEdit.CreateHandle;
begin
inherited;
AdjustUpDown;
end;