You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 10.3.3 VCL应用中如何临时隐藏TListView的TListItem?

Delphi 10.3.3 VCL中TListItem的临时隐藏/显示实现方案

以下是几种无需删除项即可实现TListView行隐藏的实用方案,隐藏后仍可直接访问项的所有属性:

方案一:利用TListItem.Data存储隐藏标记(轻量化实现)

无需自定义控件,直接用现有属性实现:

  • 标记隐藏状态:通过Data属性存储布尔标记(用Integer类型转换适配Pointer)

    // 标记第N行隐藏
    ListView1.Items[N].Data := Pointer(Integer(True));
    // 恢复显示第N行
    ListView1.Items[N].Data := Pointer(Integer(False));
    
  • 拦截绘制过程:重写OnCustomDrawItem事件,跳过隐藏项的绘制

    procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      // 检查是否标记为隐藏,是则不执行默认绘制
      if Assigned(Item.Data) and (Integer(Item.Data) = Integer(True)) then
        DefaultDraw := False;
    end;
    
  • 访问隐藏项:直接通过ListView1.Items索引访问,项并未被删除,只是不显示

    // 获取隐藏项的标题
    ShowMessage(ListView1.Items[HiddenItemIndex].Caption);
    

方案二:自定义TListItem子类添加Hidden属性(语义更清晰)

如果需要更直观的属性控制,可以自定义子类:

  • 定义子类:

    type
      THiddenListItem = class(TListItem)
      private
        FHidden: Boolean;
      public
        property Hidden: Boolean read FHidden write FHidden;
      end;
    
  • 创建自定义项:

    var
      NewItem: THiddenListItem;
    begin
      NewItem := THiddenListItem.Create(ListView1.Items);
      NewItem.Caption := '示例行';
      NewItem.Hidden := False; // 默认显示
      // 可继续设置SubItems等属性
    end;
    
  • 过滤绘制:在OnCustomDrawItem中判断Hidden属性

    procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView;
      Item: TListItem; State: TCustomDrawState; var DefaultDraw: Boolean);
    begin
      if Item is THiddenListItem then
        DefaultDraw := not THiddenListItem(Item).Hidden;
    end;
    
  • 访问隐藏项:强转类型后直接操作属性

    if ListView1.Items[Index] is THiddenListItem then
      ShowMessage(THiddenListItem(ListView1.Items[Index]).Caption);
    

方案三:虚拟列表模式(大数据量场景更高效)

如果ListView包含大量项,使用虚拟模式(OwnerData)能大幅提升性能:

  • 开启虚拟模式:设置ListView1.OwnerData := True;

  • 维护独立数据源:定义存储所有项数据的结构,包含隐藏状态

    type
      TListViewItemData = record
        Caption: string;
        SubItems: array of string;
        Hidden: Boolean;
      end;
    
    var
      ItemDataList: TList<TListViewItemData>;
    
  • 绑定数据到ListView:实现OnData事件,仅加载非隐藏项

    procedure TForm1.ListView1Data(Sender: TCustomListView; Item: TListItem);
    var
      VisibleIdx, RealIdx: Integer;
    begin
      VisibleIdx := Item.Index;
      RealIdx := -1;
      // 找到当前可见项对应的真实数据源索引
      while VisibleIdx >= 0 do
      begin
        Inc(RealIdx);
        if not ItemDataList[RealIdx].Hidden then
          Dec(VisibleIdx);
      end;
      // 赋值标题和子项
      Item.Caption := ItemDataList[RealIdx].Caption;
      Item.SubItems.Clear;
      for var SubItemStr in ItemDataList[RealIdx].SubItems do
        Item.SubItems.Add(SubItemStr);
    end;
    
  • 更新显示:修改隐藏状态后,刷新ListView的可见项数量并重绘

    procedure TForm1.RefreshListViewDisplay;
    var
      VisibleCount: Integer;
    begin
      VisibleCount := 0;
      for var Data in ItemDataList do
        if not Data.Hidden then
          Inc(VisibleCount);
      ListView1.Items.Count := VisibleCount;
      ListView1.Invalidate;
    end;
    
  • 访问隐藏项:直接操作ItemDataList即可,完全不受ListView显示状态影响

补充优化:避免选中隐藏项

方案一和二中,隐藏项仍存在于Items集合中,可能被意外选中,可通过OnSelectItem事件拦截:

procedure TForm1.ListView1SelectItem(Sender: TCustomListView;
  Item: TListItem; Selected: Boolean);
begin
  if Selected then
  begin
    // 方案一的判断逻辑
    if Assigned(Item.Data) and (Integer(Item.Data) = Integer(True)) then
      ListView1.Selected := nil;
    // 方案二的判断逻辑
    if (Item is THiddenListItem) and THiddenListItem(Item).Hidden then
      ListView1.Selected := nil;
  end;
end;

内容的提问来源于stack exchange,提问作者Xel Naga

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 03:23:22