前回「解決」した内容ですが,1つ不明なところがありましてもう1回書き込みます.
前回の内容:
https://www.petitmonte.com/bbs/answers?question_id=5187
前回,CheckBox1.OnClick := CheckBoxClickについて,
「これは、チェックのON/OFFが切り替わったときに、CheckBoxClickを
実行するようにしましょうと、定義しているだけで、
CheckBoxClickを
実行しているわけではない。」と教えていただきましたが,
結局はCheckBoxClick関数の中身を実行してるんじゃないでしょうか.
その違いがよく分かりません.
また,CheckBoxClickの宣言をCheckBoxClick(Sender: TObject)ではなく,
CheckBoxClick(Sender: TObject; i: Integer);にしたいですが,無理でしょうか.
なぜか上記のようにすると,実行時エラーが出ます.
イベントとは、メソッドポインタを一つだけ設定できるプロパティーなのです。
>CheckBox1.OnClick := CheckBoxClick
だから、これは、CheckBox1.OnClick というプロパティーに CheckBoxClick という
値を代入しているだけです。実際に CheckBox1 がクリックされたら CheckBoxClick を
呼んでね、ってことです。
で、プロパティーには型があります。TCheckBox.Click の型はヘルプを見ると
property OnClick: TNotifyEvent; ですよね。
type TNotifyEvent = procedure (Sender: TObject) of object;
ですから、この型以外の CheckBoxClick(Sender: TObject; i: Integer); な形の
イベントハンドラは型が違うので代入できません。
もし代入できたとしても、誰がそれを呼ぶんですか?
i: Integer
こんな変数に誰が代入してくれるんですか? イベントハンドラは、出来事が
起こったときに自動的に呼び出されます。普通はコードで呼び出すことは
ありません。(通常のメソッドですから、もちろんコードで呼び出すことも
できますが。)
イカで、Button1をクリックしたとき、メッセージが出たら、あなたの正解
出なければ不正解、ということでFA
procedure TForm1.Button1Click(Sender: TObject);
begin
CheckBox1.OnClick := CheckBoxClick;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
CheckBox1.OnClick := nil;
end;
procedure TForm1.CheckBoxClick(Sender: TObject);
begin
ShowMessage('CheckBoxClick');
end;
うんとさん
ご説明ありがとうございます.よく分かりました.
今やりたいのは,例えば,CheckBoxが40個あって,
5個ずつ1つのグループ,計8つのグループのCheckBoxを操作することです.
で,
for i := 1 to 5 do
TCheckBox(FindComponent('CheckBox' + IntToStr(1) + '_' + IntToStr(i))).OnClick := CheckBoxClick1;
で1個目のCheckBoxグループの処理を;
for i := 6 to 10 do
TCheckBox(FindComponent('CheckBox' + IntToStr(1) + '_' + IntToStr(i))).OnClick := CheckBoxClick2;
で1個目のCheckBoxグループの処理を...
させたいです.
それで,もし,CheckBoxClick(Sender: TObject; i: Integer);が使えれば,
iを変化させ,CheckBox1〜5の時はCheckBoxClick1を;
CheckBox6〜10の時は,CheckBoxClick2を...実行したら良いなと思ったわけです.
これはFAQの一つです。
共通のイベントハンドラを割り当てたとき、どのコンポがイベントを起こしたのか
を知りたいのでしょう?
一番簡単なのは、Tag プロパティーを使う方法です。
新規で Form1 に CheckBox1-3 を置いてください。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
CheckBox3: TCheckBox;
procedure FormCreate(Sender: TObject);
private
procedure KyotuuCheckBoxClick(Sender: TObject);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
cb: TCheckBox;
begin
for i := 1 to 3 do
begin
cb := TCheckBox(FindComponent('CheckBox' + IntToStr(i)));
cb.OnClick := KyotuuCheckBoxClick;
cb.Tag := i;
end;
end;
procedure TForm1.KyotuuCheckBoxClick(Sender: TObject);
var
no: integer;
begin
no := TCheckBox(Sender).Tag;
Showmessage('CheckBox'+ IntToStr(no) + ' Clicked!');
end;
end.
どれかのCheckBoxをクリックするたびのメッセージが表示されます。
TRadioGroupを使うのは駄目なのでしょうか?
どのコンポがイベントを起こしたのだけなら,
CheckBox1〜3までの.CheckedがTureかどうか調べれば良いので簡単ですが,
やりたいのは,5個ずつ1つのグループの40個のCheckBoxを,
グループ毎に排他的選択をさせたいです.
TRadioGroupを使ったら一番簡単ですが,
どうしてもCheckBoxを使って実現したいと思いまして...
>CheckBox1〜3までの.CheckedがTureかどうか調べれば良いので簡単ですが,
そんなことはありません。true/false はクリックするたびに入れ替わりますから。
>グループ毎に排他的選択をさせたいです.
ですから、Tag に1−40の番号を付けておけば、今クリックされたのが何番で
どのグループに属するかが分かると思いますけど。なにが問題なのですか?
うんとさん
ご指摘の通りですが,Tagを使う方法だと,
CheckBoxの排他的処理が面倒になるような気がします.
下記のページ
https://www.petitmonte.com/bbs/answers?question_id=5187
にある,
TCheckBox(FindComponent('CheckBox' + IntToStr(i))).OnClick := nil;
if Sender <> TCheckBox(FindComponent('CheckBox' + IntToStr(i))) then
TCheckBox(FindComponent('CheckBox' + IntToStr(i))).Checked := False;
TCheckBox(FindComponent('CheckBox' + IntToStr(i))).OnClick := ClickCheckBox;
よりは.
CheckBox1−15 で5個ずつ3グループの例を示します。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
CheckBox3: TCheckBox;
CheckBox4: TCheckBox;
CheckBox5: TCheckBox;
CheckBox6: TCheckBox;
CheckBox7: TCheckBox;
CheckBox8: TCheckBox;
CheckBox9: TCheckBox;
CheckBox10: TCheckBox;
CheckBox11: TCheckBox;
CheckBox12: TCheckBox;
CheckBox13: TCheckBox;
CheckBox14: TCheckBox;
CheckBox15: TCheckBox;
procedure FormCreate(Sender: TObject);
private
cb: array[1..15] of TCheckBox;
procedure CBClick(Sender: TObject);
public
{ Public 宣言 }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer;
ccb: TCheckBox;
begin
for i := 1 to 15 do
begin
ccb := TCheckBox(FindComponent('CheckBox'+IntToStr(i)));
ccb.OnClick := CBClick;
ccb.Tag := i;
cb[i] := ccb;
end;
end;
procedure TForm1.CBClick(Sender: TObject);
var
i, j, t: integer;
begin
t := TCheckBox(Sender).Tag;
j := ((t - 1) div 5) * 5 + 1;
for i := j to j+4 do
begin
cb[i].OnClick := nil;
cb[i].Checked := false;
end;
cb[t].Checked := true;
for i := j to j+4 do
cb[i].OnClick := CBClick;
end;
end.
FindComponent を毎回使うのは非効率ですから、一度だけ配列にとって
おきます。40個8グループに拡張してみてください。
うんとさん
さすがですね!感心しました!
Tag プロパティーを利用すると本当に簡単ですし,すっきりしますね.
勉強になりました.解決です!
ツイート | ![]() |