喫茶XRAYトップページ


[1018] TStringList.OnChangeは使えるのでしょうか返信 削除
2006/11/19 (日) 15:01:33 taki
マスター、皆さん こんにちは。

また、お聞きしたいことがあります。

動的に作成したTStringListのOnChangeイベントは使えるのでしょうか。
使えるとしたら、どのようなコードを記述したら良いのでしょうか。

例えば、
SLというStringListを動的に作成して、SL.ADD('abc')などをすると
ShowMessage('SLは変化しました!')を実行したいのです。

よろしくお願いします。

[1019] Re:TStringList.OnChangeは使えるのでしょうか返信 削除
2006/11/19 (日) 17:13:46 Mr.XRAY
> 動的に作成したTStringListのOnChangeイベントは使えるのでしょうか。

TStringListにはOnChangeイベントがあります。
ヘルプで調べると、このOnChaneはTNotifyEventで、TNotifyEventは

type TNotifyEvent = procedure (Sender: TObject) of object;

となっています。したがって、OnChangeのprocedureを作成してOnChangeに
結びつけます。
このProcedureをSLOnChageという名前にして、Private部に書くとすると、
例えば以下の様にできます。

  private
    { Private 宣言 }
    procedure SLOnChange(Sender: TObject);
  public
    { Public 宣言 }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.Button1Click(Sender: TObject);
var
     SL : TStringList;
begin
     SL:=TStringList.Create;
     SL.OnChange:=SLOnChange;
     try
       SL.Add('ABC');
     finally
       FreeAndNil(SL);
     end;
end;

procedure TForm1.SLOnChange(Sender: TObject);
begin
     ShowMessage(TStringList(Sender).Text+'を追加しました  ');
end;

動作確認 Delphi5 + WindowsXP

[1020] Re2:TStringList.OnChangeは使えるのでしょうか返信 削除
2006/11/19 (日) 19:46:38 taki
▼ Mr.XRAYさん

ありがとうございます。 やってみるとうまく動きました。
これで、プログラムがシンプルで効率良くなります。
実は、今作っているプログラムでは、表示の度にデータの変更の有無に関わらず
検索用のリストを再作成していたのです。
 
> ヘルプで調べると、このOnChaneはTNotifyEventで、TNotifyEventは
>
> type TNotifyEvent = procedure (Sender: TObject) of object;
>
> となっています。したがって、OnChangeのprocedureを作成してOnChangeに
> 結びつけます。


TStringListまでは調べたのですが、TNotifyEventは調べていませんでした。
D2005のヘルプで調べてみると、
「イベントはプロパティであり、イベントの型はメソッドポインタ型」???

procedureXXXは手続きのアドレス(ポインタ?)になるのかな。
だから、SL.OnChangeイベント=プロパティにSLOnChange手続きのアドレスを
代入できると考えたら良いのでしょうか。

それと、どうしても理解できない物に、Senderがあります。

> ShowMessage(TStringList(Sender).Text

上のコードのSenderは何を表しているのでしょうか?

[1021] Re3:TStringList.OnChangeは使えるのでしょうか返信 削除
2006/11/19 (日) 20:10:57 Mr.XRAY
▼ takiさん

> だから、SL.OnChangeイベント=プロパティにSLOnChange手続きのアドレスを
> 代入できると考えたら良いのでしょうか。

です。=でポインタ(関数、プロシージャーのアドレス)を設定しています。

> 上のコードのSenderは何を表しているのでしょうか?
提示のコードでは生成したSLです。
この場合のSenderはTObjectです。TObjectは何でも扱えますが、型情報は
キャストする必要があるため、TStringList(Sender)としています。
(Sender.Textでは取出せない。Senderには元のクラスが何であるかという
情報はなく、引数のオブジェクトのポインタだけ)
したがって、

TStringList(Sender).Text は SL.Text とも書けますが、Senderとしておけば、
生成したTStringListの名前が何であっても汎用的に使用できますから。
これはコードの可読性とも関係ありますので、ケースバイケースですね。

ただ、注意すべきは、提示のコードではAddしたのが一つだけですけど、
既に、または複数のLinesプロパティがある時は、Textはその全てとなって
しまいます。あくまでも例としてですので、その点よろしく。

[1022] Re4:TStringList.OnChangeは使えるのでしょうか返信 削除
2006/11/19 (日) 21:08:16 taki
▼ Mr.XRAYさん

イベントとSenderが少し理解できたような気がします。

ありがとうございます。


[1023] クラスとイベントとSenderの関係は返信 削除
2006/11/20 (月) 09:34:48 taki
▼ Mr.XRAYさん

今回質問しましたTStringListを例にすると
クラスはTStringListのプロパティ、イベント、メソッドを
定義している。

SL1,SL2:TStringListの2つのオブジェクトを生成すると、

SL1,SL2毎にプロパティ、イベントのメモリ領域が確保される。
また、SL1,SL2に共有のメソッドのコードが作成される。

変数SL1,SL2には確保されたメモリ領域(= object?)のポインタが
代入される。

次に、イベントの手続きである
procedure TForm1.SLOnChange(Sender: TObject);
begin
     ShowMessage(TStringList(Sender).Text+'を追加しました ');
end;
は、TFormクラスの中に作成されるコードでそのポインタは
TForm1.SLOnChangeの中に入っている。
 ※TFormの中に必ず記述する必要があるのでしょうか?

SL1.OnChange:=SLOnChange; することで

SL1のイベントのメモリ領域にTForm1.SLOnChangeのポインタが
代入されて呼び出し可能になる。

その後、SL1に変化があると、SL1のポインタと共にイベントが
呼び出される。

呼び出されたTForm1.SLOnChange(Sender: TObject)のSenderには
SL1のポインタが入っている。

ただ、SL1はメモリのブロックなので、TStringList型でキャスト
しないとそれぞれの定義の情報にアクセスできない。

同様に、SL2も
SL2.OnChange:=SLOnChange; すると
SL2が変化すると、SL2のポインタと共にイベントが呼ばれる。

だから、TForm1.SLOnChangeイベントのコードは1つだけど、
Senderが変わるのでこの手続きを共有して使うことができる。

と、解釈しました・・・ どうでしょうか?


[1024] Re:クラスとイベントとSenderの関係は返信 削除
2006/11/20 (月) 20:27:38 Mr.XRAY
▼ takiさん

>  ※TFormの中に必ず記述する必要があるのでしょうか?
いけないということはないと思いますが...
どんな具合にしたいのでしょうか。

> と、解釈しました・・・ どうでしょうか?
ですね。

INCM/CMT
Cyclamen v3.82