将项目添加到TListView时如何捕获事件?

根据文档,我认为OnInsert事件可以完成这项工作。甚至将实际的TListItem对象传递给处理程序:


将新项目插入列表后,立即发生OnInsert
视图。

编写一个OnInsert事件处理程序,以在项目刚被响应时进行响应
添加到列表中。 Item参数是TListItem对象,
添加到Items属性


这是我的代码:

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始终为空。在我看来胡说八道。

编辑:

按照建议切换到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;


listview - TListView:在项目上添加?-LMLPHP

为什么是这样?

最佳答案

当将新项添加到ListView时,确实触发了TListView.OnInsert事件。但是,Item是在调用TListView.Items.Add()时(而不是在Button1Click()退出时)添加到ListView的。在OnInsert仍在运行时,调用LVN_INSERTITEM事件处理程序(以响应Add()通知)。因此,当然,在Item事件处理程序中的OnInsert始终为空,因为您尚未为其分配任何值。



更新:将TListItem添加到ListView时,基础LVIF_TEXTLVITEM标志未启用。为了显示TListItem.CaptionTListItem.SubItems文本,TListView被设计为依赖带有ListView_SetItemText()标志的LPSTR_TEXTCALLBACK


此参数可以是LPSTR_TEXTCALLBACK,以指示父窗口为其存储文本的回调项目。在这种情况下,列表视图控件在需要文本时向父级发送LVN_GETDISPINFO通知代码。


如果在TListItem.Caption尚未真正出现在ListView中时分配TListItem.SubItemsTListItem属性,则LPSTR_TEXTCALLBACK标志将不会应用于这些字段。 LVN_GETDISPINFO不会在没有TListView的情况下向LPSTR_TEXTCALLBACK查询第一列的文本(因为列0在OS层中具有特殊含义),但是它会查询第二列的文本(即使不适用于它)。这就是为什么第二个示例在UI中缺少LPSTR_TEXTCALLBACK标题文本而不是'foo2'文本的原因。

实际的'bar2'标题字符串存储在'foo2'对象中,这就是为什么TListItem可以工作的原因。

因此,如果在将项目添加到ListView之前创建新的ShowMessage()并修改其TListItem,则必须手动调用Caption以启用字幕的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;


或者,暂时重置LPSTR_TEXTCALLBACK属性值(属性设置器在调用Caption之前检查重复的字符串):

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;


请注意,无论哪种方式,直到第一次调用ListView_SetItemText()事件之后,TListItem.Caption文本都不会出现在UI中,因为它是在OnInsert运行时触发的。

我在XE2中复制了此内容。如果在10.2东京中问题仍然存在,我建议在Embarcadero中使用filing a bug report。插入任何已分配的字符串字段(或至少为AddItem())后,AddItem()可能应强制插入LPSTR_TEXTCALLBACK

07-27 17:08