VisibleUpdownプロパティのスコープを変更する – Delphiカスタムコンポーネントの作成 13

投稿者: | 2018年3月21日

前回、VisibleUpdownプロパティを作成し、編集ボックス内にUpdownボタンを表示できるようにしました。
これが正しく動作できるか確認したいのですが、VisibleUpdownプロパティのスコープをprotectedにしたので、プロパティを変更する手段がありません。

VisibleUpdownプロパティのスコープを変更する

スコープが protected だからプロパティを変更できないのなら、スコープを publicpublished に変更すればよいのですが、テストのたびにスコープを変えていたのでは非効率です。
現在コーディングしているのは 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は下位クラスも含めて外部から見えない = 存在しないと同じ)なので、子クラスで再定義はできない。
protectedprotected / public / published
publicpublic / published
publishedpublished

動作テスト

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;

コメントを残す

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

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