代码之家  ›  专栏  ›  技术社区  ›  Marus Gradinaru

如何找到下一个未选中的ListView项?

  •  1
  • Marus Gradinaru  · 技术社区  · 6 年前

    我想在ListView中搜索下一个未选中的项目,但只能使用windows API。

    ListView_FindItem 但它不起作用。结果总是-1:

    function TNewListView.NextUnselected(I: Integer): Integer;
    var FindInfo: TLVFindInfo;
        ItemInfo: TLVItem;
    begin
     if not HandleAllocated then Exit(-1)
     else begin
       FillChar(ItemInfo, SizeOf(ItemInfo), 0);
       ItemInfo.mask:= LVIF_STATE;
       ItemInfo.state:= 0;
       ItemInfo.stateMask:= LVIS_SELECTED;
    
       FillChar(FindInfo, SizeOf(FindInfo), 0);
       FindInfo.flags:= LVFI_PARAM;
       FindInfo.lParam:= LPARAM(@ItemInfo);
       Result:= ListView_FindItem(Handle, I, FindInfo);
     end;
    
    1 回复  |  直到 6 年前
        1
  •  4
  •   Remy Lebeau    6 年前

    你在打电话吗 ListView_FindItem() LVFI_PARAM

    LVFI参数

    lParam 成员和 lParam公司 项的成员 LVITEM

    它告诉ListView比较指定的 TLVFindInfo.lParam 价值 原样

    如果您正在使用 TListView 非虚拟的 OwnerData=False ),列表项的 lParam公司 值保持其对应的 TListItem 对象指针。

    如果您正在使用 TListView视图 事实上的 模式( OwnerData=True ),列表项的 lParam公司 值始终为0。

    ListView\u FindItem() (以及潜在的 LVM_FINDITEM Caption (全部或部分),其 1 没别的了

    1:比如说 TListItems.IndexOf() 方法使用 ListView\u FindItem() TListItem公司 对象使用 lParam公司 lParam公司 每个项目的 TListItem公司

    lParam公司 也可以搜索,但您正在使用 lParam公司 TLVFindInfo.lParam文件 价值 指向本地 TLVItem 变量 LVFI参数 比较会 从未 查找匹配的列表项。这就是为什么你总是得到-1的结果。

    ListView\u FindItem() 在示例中执行以下逻辑:

    function ListView_FindItem(hWnd: HWND; iStart: Integer; const plvfi: TLVFindInfo): Integer;
    var
      lvi: TLVItem;
    begin
      for Result := iStart+1 to ListView_GetItemCount(hWnd)-1 do
      begin
        FillChar(lvi, SizeOf(lvi), 0);
        lvi.iIndex := Result;
        lvi.mask = LVIF_PARAM;
        ListView_GetItem(hWnd, lvi);
        if lvi.lParam = plvfi.lParam then // <-- NEVER FINDS A MATCH!
          Exit;
      end;
      Result := -1;
    end;
    

    目录 特维特姆

    你是 ListView\u FindItem() 基本上

    function ListView_FindItem(hWnd: HWND; iStart: Integer; const plvfi: TLVFindInfo): Integer;
    var
      lvi: TLVItem;
    begin
      for Result := iStart+1 to ListView_GetItemCount(hWnd)-1 do
      begin
        FillChar(lvi, SizeOf(lvi), 0);
        lvi.iIndex := Result;
        lvi.mask = LVIF_STATE;
        lvi.stateMask := PLVItem(plvfi.lParam)^.stateMask;
        ListView_GetItem(hWnd, lvi);
        if lvi.state = PLVItem(plvfi.lParam)^.state then // <-- BUZZ, WRONG!
          Exit;
      end;
      Result := -1;
    end;
    

    因此,您不能使用 ListView\u FindItem() /

    你可能想用 ListView_GetNextItem() LVM_GETNEXTITEM 取而代之的是:

    搜索具有指定属性且与指定项具有指定关系的列表视图项。

    但是,它们只能用于搜索启用了指定特征(例如 LVNI_SELECTED 缺席 具有特定特征的(如 已选择LVNI\U 已禁用)。

    因此,要做您想做的事情,您只需使用 ListView_GetItem() ListView_GetItemState() 检索每个项目的当前状态,直到找到要查找的内容。

    function TNewListView.NextUnselected(StartIndex: Integer): Integer;
    begin
      if HandleAllocated then
      begin
        for Result := StartIndex+1 to ListView_GetItemCount(Handle)-1 do
        begin
          if (ListView_GetItemState(Handle, Result, LVIS_SELECTED) and LVIS_SELECTED) = 0 then
            Exit;
        end;
    
        // if you want to implement wrap-around searching, uncomment this...
        {
        for Result := 0 to StartIndex-1 do
        begin
          if (ListView_GetItemState(Handle, Result, LVIS_SELECTED) and LVIS_SELECTED) = 0 then
            Exit;
        end;
        }
      end;
      Result := -1;
    end;
    

    或:

    function TNewListView.NextUnselected(StartIndex: Integer): Integer;
    
      function IsNotSelected(Index: Integer): Boolean;
      var
        ItemInfo: TLVItem;
      begin
        FillChar(ItemInfo, SizeOf(ItemInfo), 0);
        ItemInfo.iItem := Index;
        ItemInfo.mask := LVIF_STATE;
        ItemInfo.stateMask := LVIS_SELECTED;
        ListView_GetItem(Handle, ItemInfo);
        Result := (ItemInfo.state and LVIS_SELECTED) = 0;
      end;
    
    begin
      if HandleAllocated then
      begin
        for Result := StartIndex+1 to ListView_GetItemCount(Handle)-1 do
        begin
          if IsNotSelected(Result) then
            Exit;
        end;
    
        // if you want to implement wrap-around searching, uncomment this...
        {
        for Result := 0 to StartIndex-1 do
        begin
          if IsNotSelected(Result) then
            Exit;
        end;
        }
      end;
      Result := -1;
    end;
    

    这两种方法都适用于您正在尝试的内容。