TListView:添加了项目?

时间:2017-08-21 22:20:49

标签: listview delphi delphi-7 tlistview

如何将项目添加到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;

image

为什么会这样?

1 个答案:

答案 0 :(得分:7)

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

更新:将TListItem添加到ListView时,未启用基础LVITEMLVIF_TEXT标记。要显示TListItem.CaptionTListItem.SubItems文字,TListView旨在依赖于ListView_SetItemText()LPSTR_TEXTCALLBACK标志:

  

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

如果您在TListItem.Caption实际上尚未在ListView中分配TListItem.SubItemsTListItem属性,则LPSTR_TEXTCALLBACK标志将不会应用于这些字段。如果没有LVN_GETDISPINFOTListView将不会向LPSTR_TEXTCALLBACK查询第1列的文本(因为第0列在OS层具有特殊含义),但它会查询第2列的文本列(即使未应用LPSTR_TEXTCALLBACK)。这就是为什么您的第二个示例缺少UI中的'foo2'标题文本,而不是'bar2'文本。

实际的'foo2'字幕字符串存储在TListItem对象中,这就是ShowMessage()能够正常工作的原因。

因此,如果您在将项目添加到ListView之前创建新的TListItem并修改其Caption,则必须手动调用ListView_SetItemText()以启用{{1}标题的标志,例如:

LPSTR_TEXTCALLBACK

或者,暂时重置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; 文字都会在首次​​调用TListItem.Caption事件之后才会显示在用户界面中,因为它会在OnInsert运行时触发。

我在XE2中重现了这一点。如果问题仍然发生在10.2东京,我会建议{Emborcadero filing a bug report。插入任何已经分配的字符串字段后,AddItem()可能应该强制AddItem(),或者至少LPSTR_TEXTCALLBACK