こんにちは
奇妙な(あほうな)ことをおききすることになるかもしれませんが
どうしても理解できないことがあります。ご教授願いませんでしょうか?
現在カスタムコンポーネントを作っておりますがそれに対するイベントの
実装についてどうしても理解できないことがあります。誤りがあれば
つっこんでいただけませんでしょうか?
基本的な理解がおかしいのでしょうか?
あるコンポーネントにおいてメソッドが実行されたとき通常いくつかの
プロパティが変化する。それらひとつひとつがイベントである。それぞれの
イベントを発生させるメソッドは決まっていてあるイベントの動作を変更
させたいならそれを引き起こすメソッドをオーバーライドし、処理を変更
する。
イベントの考え方はこれでよろしいでしょうか?ならば
たとえばあるコンポーネントでOnKeyPressを定義(変更)したいなら
KeyPressをオーバーライドする(細かい処理は省略)
procedure KeyPress(Sender: TObject; var key char); pverride;
...
published
property OnKeyPress;
...
procedure XXX.KeyPress(Sender: TObject; var key char);
begin
inherited KeyPress(key);
showmessage(key);
end;
これでたとえばTEditのようなコントロールでキー入力をするたびに入力
された文字がメッセージボックスに出るはずですがこれはよいのです
(理解できる)が、TTreeViewでOnEditedイベントの処理を変更したくて
Editイベントをオーバーライドするような場合にはどうでしょう?
OnEditedの引数は(Sender: TObject; Node: TTreeNode; var S:string)
ですがEditの引数は (const Item: TTVItem)です。引数が違いますよね。
これだと前出したOnKeyPressの例のような標準イベントが持つ引数を使う
処理ができないと思うのですがどうでしょう?こんな風にです
procedure Edit(const Item: TTVItem); override;
...
published
property OnEdited;
...
procedure XXX.Edit(const Item: TTVItem);
begin
inherited Edit(Item);
showmessage(S) <---こういったことしたくてもできませんよね。
end;
私の考えでいくと、あるイベントとそれを引き起こすメソッドは1対1
(または多対1)で対応しており、それぞれの引数は一致していないと
おかしい(使えない)のではないかと思うのです。特にOnEditedとEdit
のように共通部分がまったくないのはどういうことか?と考えているの
ですが...おかしいでしょうか?
わっとっと
複数の知りたい事を同時に聞かれても答えるのに苦労します。
Delphiは命名規則がしっかしている言語ですので
質問内容の部分から回答すると
Edit:メソッド(関数)
OnEdited:イベント
メソッドとイベントには何の関連もありませんよ
イベントを発生させるだけのメソッドであれば
OnをDoに変えたものを使用します。
OnEditedを発生させるだけのメソッドはDoEditedになります。
EditとOnEditedは無関係なので引数は一致しません。
Edit内で何が起きているのかは
ComCtrlsユニットの
procedure TCustomTreeView.Edit(const Item: TTVItem);
を参考にしてはいかがでしょうか?
具体的に何をしたいのかがわかれば力にもなれます
質問が煩雑かつわかりにくくて申し訳ありません
やりたいこととわからないことははこういうことです
「既存のコンポーネントを改良したコンポーネントを作りたい。」
「イベントハンドラは私の場合どういうアプリケーションを作るときでも
たいてい決まっているのでアプリケーション本体には書かず、処理を
コンポーネントのユニットに書くようにしたい。そうすればどのような
アプリケーションを作るときでもusesするだけで済むので自分としては
RADだと考えた。」
「しかしその際にイベントを実装するやり方でつまずいた。」というわけ
です。改良コンポーネントMyEditを作ってみました。コードを見てください。
unit MyEdit;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TREdit =class(TEdit)
protected
procedure DoEnter; override; ...(1)
procedure KeyPress(var Key: Char); override; ...(2)
procedure rClick(Sender: TObject);...(3)
published
property OnEnter; ...(1)
property OnKeyPress; ...(2)
property OnClick; ...(3)
public
constructor CreateEX(Origin :TEdit);
end;
implementation
constructor TREdit.CreateEX(Origin :TEdit);
begin
OnClick := rClick; ...(3)
end;
procedure TREdit.DoEnter; ...(1)
begin
inherited DoEnter;
showmessage('Enter!');
end;
procedure TRedit.KeyPress(var Key: Char); ...(2)
begin
inherited KeyPress(Key);
showmessage(key);
end;
procedure TREdit.rClick; ...(3)
begin
showmessage('Click!');
end;
end.
(1)(2)(3)と実装してみました(1)(2)は機能しますが(3)はエラーにはなり
ませんが実行しても機能しません(3)は直感的にはわかりやすいのですが
だめなのでしょうか。
また(2)はKeyPressがOnKeyPressを発生させているのではないのでしょうか。といった風に実装に関してわからないことが山積しております。
わっとっと
クラスを学びたいのであればとりあえず基本的なTObjectから入ると楽ですよ。
Windowsコントロールを含むクラスはその後のほうが効率的だとおもいますよ。
Clickは
TControlのprotectedで
procedure Click; dynamic;
と定義されていますね。
継承するなら
procedure Click; ovrride;
ですよ。
>イベントハンドラは私の場合どういうアプリケーションを作るときでも
> たいてい決まっているのでアプリケーション本体には書かず、処理を
> コンポーネントのユニットに書くようにしたい
なるほど、言いたい事はおよそ理解しました。
コンポーネントの設計としては正しい考えです。
そして様々なイベントを捕まえてコンポーネント側で
処理したいけど特にイベントが思うようにいかない
というわけですね。
>KeyPressがOnKeyPressを発生させているのではないのでしょうか
わからなければF7でトレースしていけばいいです。
標準ライブラリは普通トレースできませんが
プロジェクト→オプション→コンパイラ→デバッグ版DCUを使う
にチェックを付けてコンパイルする事で
どこまでもトレースする事が出来ます。
Standerd版は無理かも
クラス、特にオブジェクト指向は最初は大変かもしれませんが
一度理解してしまえば全ての言語で使える技術でもありますので
やって損は無いかと思います
constructor TREdit.CreateEX(Origin :TEdit);
begin
OnClick := rClick; ...(3)
end;
rClickは見たところ TNotifyEventのハンドラのようですが
CreateExのほかの部分はそのままに OnClickのイベントハンドラの指定のみを
procedure Afterconstruction; override;
あるいは
constructor Create(AOwner:TComponent); override
にうつしたらどうなりますかね・・・。
OnClickを指定しなくとも
monaa さんもおっしゃってますが
procedure Click; override;
で
procedure TREdit.Click;
begin
// inherited Click;
showmessage('Click!');
end;
とすると目的が達成できるように思います。
この場合、inherited Click をやらないと
property OnClick に Assignした TNotifyEventは呼ばれませんが
showmessageは実行されます。
ツイート | ![]() |