将项目添加到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.OnInsert
事件。但是,Item
是在调用TListView.Items.Add()
时(而不是在Button1Click()
退出时)添加到ListView的。在OnInsert
仍在运行时,调用LVN_INSERTITEM
事件处理程序(以响应Add()
通知)。因此,当然,在Item
事件处理程序中的OnInsert
始终为空,因为您尚未为其分配任何值。
更新:将TListItem
添加到ListView时,基础LVIF_TEXT
的LVITEM
标志未启用。为了显示TListItem.Caption
和TListItem.SubItems
文本,TListView
被设计为依赖带有ListView_SetItemText()
标志的LPSTR_TEXTCALLBACK
:
此参数可以是LPSTR_TEXTCALLBACK,以指示父窗口为其存储文本的回调项目。在这种情况下,列表视图控件在需要文本时向父级发送LVN_GETDISPINFO
通知代码。
如果在TListItem.Caption
尚未真正出现在ListView中时分配TListItem.SubItems
或TListItem
属性,则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
。