コンポーネント開発について学習を始めました。
トラックバーが動くとエディットに整数値が表示され、
エディットに整数値が入力されるとトラックバーのつまみが移動する
という、変化を相互に反映させ合うコンポーネントを作ってみようと考えました。
親コンポ(TPanel)の上に子コンポ(TTrackBarとTEdit)を置きました。
ここで2つ分からないことがあります。
①トラックバーが変化したとき、トラックバーのつまみの位置をエディットに反映させるのことになる。そのイベントやプロパティ、プロシージャは?
②エディットに整数値を入れたとき、トラックバーのつまみの位置にどのようにして反映させることになる。そのイベントやプロパティ、プロシージャは?
教えてください。
以下がそのソースです。
unit PanelTrackBarEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls,ComCtrls,StdCtrls;
type
TPanelTrackBarEdit = class(TPanel)
private
{ Private 宣言 }
FTrackBar: TTrackBar;
FEdit: TEdit;
protected
{ Protected 宣言 }
public
{ Public 宣言 }
constructor Create( AOwner: TComponent); override;
published
{ Published 宣言 }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TPanelTrackBarEdit]);
end;
constructor TPanelTrackBarEdit.Create( AOwner: TComponent);
begin
inherited Create(AOwner);
width:= 190;
height:= 30;//100;
//TrackBarを作成
FTrackBar:= TTrackBar.Create(self);
FTrackBar.Parent:= self;
FTrackBar.Top:= 2;
FTrackBar.Left:= 2;
//Editを作成
FEdit:= TEdit.Create(self);
FEdit.Parent:= self;
FEdit.top:=2;
FEdit.Left:= 150;
FEdit.Width:= 30;
FEdit.Text:= inttostr(FTrackBar.position);
end;
end.
Mr.XRAYです.今年もよろしくお願いします.
複数のコンポーネントを持つコンポーネントにはいろいろな種類がありますが,
ingさんのように,そのコンポーネント(PanelTrackBarEdit)を使用したアプリから
TTrackbar,TEditを操作する必要のないコードであれば,以下の考え方でイベント処理が可能です.
1. 内部で生成するコンポーネントに必要なイベントを定義
2. そのイベント内で必要な処理を書く
以下は,Editの値を変更する場合です.(TEditのOnChangeを使用)
//*** が追加した行です(6行)
unit PanelTrackBarEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls,ComCtrls,StdCtrls;
type
TPanelTrackBarEdit = class(TPanel)
private
{ Private 宣言 }
FTrackBar: TTrackBar;
FEdit: TEdit;
protected
{ Protected 宣言 }
procedure EditChange(Sender: TObject); //***
public
{ Public 宣言 }
constructor Create( AOwner: TComponent); override;
published
{ Published 宣言 }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TPanelTrackBarEdit]);
end;
constructor TPanelTrackBarEdit.Create( AOwner: TComponent);
begin
inherited Create(AOwner);
width:= 190;
height:= 30;//100;
//TrackBarを作成
FTrackBar:= TTrackBar.Create(self);
FTrackBar.Parent:= self;
FTrackBar.Top:= 2;
FTrackBar.Left:= 2;
//Editを作成
FEdit:= TEdit.Create(self);
FEdit.Parent:= self;
FEdit.top:=2;
FEdit.Left:= 150;
FEdit.Width:= 30;
FEdit.OnChange := EditChange; //***
FEdit.Text:= inttostr(FTrackBar.position);
end;
procedure TPanelTrackBarEdit.EditChange(Sender: TObject); //***
begin //***
FTrackBar.Position := StrToIntDef(FEdit.Text,0); //***
end; //***
end.
参考になるかどうかはわかりませんが...
http://mrxray.on.coocan.jp/Delphi/plSamples/160_CreateComponent.htm#110
Mr.XRAY さんへ
ありがとうございます。
感動しました。
「すばらしい」の一言に尽きます。
Mr.XRAYさんのコードを参考にして、
「//*」のついている行を付け足してみました。
期待していたとおりの動作です。
これをもとに、コンポーネントのサイズを変えたときに、トラックバーとエディットの位置がうまくいくようにするとか、エディットの広さを変えるとか、いろいろなプロパティやメソッドを付け加えていきながら、勉強を重ねたいと思います。
本当にありがとうございます。
以下が、Mr.XRAYさんのコードをまねして付け加えたものです。
unit PanelTrackBarEdit;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
ExtCtrls,ComCtrls,StdCtrls;
type
TPanelTrackBarEdit = class(TPanel)
private
{ Private 宣言 }
FTrackBar: TTrackBar;
FEdit: TEdit;
protected
{ Protected 宣言 }
procedure EditChange(Sender: TObject); //***
procedure TrackBarChange(Sender: TObject); //*
public
{ Public 宣言 }
constructor Create( AOwner: TComponent); override;
published
{ Published 宣言 }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TPanelTrackBarEdit]);
end;
constructor TPanelTrackBarEdit.Create( AOwner: TComponent);
begin
inherited Create(AOwner);
width:= 190;
height:= 30;//100;
//TrackBarを作成
FTrackBar:= TTrackBar.Create(self);
FTrackBar.Parent:= self;
FTrackBar.Top:= 2;
FTrackBar.Left:= 2;
FTrackBar.OnChange:= TrackBarChange; //*
//Editを作成
FEdit:= TEdit.Create(self);
FEdit.Parent:= self;
FEdit.top:=2;
FEdit.Left:= 150;
FEdit.Width:= 30;
FEdit.OnChange := EditChange; //***
FEdit.Text:= inttostr(FTrackBar.position);
end;
procedure TPanelTrackBarEdit.EditChange(Sender: TObject); //***
begin //***
FTrackBar.Position := StrToIntDef(FEdit.Text,0); //***
end; //***
procedure TPanelTrackBarEdit.TrackBarChange(Sender: TObject); //*
begin //*
FEdit.Text:= intTostr(FTrackBar.Position); //*
end; //*
end.
>これをもとに、コンポーネントのサイズを変えたときに、トラックバーとエディット
もちろんこの方法でいいのですが,また別の方法も書いておきますね.
内部で使用するコンポーネントのクラスを定義して使用する方法です.
この方法は,内部のコンポーネントに対して細かい制御が必要となった場合に有効です.
詳しい説明は省略しますが,テストするのであれば以下の手順がいいでしょう.
1. コンポーネントのコードをバスの通った(とりあえずテスト用のプロジェクト等)に置く
2. テスト用のプロジェクトを作成.コンポはこのテスト用プログラムで生成する.
usesにplPanelTrackBarEditを追加します
ビジュアルなコンポのテストは,実行時に生成するといいです.
コンポーネントの再インストールが必要ありません.もちろん,設計時のデザイン
テストの場合は再インストールが必要です.
----- コンポのコード plPanelTrackBarEdit.pasで保存する --------
unit plPanelTrackBarEdit;
interface
uses
SysUtils, Classes, Controls, ExtCtrls, StdCtrls, ComCtrls, Graphics;
type
//前方参照
//TplTracBarとTplEditSPはコードでは後方で定義しているため,そのままでは参照
//できない
TplTrackBar = class;
TplEditSP = class;
TplPanelTrackBarEdit = class(TPanel)
private
{ Private 宣言 }
FTrackBar : TplTrackBar;
FEdit : TplEditSP;
protected
{ Protected 宣言 }
procedure SetParent(AParent: TWinControl); override;
public
{ Public 宣言 }
constructor Create( AOwner: TComponent); override;
destructor Destroy; override;
property TrackBar : TplTrackBar read FTrackBar write FTrackBar;
property Edit : TplEditSP read FEdit write FEdit;
published
{ Published 宣言 }
end;
//内部コントロールのTTrackBar
//TplPanelTrackBarEditのプロパティ等を利用可能にするためにプロパティを定義
TplTrackBar = class(TTrackBar)
private
FPanelTrackBarEdit : TplPanelTrackBarEdit;
protected
procedure Changed; override;
public
property PanelTrackBarEdit : TplPanelTrackBarEdit read FPanelTrackBarEdit;
end;
//内部コントロールのTEdit
//TplPanelTrackBarEditのプロパティ等を利用可能にするためにプロパティを定義
TplEditSP = class(TCustomEdit)
private
FPanelTrackBarEdit : TplPanelTrackBarEdit;
protected
procedure Change; override;
procedure DoEnter; override;
procedure KeyPress(var Key: Char); override;
public
property PanelTrackBarEdit : TplPanelTrackBarEdit read FPanelTrackBarEdit;
end;
procedure Register;
implementation
uses DebugWndUnit;
procedure Register;
begin
RegisterComponents('plXRAY', [TplPanelTrackBarEdit]);
end;
{ TplTrackBarEdit }
//=============================================================================
// コンポのCreate処理
// ビジュアルな内部コンポーネントはSetParentで生成する
// 非ビジュアルな内部コンポーネントはCreateで生成してよい
//=============================================================================
constructor TplPanelTrackBarEdit.Create(AOwner: TComponent);
begin
inherited;
Caption := '';
Width := 250;
Height := 85;
Color := $00AFBBA6;
//Delphi6以降でXPManを使用する場合はこれがないとTPanelのColorプロパティ
//の設定が反映されない
Self.ParentBackground := False;
end;
//=============================================================================
// コンポのDestroy処理
// 内部コンポーネントを解放する
//=============================================================================
destructor TplPanelTrackBarEdit.Destroy;
begin
if Assigned(FTrackBar) then FreeAndNil(FTrackBar);
if Assigned(FEdit) then FreeAndNil(FEdit);
inherited;
end;
//=============================================================================
// コンポのSetParent処理
// ビジュアルな内部コンポーネントはSetParentで生成する
// SetParentメソッドは何回も呼出されるので注意
//=============================================================================
procedure TplPanelTrackBarEdit.SetParent(AParent: TWinControl);
begin
inherited;
//コンポ破棄の時もSetParentは呼ばれるため,Parentが無い場合は処理をしない
if AParent = nil then exit;
Caption := '';
if not Assigned(FTrackBar) then begin
FTrackBar := TplTrackBar.Create(Self);
FTrackBar.Parent := Self;
FTrackBar.Left := 10;
FTrackBar.Top := 10;
FTrackBar.Height := 35;
FTrackBar.Width := Self.Width-FTrackBar.Left-10;
FTrackBar.Min := 0;
FTrackBar.Max := 100;
FTrackBar.Frequency := 10;
FTrackBar.TickStyle := tsNone;
FTrackBar.FPanelTrackBarEdit := Self;
end;
if not Assigned(FEdit) then begin
FEdit := TplEditSP.Create(Self);
FEdit.Parent := Self;
FEdit.Left := FTrackBar.Left+5;
FEdit.Top := FTrackBar.Top+FTrackBar.Height+3;
FEdit.Width := 45;
FEdit.FPanelTrackBarEdit := Self;
end;
FEdit.SetFocus;
end;
{ TplTrackBar }
//=============================================================================
// TTrackBarコンポ内部でのOnChageイベント処理
// ChangedメソッドをOverrideして作成しておくと自動的にこのメソッドが呼ばれる
//=============================================================================
procedure TplTrackBar.Changed;
begin
inherited;
FPanelTrackBarEdit.FEdit.Text:= IntTostr(Self.Position);
end;
{ TplEditSP }
//=============================================================================
// TEditコンポ内部でのOnChageイベント処理
// ChangeメソッドをOverrideして作成しておくと自動的にこのメソッドが呼ばれる
//=============================================================================
procedure TplEditSP.Change;
begin
inherited;
FPanelTrackBarEdit.FTrackBar.Position :=
StrToIntDef(FPanelTrackBarEdit.FEdit.Text,0);
end;
//=============================================================================
// TEditコンポ内部でのOnEnterイベント処理
// DoEnterメソッドをOverrideして作成しておくと自動的にこのメソッドが呼ばれる
//=============================================================================
procedure TplEditSP.DoEnter;
begin
inherited;
//かな漢字入力を不可にしてしまう
SetImeMode(Handle,imDisable);
end;
//=============================================================================
// TEditコンポ内部でのOnKeyPressイベント処理
// KeyPressメソッドをOverrideして作成しておくと自動的にこのメソッドが呼ばれる
// KeyPressは継承元のTWindControl.pasで定義されている
//=============================================================================
procedure TplEditSP.KeyPress(var Key: Char);
begin
//数値以外は入力させない
//英字は入力できない. #8は[BackSpace]. #27は[Escape]
if ((Key>='0') and (Key<='9')) or (Key=#8) or (Key=#27) then begin
inherited KeyPress(Key);
end else begin
Key:=#0;
end;
end;
end.
------ テストプログラムのコード
//=============================================================================
// 開発中のコンポーネントをフォーム表示開始で生成
// ビジュアルなコンポーネントは,概観を変更すると再インストールが必要になる
// 実行時のテストであれば,実行時に生成してテストすると再インストールが不要
// ただし,設計時の外観変更は再インストールが必要
//=============================================================================
procedure TForm1.FormShow(Sender: TObject);
var
APanelTrackBarEdit : TplPanelTrackBarEdit;
begin
APanelTrackBarEdit := TplPanelTrackBarEdit.Create(Self);
APanelTrackBarEdit.Parent := Self;
APanelTrackBarEdit.Top := 20;
APanelTrackBarEdit.Left := 20;
end;
>コンポーネント開発について学習を始めました。
ということですので,ついでに.
コンポーネント本体の名前,また内部で生成するコントロールやクラス名には
極力ユニークな名前をつけるといいです.
これは他のユニットを使用した時に名前の衝突を避けるためです.
私はプリフィックスとして先頭にplを付けています.
Mr.XRAY さま
しばらくの間、2009/01/06(火) 10:01:15 に回答していただいたことについて学習を進めており、このページを開いていませんでした。
追加情報をありがとうございます。
ただ、当方初心者ゆえ、少々難解です。
繰り返し学習して、少しずつ理解していきたいと思います。
さて、上記ソース(plPanelTrackBarEdit.pas)をコンパイルしようとしたところ、
uses DebugWndUnit;
の行で、致命的エラーがでます。
外部参照のユニットだと思われますが、どこを参照すればよいでしょうか。
Mr.XRAYです.
>uses DebugWndUnit;
>の行で、致命的エラーがでます。
これは,私がデバックのために使用しているユニットです.削除してください.
時々削除を忘れるんです.
実行プログラムをUPしています.もしよろしかったら.
http://mrxray.on.coocan.jp/Delphi/plSamples/160_CreateComponent.htm#112
このページの先頭に[DownLoad]ボタンがあります.
スミマセン.間違いました.今回のは実行時の生成ですから,こちらですね.
http://mrxray.on.coocan.jp/Delphi/plSamples/160_CreateComponent.htm#111
いずれにしても,複数のコンポーネント(コントロール)を持つコンポーネントの
作成は結構難しいと思います.
がんばってください.
Mr.XRAY さん
わずかの間に2つも書き込みしていただき、感謝しています。
紹介していただいたページは、印刷し、何度も見返して学習していきたいと思います。
思いつきで、できもしない課題を設定してしまいました。
Delphi初心者のくせに、高いハードルに挑んで、みなさんにご迷惑をおかけしております。
私にとって雲の上の存在(かってにそう思っています)であるMr.XRAYさんから「がんばってください」と声援を頂き、とてもうれしいです。
これからも、こつこつがんばりたいです。
ありがとうございました。
ツイート | ![]() |