代码之家  ›  专栏  ›  技术社区  ›  hundreAd

TListView OnSelectItem:为什么访问TopItem会更改过程输入Item?

  •  0
  • hundreAd  · 技术社区  · 3 年前

    复制:点击按钮初始化ListView,然后选择任何项目(第一个项目除外)。Form标题中的输出将显示,已访问 TopItem ,的值 Item 现已更改。

    有人能解释一下吗?

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      ListView1.OwnerData := True;
      ListView1.Items.Count := 5;
    end;
    
    procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
    begin
      Item.Caption := '...';
    end;
    
    procedure TForm1.ListView1SelectItem(Sender: TObject; Item: TListItem;
        Selected: Boolean);
    var
      one, two: string;
    begin
      if Item <> nil then
        one := IntToStr(Item.Index)
      else
        one := 'nil';
      if ListView1.TopItem <> nil then;
      if Item <> nil then
        two := IntToStr(Item.Index)
      else
        two := 'nil';
      Form1.Caption := one + '/' + two;
    end;
    
    1 回复  |  直到 3 年前
        1
  •  2
  •   Remy Lebeau    3 年前

    在里面 非虚拟模式 ( OwnerData=False ),ListView保存物理项,其中每个项都由一个唯一的 TListItem 对象。但是 处于虚拟模式 ( OwnerData=True ),ListView具有 没有实物 一点也不 TListItem 为每个项目创建对象。

    然而,由于 TListView 公开使用的公共接口 TListItem ,并且这些接口即使在虚拟模式下也必须继续工作, TListView 持有1个内部 TListItem 对象处于虚拟模式,它得到 可重复用于任何操作 这涉及到 TListItem .

    因此,在您的示例中,当您选择任何列表项时 OnSelectItem 事件是用引发的 TListItem 参数,所以 TListView 必须先发射 OnData 事件以填充内部 TListItem 以及所选项目的数据。然后,当您访问 TListView.TopItem 所有物 TListView 不得不解雇它 OnData 再次填充事件 同样的内部 TListItem 对象 具有顶部可见项目的新数据。

    这就是为什么你看到 Item.Index 属性更改值。

    使用虚拟模式时,不要期望给定 TListItem 访问不同的后保持原样 TListItem 。事实上,你真的应该避免使用 任何 TListItem 尽可能多地进行操作。如果您需要访问有关特定列表项的信息,而该信息在您自己的数据源中还不可用,那么您应该查询基础 ListView 控件直接使用Win32 API,以免影响 TListView 的鞋底 TListItem 对象,例如:

    procedure TForm1.ListView1SelectItem(Sender: TObject;
      Item: TListItem; Selected: Boolean);
    var
      one, two: string;
    begin
      if Item <> nil then
        one := IntToStr(Item.Index)
      else
        one := 'nil';
    
      //if ListView1.TopItem <> nil then;     // Item is affected!
      ListView_GetTopIndex(ListView1.Handle); // Item is not affected!
    
      if Item <> nil then
        two := IntToStr(Item.Index)
      else
        two := 'nil';
    
      Caption := one + '/' + two;
    end;
    
    推荐文章