[最終更新日 1999/03/14]
プロパティは変数と同じように見えますが、実は書きこみ時や読みだし時に処理(手続き、関数等)を経由することで、範囲外の値を受け付けないようにしたり、読みだし時に文字変数を数値に変換するためのものです。
ここでは、そのプロパティを追加してみましょう。
設計時プロパティとはフォーム設計時にオブジェクトインスペクタで操作可能なプロパティ。実行時プロパティはプログラム実行中しか操作できないプロパティです。実行時プロパティはオブジェクトインスペクタで操作不可能なので、プログラムでプロパティ操作のコードを記述する必要性があります。(詳しくはマニュアル参照)
ではこのプロパティをコンポーネントで記述するにはどのようにすれば良いのでしょうか。答えは簡単です。published(C++Builderでは、__published)に記述すれば設計時プロパティ、publicに記述すれば実行時プロパティになります。
プロパティを追加する場合、どちらに配置するか考えてコードを記述してください。
プロパティ読みだしが行われる変数、あるいは処理をreadで指定できます。またプロパティ書きこみが行われる変数、あるいは処理をwriteで指定できます。
設計時プロパティの場合、コンポーネントをフォームに配置したときにオブジェクトインスペクタに表示する初期値を default で指定することができます。ただし、これはプロパティに表示する値だけを初期化するだけで、メンバ変数の初期化までは行いません。メンバ変数を初期化する場合はコンストラクタにコードを記述する必要性があります。
では実際にTextプロパティに入力している文字を数値で取りだせる。また、数値を代入するとTextプロパティに変換した文字列をセットする
UIntValue プロパティを追加してみましょう。
このプロパティは書きこみ、読みだし時に変換処理が入るので
read、write の両方とも処理を呼び出す必要性があります。
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 宣言 } 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; 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: 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プロパティに範囲外の値が代入された"); } } } //---------------------------------------------------------------------------
メモ: SetUIntValue手続き(関数)内で範囲外の場合、例外を発生させています。これはコンポーネント使用者が範囲外の値を代入したとき、値を代入されないバグと勘違いされるのを防ぐためです。例外を使えばデバックの効率がアップするのでうまく利用してください。 プロパティで使用する関数は、read 時は "Get"+"プロパティ名"、write 時は "Set"+"プロパティ名" と書くのが標準的です。 |
ではコンポーネントに追加したプロパティをテストするために、テストコードを書いてみましょう。まずフォームにボタンを3つ配置してください。そのボタンをダブルクリックして以下のコードを追加します。
procedure TForm1.Button1Click(Sender: TObject); begin ShowMessage(IntToStr(UIntEdit1.UIntValue)); end; procedure TForm1.Button2Click(Sender: TObject); begin UIntEdit1.UIntValue := 100; end; procedure TForm1.Button3Click(Sender: TObject); begin UIntEdit1.UIntValue := -100; end;
//--------------------------------------------------------------------------- void __fastcall TForm1::Button1Click(TObject *Sender) { ShowMessage(IntToStr(UIntEdit1->UIntValue)); } //--------------------------------------------------------------------------- void __fastcall TForm1::Button2Click(TObject *Sender) { UIntEdit1->UIntValue = 100; } //--------------------------------------------------------------------------- void __fastcall TForm1::Button3Click(TObject *Sender) { UIntEdit1->UIntValue = -100; } //---------------------------------------------------------------------------
メモ: Button3Click でマイナス値を代入しているのは例外を試すためです。 |
メニューの[実行(R)|実行(R)]で実行してみてください。入力ミスが無ければフォームが表示されます。
それでは以下の操作を行ってみてください。
さてここまでやってみてどうでしょうか?
プロパティを追加したことでもう標準のTEditと違う独自のコンポーネントとなりました。
しかし、数値以外の文字が入力できるのは問題ですね。
さて次は既にある処理のオーバーライドにチャレンジです。
レッツ、トライ!コンポーネント