TListView:是否已添加项?
将项目添加到TListView时,如何捕获事件 根据文档,我认为TListView:是否已添加项?,listview,delphi,delphi-7,tlistview,Listview,Delphi,Delphi 7,Tlistview,将项目添加到TListView时,如何捕获事件 根据文档,我认为OnInsert事件可以完成这项工作。它甚至将实际的TListItem对象传递给处理程序: 在将新项目插入列表后立即执行OnInsert 视图 编写一个OnInsert事件处理程序,以便在项目刚刚启动时进行响应 添加到列表中项参数是已创建的TListItem对象 添加到项目属性中 这是我的密码: procedure TForm1.Button1Click(Sender: TObject); begin with ListView
OnInsert
事件可以完成这项工作。它甚至将实际的TListItem
对象传递给处理程序:
在将新项目插入列表后立即执行OnInsert
视图
编写一个OnInsert事件处理程序,以便在项目刚刚启动时进行响应
添加到列表中项参数是已创建的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;
但令人惊讶的是,项标题总是空的。对我来说似乎是胡说八道
编辑:
按照建议切换到项。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
事件。但是,在调用TListView.Items.Add()
时,而不是在退出Button1Click()
时,会将项添加到列表视图中。当Add()
仍在运行时,调用OnInsert
事件处理程序(响应通知)。因此,当然,OnInsert
事件处理程序中的项
将始终为空,因为您尚未为其分配任何值
更新:将t列表项
添加到列表视图时,基础的LVIF_TEXT
标志未启用。要显示TListItem.Caption
和TListItem.SubItems
text,TListView
设计为依赖LPSTR\u TEXTCALLBACK
标志:
此参数可以是LPSTR_TEXTCALLBACK,以指示父窗口存储文本的回调项。在这种情况下,列表视图控件在需要文本时向父控件发送一个LVN_GETDISPINFO
通知代码
如果指定TListItem.Caption
或TListItem.SubItems
属性,而TListItem
实际上还不在列表视图中,则LPSTR\u TEXTCALLBACK
标志将不会应用于这些字段LVN_GETDISPINFO
不会在没有LPSTR_TEXTCALLBACK
的情况下查询TListView
第一列的文本(因为列0在OS层具有特殊含义),但它会查询第二列的文本(即使LPSTR_TEXTCALLBACK
未应用于它)。这就是为什么您的第二个示例在UI中缺少'foo2'
标题文本,而不是'bar2'
文本的原因
实际的'foo2'
标题字符串存储在TListItem
对象中,这就是ShowMessage()
能够工作的原因
因此,如果在将项目添加到ListView之前创建一个新的TListItem
并修改其标题
,则必须手动调用ListView\u SetItemText()
,以启用标题的LPSTR\u 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;
或者,临时重置标题
属性值(属性设置程序在调用ListView\u SetItemText()
之前检查重复的字符串):
请注意,无论哪种方式,TListItem.Caption
文本都不会出现在UI中,直到首先调用OnInsert
事件之后,因为它是在运行AddItem()
时触发的
我在XE2中复制了这个。如果问题仍然发生在10.2东京,我建议与EmbarcaderoAddItem()
在插入任何已分配的字符串字段后,或者至少在插入标题后,可能会强制执行LPSTR\u TEXTCALLBACK
。它应该是ListView1,而不是TListView1。添加项目时也要使用BeginUpdate和EndUpdate过程。请注意,调用(Begin | End)Update()
只会影响ListView的绘制(以避免在对项目进行更改时重新绘制),而不会影响其效果events@RemyLebeau是的,当然!我建议使用它们,因为当我处理要编辑的项目时,我总是这样做(特别是如果项目很多的话)。我想它们应该在任何情况下使用——你不能在另一个线程中添加项目。VCL访问需要在主线程中。无论您试图做什么,GUI控件事件都是错误的解决方案。正确。十足的下铺。我担心Zarko写的绝大多数东西都有缺陷。我不会相信你读到的关于他的任何消息。无论如何,我强烈地感到这个问题的整个前提是错误的。您只希望响应事件,因为您在错误的位置添加了项目。如果将与VCL一起工作的代码移动到主线程中(必须这样做),则不需要响应事件。您可以在添加项目的同时执行该操作。那么,我应该如何访问新添加的项目的值?设置一个项目并使用AddItem。不要使用ListView.Items.add()
来创建一个新的TListItem
,该项目将传递给TListView.Items.AddItems()
。改用TListItem.Create(ListView.Items)
。或者更好:TListViewAccess(ListView).CreateListItem()
(其中TListViewAccess
是类型TListViewAccess=class(TListView)end;
,因为CreateListItem()
被声明为受保护的
)。使用CreateListItem()
允许用户通过TListView.OnCreateItemClass
事件,或者通过重写CreateListItem()
本身,自定义所使用的item类。@RemyLebeau这导致了另一个问题,因此我扩展了这个问题
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;