2017-08-21 13 views
2

アイテムがTListViewに追加されたときに、どのようにイベントを捕捉できますか?TListView:アイテムが追加されましたか?

ドキュメントによれば、OnInsertイベントは仕事をすると思っていました。それも、ハンドラに実際のTListItemオブジェクトを渡します: OnInsert

は、新しい項目がリスト ビューに挿入された直後に発生します。

項目が がリストに追加されたばかりのときに応答するOnInsertイベントハンドラを作成します。 アイテムのパラメータが ここ

Itemsプロパティに追加されたTListItemのオブジェクトは、私のコードです:

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with ListView1.Items.Add do 
    begin 
    Caption := 'foo'; 
    SubItems.Add('bar'); 
    end; 
end; 

procedure TForm1.TListView1Insert(Sender: TObject; Item: TListItem); 
begin 
    //Item is empty 
    ShowMessage(Item.Caption); 
end; 

しかし、驚くべきことには、Item.Captionは常に空です。私にナンセンスみたいだ。

EDIT:

示唆されているように、Items.AddItem()への切り替えは、別の奇妙な問題につながります。 OnInsertイベントハンドラが正常に機能するようになりましたが、TListViewにはTListItem.Captionが表示されません。

procedure TForm1.Button1Click(Sender: TObject); 
begin 
    with ListView1.Items.Add do 
    begin 
    Caption := 'foo1'; 
    SubItems.Add('bar1'); 
    end; 
end; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    item: TListItem; 
begin 
    item := TListItem.Create(ListView1.Items); 
    item.Caption := 'foo2'; 
    item.Subitems.Add('bar2'); 
    ListView1.Items.AddItem(item); 
end; 

procedure TForm1.ListView1Insert(Sender: TObject; Item: TListItem); 
begin 
    //this now works as expected 
    ShowMessage(Item.Caption); 
end; 

image

これはなぜでしょうか?

+1

ListView1ではなく、TListView1である必要があります。また、アイテムを追加するときにBeginUpdateおよびEndUpdateプロシージャを使用します。 –

+0

'(Begin | End)Update()'を呼び出すことは、ListViewのペイントにのみ影響します(項目を変更している間は再ペイントしないようにする)、 –

+0

@RemyLebeau確かめてください!私はそれらを使うことを提案しました。なぜなら、編集するアイテムを扱うとき(特にそれらがたくさんある場合)、私はいつもそうするからです。私は彼らがどんな場合でも使用されるべきだと思います。 –

答えて

7

TListView.OnInsertイベントは、新しいアイテムがListViewに追加されたときに実際にトリガーされます。ただし、TListView.Items.Add()が呼び出されたときにButton1Click()が終了したときではなく、ItemがListViewに追加されます。 Add()が実行されている間にOnInsertイベントハンドラが(LVN_INSERTITEM通知に応答して)呼び出されます。したがって、OnInsertイベントハンドラのItemは、まだ値を割り当てていないので、常に空になります。


更新TListItemがリストビューに追加されると、基礎となるLVITEMLVIF_TEXTフラグが有効になっていません。 TListItem.CaptionTListItem.SubItemsテキストを表示するには、TListViewではなくLPSTR_TEXTCALLBACKフラグでListView_SetItemText()に頼るように設計されています

このパラメータは、親ウィンドウのテキストを格納するためのコールバック項目を示すためにLPSTR_TEXTCALLBACKことができます。この場合、リストビューコントロールはテキストを必要とするときに親にLVN_GETDISPINFO通知コードを送信します。

TListItemはまだリストビューでは、実際にはないながら、あなたがTListItem.CaptionTListItem.SubItemsプロパティを割り当てた場合、LPSTR_TEXTCALLBACKフラグがそれらのフィールドに適用されません。LVN_GETDISPINFOLPSTR_TEXTCALLBACK(0列はOS層で特別な意味を持ちます)を除いて第1列のテキストをTListViewに照会しませんが、LPSTR_TEXTCALLBACKが適用されていなくても2列目のテキストを照会します。あなたの2番目の例では、'bar2'のテキストではなく、UI内の'foo2'キャプションテキストが欠落しています。

実際の'foo2'キャプション文字列はTListItemオブジェクトに格納されています。そのため、お客様のShowMessage()は機能します。だから、

、項目がリストビューに追加された前に新しいTListItemを作成し、そのCaptionを変更し、キャプションのためLPSTR_TEXTCALLBACKフラグを有効にするには、手動でListView_SetItemText()を呼び出す必要があります場合は、例えば:

uses 
    Commctrl; 

procedure TForm1.Button2Click(Sender: TObject); 
var 
    item: TListItem; 
begin 
    item := TListItem.Create(ListView1.Items); 
    item.Caption := 'foo2'; 
    item.Subitems.Add('bar2'); 
    ListView1.Items.AddItem(item); 
    ListView_SetItemText(ListView1.Handle, item.Index, 0, LPSTR_TEXTCALLBACK); 
end; 

あるいは、一時的にCaptionプロパティの値をリセットする(ListView_SetItemText()を呼び出す前に、重複した文字列のプロパティのセッターをチェック):

procedure TForm1.Button2Click(Sender: TObject); 
var 
    item: TListItem; 
begin 
    item := TListItem.Create(ListView1.Items); 
    item.Caption := 'foo2'; 
    item.Subitems.Add('bar2'); 
    ListView1.Items.AddItem(item); 
    item.Caption := ''; 
    item.Caption := 'foo2'; 
end; 

ちょうどトンの点に注意してください。いずれにしてものテキストは、AddItem()が実行されている間にトリガーされるため、最初にOnInsertイベントが呼び出されるまでUIに表示されません。

これをXE2で再現しました。それでも10.2東京で問題が発生する場合は、filing a bug reportにEmbarcaderoをお勧めします。 AddItem()は既に割り当て済みの文字列フィールドの場合はLPSTR_TEXTCALLBACK、おそらくはCaptionの場合は、挿入後に強制的に実行する必要があります。

+0

新しく追加されたアイテムの値にアクセスするにはどうすればよいですか? – forsajt

+4

アイテムをセットアップし、AddItemを使用します。 –

+1

DONTは 'ListView.Items.Add()'を使って 'TListView.Items.AddItem()'に渡す新しい 'TListItem'を作成します。代わりに 'TListItem.Create(ListView.Items)'を使用してください。 'TListViewAccess'が' typeListViewAccess = class(TListView)end; 'で、' CreateListItem() 'が' protected'として宣言されているので) 'TListViewAccess(ListView).CreateListItem()'です。 'CreateListItem()'を使うと、ユーザは 'TListView 'を使って、使われているアイテムクラスをカスタマイズできます。OnCreateItemClass'イベント、または 'CreateListItem()'自体をオーバーライドすることによって呼び出されます。 –

関連する問題