TListView:关于项目添加?

for*_*ajt 2 delphi listview delphi-7 tlistview

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

OnInsert根据文件,我认为该活动将起到作用.它甚至将实际TListItem对象传递给处理程序:

OnInsert在将新项插入列表视图后立即发生.

编写一个OnInsert事件处理程序,以便在项刚刚添加到列表时进行响应.Item参数是添加到Items属性的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;
Run Code Online (Sandbox Code Playgroud)

但令人惊讶的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;
Run Code Online (Sandbox Code Playgroud)

图片

为什么是这样?

Rem*_*eau 7

TListView.OnInsert新项添加到ListView时,确实会触发该事件.但是,在调用时会将其Item添加到ListView中TListView.Items.Add(),而不是在Button1Click()退出时添加到ListView中.该OnInsert事件处理函数(响应LVN_INSERTITEM通知),同时Add()仍在运行.因此,当然ItemOnInsert事件处理程序将永远是空的,因为你还没有分配任何值呢.


更新:当a TListItem添加到ListView时,未启用LVIF_TEXT基础的标志LVITEM.要显示TListItem.CaptionTListItem.SubItems文本,TListView旨在依靠ListView_SetItemText()LPSTR_TEXTCALLBACK标志来代替:

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

如果在尚未实际位于ListView中的情况下分配TListItem.Captionor TListItem.SubItems属性TListItem,则该LPSTR_TEXTCALLBACK标志将不会应用于这些字段. LVN_GETDISPINFO不会查询TListView的第一列中没有文本LPSTR_TEXTCALLBACK(如0列有在OS层特殊的含义),但它确实查询中第二列的文本(即使LPSTR_TEXTCALLBACK不应用到它).这就是为什么你的第二个例子缺少'foo2'UI中的标题文本,而不是'bar2'文本.

实际的'foo2'标题字符串存储在TListItem对象中,这就是您ShowMessage()能够工作的原因.

因此,如果您在将项目添加到ListView之前创建新的TListItem并修改它Caption,则必须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; 
Run Code Online (Sandbox Code Playgroud)

或者,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; 
Run Code Online (Sandbox Code Playgroud)

请注意,无论哪种方式,TListItem.Caption文本都不会出现在UI中,直到OnInsert首先调用该事件,因为它在AddItem()运行时被触发.

我在XE2中重现了这一点.如果问题仍然发生在10.2东京,我建议 Embarcadero 提交一份错误报告. AddItem()应该LPSTR_TEXTCALLBACK在插入任何已经分配的字符串字段之后强制执行,或者至少应该强制执行Caption.

  • 设置项目并使用AddItem. (4认同)