[最終更新日 1999/03/23]
上位クラスの既存処理の動作を変更することをオーバーライド(override)すると言います。オーバーライドにより新しい機能を追加することができます。
ここではオーバーライドを利用してキー入力処理を変更して、数値のみを受け付けるようにします。
TEdit でキー入力の制限を行う場合、どのようにするのでしょうか。普通は
OnKeyPress イベントで無視したいキーが入力された場合、
Key コードを無効(0)にしますね。ということは
OnKeyPress を呼び出す元のメソッドをオーバーライドできれば良いわけです。
(ここで TUIntEdit コンポーネントの OnKeyPress
イベントハンドラで入力制限を行えば良いのでは?という疑問が出てきますが、これでは残念ながら問題が起きてしまいます。コンポーネントを利用するアプリケーションはイベントハンドラを自由に変更できるので、コンポーネントがコンストラクタで自分のイベントハンドラをセットしても、後からアプリケーション側で変更される恐れがあります。)
実際に探してみると TEdit のメソッドにはオーバーライドできそうなものがありません。この場合はTEditのヘルプを開き、継承のところから一つ上のクラスを探してみます。TEdit
→ TCustomEdit → TWinControl の順で探すと
TWinControl の KeyPress メソッドが OnKeyPress
を呼び出し、オーバーライド出来るとヘルプに書いてあります
これでオーバーライドするメソッドは見つかりました。
メモ: オーバーライド可能なメソッドは仮想メソッド(Delphi:virtual、C++Builder:virtual)、動的メソッド(Delphi:dynamic、C++Builder:DYNAMIC)のどちらかです。静的メソッド(C++Builder:レギュラーメソッド)はオーバーライドできませんので注意してください。 |
上位クラスの KeyPress をオーバーライドして独自の処理を追加するわけですが、オーバーライドしたままでは上位クラスの処理が呼び出されず、こちらで書いたコードの部分だけが動作します。今回オーバーライドした
KeyPress は OnKeyPress を呼び出す処理を行っているので、その部分を呼び出す必要性があります。
そこでオーバーライドした上位メソッドを呼び出す記述を書いておけば、機能を追加しても正しく
OnKeyPress が呼び出されます。
メモ: Pro版やCSS版、ENT版を持っている場合、VCLのソースを覗いてみましょう。 Pascalで記述してあるのでC++Builderユーザには辛いかもしれませんが、まったく読めないこともないはずなので処理を見て大体の内容を理解すればオーバーライドの記述も簡略化できるかもしれません。 |
では実際に6桁までの数値('0'〜'9')入力機能を、オーバーライドしたKeyPressに実装してみましょう。
ここで大切なのは、いつ上位処理を呼び出すかということです。最初に上位処理を呼び出す場合もありますが、今回は入力されたキーをあらかじめ処理した上で、上位処理を呼び出すようにします。
unit UIntEdit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TUIntEdit = class(TEdit) private { Private 宣言 } function GetUIntValue: Integer; procedure SetUIntValue(AValue: Integer); protected { Protected 宣言 } procedure KeyPress(var Key: Char); override; public { Public 宣言 } published { Published 宣言 } property UIntValue: Integer read GetUIntValue write SetUIntValue; end; procedure Register; implementation procedure Register; begin RegisterComponents('MyCompo', [TUIntEdit]); end; function TUIntEdit.GetUIntValue: Integer; begin // Textプロパティを数値に変換、変換できない場合は0とする Result := StrToIntDef(Text, 0); end; procedure TUIntEdit.SetUIntValue(AValue: Integer); begin if AValue <> StrToIntDef(Text, 0) then begin // 代入された値がTextプロパティと一致しない if (AValue >= 0) and (AValue <= 999999) then begin // 範囲内なのでTextプロパティに文字列変換して代入 Text := IntToStr(AValue); end else begin // 範囲外なので例外を起こす raise ERangeError.Create('UIntValueプロパティに範囲外の値が代入された'); end; end; end; // TWinControl.KeyPress メソッドのオーバーライド procedure TUIntEdit.KeyPress(var Key: Char); begin if (Key >= '0') and (Key <= '9') then begin // '0'〜'9' if Length(Text) >= 6 then begin // 6桁以上入力した場合 Beep; Key := #0; end; end else begin // 数値以外のキー if Key <> #8 then begin // 数値とBSキー以外の場合 Beep; Key := #0; end; end; inherited; // TWinControl.KeyPress メソッドの呼び出し end; end.
/--------------------------------------------------------------------------- #ifndef UIntEditH #define UIntEditH //--------------------------------------------------------------------------- #include <SysUtils.hpp> #include <Controls.hpp> #include <Classes.hpp> #include <Forms.hpp> #include <StdCtrls.hpp> //--------------------------------------------------------------------------- class PACKAGE TUIntEdit : public TEdit { private: int __fastcall GetIntValue(void); void __fastcall SetIntValue(int AValue); protected: DYNAMIC void __fastcall KeyPress(char &Key); public: __fastcall TUIntEdit(TComponent* Owner); __published: __property int UIntValue = {read=GetIntValue, write=SetIntValue}; }; //--------------------------------------------------------------------------- #endif
//--------------------------------------------------------------------------- #include <vcl.h> #pragma hdrstop #include "UIntEdit.h" #pragma package(smart_init) //--------------------------------------------------------------------------- // ValidCtrCheck は作成されたコンポーネントが純粋仮想関数を持たないことを // 保証するために使用されます。 // static inline void ValidCtrCheck(TUIntEdit *) { new TUIntEdit(NULL); } //--------------------------------------------------------------------------- __fastcall TUIntEdit::TUIntEdit(TComponent* Owner) : TEdit(Owner) { } //--------------------------------------------------------------------------- namespace Uintedit { void __fastcall PACKAGE Register() { TComponentClass classes[1] = {__classid(TUIntEdit)}; RegisterComponents("MyCompo", classes, 0); } } //--------------------------------------------------------------------------- int __fastcall TUIntEdit::GetIntValue(void) { // Textプロパティを数値に変換、変換できない場合は0とする return StrToIntDef(Text, 0); } //--------------------------------------------------------------------------- void __fastcall TUIntEdit::SetIntValue(int AValue) { if(AValue != StrToIntDef(Text, 0) ){ // 代入された値がTextプロパティと一致しない if((AValue >= 0) && (AValue <= 999999)){ // 範囲内なのでTextプロパティに文字列変換して代入 Text = IntToStr(AValue); } else{ // 範囲外なので例外を起こす throw ERangeError("UIntValueプロパティに範囲外の値が代入された"); } } } //--------------------------------------------------------------------------- // TWinControl::KeyPress メソッドのオーバーライド void __fastcall TUIntEdit::KeyPress(char &Key) { if( ('0' <= Key) && (Key <= '9') ){ // '0'〜'9' if(Text.Length() >= 6){ // 6桁以上入力した場合 Beep(); Key = 0; } } else{ // 数値以外のキー if(Key != '\b'){ // 数値とBSキー以外の場合 Beep(); Key = 0; } } TWinControl::KeyPress(Key); // TWinControl::KeyPress メソッドの呼び出し } //---------------------------------------------------------------------------
今回はテストコードは不要です。そのまま実行して色々キーを押してみましょう。
さてここまでやってみてどうでしょうか?
オーバーライドを使うと、少しのコード追加で機能を変更することができますね。
さて次はメソッドの追加にチャレンジです。
レッツ、トライ!コンポーネント