当项目添加到 TListView 时,如何捕获事件?
根据文档,我认为 OnInsert
事件可以完成这项工作。它甚至将实际的 TListItem
对象传递给处理程序:
OnInsert Occurs immediately after a new item is inserted into the list view.
Write an OnInsert event handler to respond when an item has just been added to the list. The Item parameter is the TListItem object that was added to the Items property
这是我的代码:
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;
这是为什么?
最佳答案
TListView.OnInsert
当新项目添加到 ListView 时,事件确实会被触发。然而,Item
当 TListView.Items.Add()
时添加到 ListView被调用,而不是在 Button1Click()
时调用退出。 OnInsert
当 LVN_INSERTITEM
时调用事件处理程序(响应 Add()
通知)仍在运行。所以,当然是Item
在 OnInsert
事件处理程序将始终为空,因为您尚未为其分配任何值。
更新:当 TListItem
添加到 ListView 后,LVIF_TEXT
底层证券标志 LVITEM
未启用。显示TListItem.Caption
和TListItem.SubItems
文本,TListView
设计依赖 ListView_SetItemText()
与 LPSTR_TEXTCALLBACK
改为标记:
This parameter can be LPSTR_TEXTCALLBACK to indicate a callback item for which the parent window stores the text. In this case, the list-view control sends the parent an
LVN_GETDISPINFO
notification code when it needs the text.
如果您分配TListItem.Caption
或TListItem.SubItems
属性(property)而TListItem
实际上还没有在 ListView 中,LPSTR_TEXTCALLBACK
标志不会应用于这些字段。 LVN_GETDISPINFO
不会查询TListView
对于没有 LPSTR_TEXTCALLBACK
的第一列文本(因为第 0 列在操作系统层具有特殊含义),但它确实查询第二列的文本(即使 LPSTR_TEXTCALLBACK
未应用于它)。这就是为什么你的第二个例子缺少 'foo2'
UI 中的标题文本,但不是 'bar2'
文本。
实际'foo2'
标题字符串存储在TListItem
中对象,这就是为什么你的 ShowMessage()
可以工作。
所以,如果您创建一个新的 TListItem
并修改其Caption
在将项目添加到 ListView 之前,您必须调用 ListView_SetItemText()
手动启用 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
临时属性值(属性 setter 在调用 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
之后文本才会出现在 UI 中首先调用事件,因为它是在 AddItem()
时触发的。正在运行。
我在 XE2 中重现了这个。如果问题在10.2东京仍然出现,我建议filing a bug report与内河码头。 AddItem()
可能应该强制LPSTR_TEXTCALLBACK
插入任何已分配的字符串字段后,或至少 Caption
无论如何。
关于listview - TListView:已添加项目?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45806324/