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

时间:2018-08-31 22:12:52

标签: listview delphi delphi-2009

我想在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 个答案:

答案 0 :(得分:4)

您正在使用LVFI_PARAM标志呼叫ListView_FindItem()

  

LVFI_PARAM

     

搜索此结构的lParam成员与项目的lParam结构的LVITEM成员之间的匹配项。

这告诉ListView将指定的TLVFindInfo.lParam原样与每个列表项的lParam进行比较,直到找到匹配项。

如果您以非虚拟模式(TListView)使用OwnerData=False,则列表项的lParam值将保留其对应的TListItem对象指针。

如果您在{strong>虚拟模式(TListView)下使用OwnerData=True,则列表项的lParam值始终为0。

ListView_FindItem()(和基础LVM_FINDITEM消息)可以通过其Caption(全部或部分),其lParam 1 < / sup>或它的位置,但没有其他

1:例如,TListItems.IndexOf()方法使用ListView_FindItem()通过TListItem搜索返回lParam对象的索引(仅适用于非虚拟模式,其中每个项目的lParamTListItem对象指针)。

您也尝试执行lParam搜索,但是您正在使用 WRONG lParam值进行搜索!您正在将TLVFindInfo.lParam的值设置为指向本地TLVItem的指针,因此LVFI_PARAM比较将从不项目清单。这就是为什么您总是得到-1的原因。

ListView_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;

如您所见,本地TLVItem变量的 contents 从未使用过,因此将TLVItem字段设置为什么都没有关系。

期望 ListView_FindItem() 本质上执行以下逻辑,这不是它的工作方式,也不是该文件的工作方式:< / p>

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_FindItem() / LVM_FINDITEM按状态搜索项目,因为它们不支持这种搜索。

您可能会倾向于使用ListView_GetNextItem() / LVM_GETNEXTITEM

  

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

但是,它们只能用于搜索已启用指定特征(例如启用LVNI_SELECTED)的列表项。不能使用它们来查找具有指定特征 ABSENCE 的项目(例如禁用LVNI_SELECTED)。

因此,要执行所需的操作,只需使用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;

这两种方法都可以满足您的尝试。