TListBox ないにある項目をクリックしたときに、
以下の条件を調べて、それぞれに対する処理を行いたいのです。
1.何も選択されていない状態から、項目をクリックされた
2.既に選択されている項目と違う項目が選択された。
3.既に選択されている項目と同じ項目が選択された
int BackItem;
を作成し、Create 時に -1 を入れて、
今までなら、クリック時に BackItem を 変更していく方法を
使っていたのですが、
処理のいたるところ等で処理を行った場合に
BackItem を設定しなければならなくなりそうで、
どこかの処理で BackItem がずれてバグになりそうな予感がします。
デバッグで全て取りきれるかどうかもわからないぐらい
処理箇所が多くなるので。
OnClick時に何かのプロパティ等で調べることとか、
OnClick時にItemIndex が変更される前に発生する
BeforeClick イベントとかで処理するといった方法は
できないでしょうか?
OnClick時に BackItem := ListBox1.ItemIndex; ではだめなのですか?
deldel さん、どうもです。
質問の記述で理解できなかったのかもしれませんね。
前回の質問でBackItem に値を入れる方法は既に試しています。
>int BackItem;
>iを作成し、Create 時に -1 を入れて、
>i今までなら、クリック時に BackItem を 変更していく方法を
>i使っていたのですが、
この方法を使った場合に、削除、や、追加、いくつかの処理
を行った場合に、BackItemを正常な数値に設定してやる必要があります。
つまり、OnClick 以外で、選択が変更される箇所でBackItemを
設定しなおす必要があります。
こうなった場合にメンテナンスやデバッグで悩まされる原因にもなるため
できればこの方法を避けたいのです。
そこで、なんですが、
例えば OnClick イベント前には OnMouseDown イベントが発生するので
OnMouseDown で ListBox1.ItemIndex が変更されていなければ
BackItem:=ListBox1.ItemIndex として、
直前の Index値 を取得できたのですが、実際には
OnMouseDown 時には既にIndex値が変更されていました。
このように他の処理や影響を受けないような方法がないものかと
質問させていただたしだいです。
すみません。よろしくお願いします。
>この方法を使った場合に、削除、や、追加、いくつかの処理
>を行った場合に、BackItemを正常な数値に設定してやる必要があります。
TListBoxには、itemsプロパティのObjectsに重複しない値(コードとか)
などを埋め込み、ItemIndexではなく、Objectsの中身をBackItemに格納すれば、
削除や追加などで位置が変わっても、BackItemを更新する必要がなくなりますが、
どうでしょう?
igyさんありがとうございます。
すみません。理解できませんでした。
まず、「itemsプロパティのObjects」の意味がわかりません。
Objectsがわかってないのかも。
リストボックスの中身を格納するとき、
with ListBox1.Items do
begin
Add('Delphi1');
Add('Delphi2');
Add('Delphi3');
Add('Delphi4');
Add('Delphi5');
Add('Delphi6');
Add('Delphi7');
end;
ではなく、
with ListBox1.Items do
begin
AddObject('Delphi1', TObject(80));
AddObject('Delphi2', TObject(90));
AddObject('Delphi3', TObject(100));
AddObject('Delphi4', TObject(120));
AddObject('Delphi5', TObject(130));
AddObject('Delphi6', TObject(140));
AddObject('Delphi7', TObject(150));
end;
のようにObjectも指定。
リストボックスのOnClickイベントで、選択された項目のObjectの内容を表示する場合、
procedure TForm1.ListBox1Click(Sender: TObject);
begin
with ListBox1 do
if ItemIndex >= 0 then
Label7.Caption := IntToStr(Integer(Items.Objects[ItemIndex]));
end;
さらに、格納されている位置を探す場合、IndexOfObjectメソッドで。
procedure TForm1.Button7Click(Sender: TObject);
var
idx: Integer;
begin
with ListBox1 do
begin
idx := items.IndexOfObject(TObject(130));
MessageDlg('130が格納されているのは、idx=' + IntToStr(idx), mtInformation, [mbOk], 0);
end;
end;
procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
i, Index, Data: Integer;
s: string;
begin
with TListBox(Sender) do begin
Index := ItemAtPos(Point(X, Y), True);
if Index >= 0 then begin
Data := Integer(Items.Objects[Index]);
case Data of
0: s := '初めてクリック';
1: s := '違う項目を選択';
2: s := '同じ項目を選択';
end;
Memo1.Lines.Add(Format('%d %d %s', [Index, Data, s]));
for i:=0 to Pred(Items.Count) do Items.Objects[i] := TObject(1);
Items.Objects[Index] := TObject(2);
end;
end;
end;
未選択時の追加…AddObject('追加項目', TObject(0));
既選択時の追加…AddObject('追加項目', TObject(1));
igyさん、RE最下位(;´д`) さん
どうもすみません。
私の説明がとても不十分のようなので、
求めている回答と違うような気がします。
もともとの処理イメージですが以下のようになります。
var
BackItem: Integer = -1;
procedure TForm1.ListBox1Click(Sender: TObject);
begin
if ( BackItem = -1) then begin
// クリック直前にどの項目も選択されていない
end else if ( ListBox1.ItemIndex = BackItem ) then begin
// クリック直前と今回クリックされた項目が同じ
end else begin
// クリック直前に選択されていた項目と違う項目をクリック
end;
BackItem = ListBox1.ItemIndex;
end;
この状態ですと、リストボックスのクリックだけの処理であれば
問題ないのですが、例えば、[削除][追加][挿入]などのボタンを
フォームに貼り付けて、リストの内容が変更された場合に
次に、このクリックイベントが発生されたときに
BackItem の中身と実際にクリック直前に選択されていたItemIndexの値とが
違うものになってしまいます。
それぞれのボタン処理イベント等の最終で
BackItem = ListBox1.ItemIndex;
を実行すればよいのですが、これ以外にも
処理ボタン等があり、それらの場合に BackItem を管理しながらプログラムを作ることになります。
このとき何らかのミスにより BackItem の値が違うものになる可能性が
多々発生し、デバッグに時間がかかるため
クリック直前のItemIndexとクリック後のItemIndexを比較できる方法を
探しています
すみません、よろしくお願いします。
いったいナニをどうしたいのか見えてこないね。
クリック直前のItemIndexを保存/使用する必要がなければ、
Object値操作だけで、項目追加、挿入、削除も問題無し。
ItemIndexのような“位置”を覚えるのではなく、(追加・削除で位置が変わるので)
>TListBoxには、itemsプロパティのObjectsに重複しない値(コードとか)
>などを埋め込み、ItemIndexではなく、Objectsの中身をBackItemに格納すれば、
>削除や追加などで位置が変わっても、BackItemを更新する必要がなくなりますが、
>どうでしょう?
と書いたようにObjectsに記憶している“値(コードとか)”を覚えるのでは
だめなのですか?
基本的に以下のようなプログラムです。
リストボックスに[1111][2222]の2つの項目が入っているとします。
プログラムを起動して、2222を選択したとします。
このとき、ItemIndex=1 です。
次に追加ボタンを押します。
「3333」という項目が追加され、追加した項目が選択されるように
ListBox1.ItemIndex := ListBox1.Count - 1;
としています。
以下のプログラムではこの後、「3333」をクリックすると、
「アイテム変更処理」が行われません。
BackItemが1のままで、ItemIndexは2になっているからです。
目的は
クリック時に「アイテム変更処理」が行われるようにしたいのです。
ただ、BackItem をプログラムのいたるところで設定するといった
方法はとりたくないという条件をつけてわけですが
私の説明はまだ、理解するには不十分なのでしょうか?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
ListBox1: TListBox;
Button1: TButton;
procedure ListBox1Click(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private 宣言 }
public
{ Public 宣言 }
end;
var
Form1: TForm1;
BackItem: Integer;
implementation
{$R *.dfm}
// リストボックスのクリック
procedure TForm1.ListBox1Click(Sender: TObject);
begin
if BackItem = ListBox1.ItemIndex then begin
//アイテム変更処理
end;
BackItem := ListBox1.ItemIndex;
end;
// 挿入ボタンのクリック
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add('3333');
ListBox1.ItemIndex := ListBox1.Count - 1;
end;
end.
コード上でItemIndexに直接、値を格納するかわりに、次のようなメソッドを使うのはどうですか?
procedure TForm1.SetItemIndex(AIdx: Integer);
begin
ListBox1.ItemIndex := AIdx;
BackItem := ListBox1.ItemIndex;
end;
ListBox1.ItemIndex := ListBox1.Count - 1;
↓
SetItemIndex(ListBox1.Count - 1);
>BackItem をプログラムのいたるところで設定するといった方法はとりたくない
は満たせます?
>こうなった場合にメンテナンスやデバッグで悩まされる原因にもなるため
>できればこの方法を避けたいのです。
こうなると、TListBoxから派生したクラスを書かないと
いけなさそうな気もしますが・・・。
挑戦してみました。
>クリック時に「アイテム変更処理」が行われるようにしたいのです。
TListBoxのアイテムと、それの付加的な情報が常に存在するわけですよね。
その付加的な情報を TObjectから派生したクラスにして、どなたかが
書かれた様にObjectsに追加すればよいです。
この場合、BackItemみたいなインデックスを保存しておく変数は
いりません。
ただ、オブジェクトを作成するコードと破棄するコードを
ListBoxのItemsの状態と同期を取って
書かねばら無いので、やはりソースが見にくくなったり、
バグがでたりといろいろ問題があるかと。
TListData= class( TObject)
Data1: string;
Data2: string;
end;
//挿入ボタンのクリック
procedure TForm1.InsertButtonClick(Sender: TObject);
var
ListData: TListData;
begin
ListData:= TListData.Create;
ListBox1.Items.AddObject('3333',ListData);
end;
procedure TForm1.ListBoxClick(Sender: TObject);
begin
// これは TListBox1.OnClickのハンドラ
EditButtonClick(nil);
end;
//編集
procedure TForm1.EditButtonClick;
var
ListData: TListData;
begin
if ListBox1.ItemIndex<0 then Exit;
if ListBox1.ItemIndex<ListBox1.Items.Count-1 do
begin
ListData:= ListBox1.Items.Objects( ListBox1.ItemIndex) as TListData;
Edit1.Text:= ListData.Data1;
Edit2.Text:= ListData.Data2;
end;
end;
//削除
procedure TForm1.DeleteButtonClick;
begin
if ListBox1.ItemIndex<0 then Exit;
if ListBox1.ItemIndex<ListBox1.Items.Count-1 do
begin
ListData:= ListBox1.Items.Objects( ListBox1.ItemIndex) as TListData;
ListData.Free;
ListBox1.Items.Delete( ListBox1.ItemIndex);
end;
end;
//クリア
procedure TForm1.ClearListBoxItems;
begin
if ListBox1.Items.Count>0 then
for i:=ListBox1.Items.Count-1 downto 0 do
begin
(ListBox1.Objects[i] as TListData).Free;
end;
ListBox1.Items.Clear;
end;
こんな感じで常に、選択項目と付加的な情報の表示内容が
一致すると思います。
>この状態ですと、リストボックスのクリックだけの処理であれば
>問題ないのですが、例えば、[削除][追加][挿入]などのボタンを
>フォームに貼り付けて、リストの内容が変更された場合に
>次に、このクリックイベントが発生されたときに
>BackItem の中身と実際にクリック直前に選択されていたItemIndexの値とが
>違うものになってしまいます。
は、これで回避できてると思います。(確認はしてませんが)
まあ、結局のところ、igyさんが最後の1つ前に言ったことと同じかもしれない。
気もする。
やっぱり、派生 を避けては通れないと思います。
これを機に、学んでみてはどうでしょうか。
これまでの内容を TListBoxExで再実装(涙)
TListBoxEx = class(TListBox)
//自分で考えてください(汗)
end;
OnClickで変更を検知するのをやめるとか・・・
ItemIndexと同期をとるように変更するBackItemではなく、
BackItemと同期をとるようにItemIndexを変更する。
type
TForm1 = class(TForm)
private
FBackItem :Integer;
procedure SetBackItem(Value:Integer);
public
property BackItem: Integer read FBackItem write SetBackItem;
end;
procedure TForm1.SetBackItem(Value:Integer);
begin
if FBackItem <> Value then begin
FBackItem := Value;
{//ここでアイテム変更イベント//}
OnChangeItemIndexHogeHoge...
end;
if ListBox1.ItemIndex <> FBackItem then begin
ListBox1.ItemIndex := FBackItem;
end;
end;
// リストボックスのクリック
procedure TForm1.ListBox1Click(Sender: TObject);
begin
BackItem := ListBox1.ItemIndex;
end;
// 挿入ボタンのクリック
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add('3333');
BackItem := ListBox1.Count - 1;
end;
ざっと読んだのですが、以下ではだめですか?
// リストボックスのクリック
procedure TForm1.ListBox1Click(Sender: TObject);
begin
//アイテム変更処理
end;
若しくは、
// 挿入ボタンのクリック
procedure TForm1.Button1Click(Sender: TObject);
begin
ListBox1.Items.Add('3333');
ListBox1.ItemIndex := ListBox1.Count - 1;
//アイテム変更処理
end;
ツイート | ![]() |