具有 vsIcon 和 vsSmallIcon 复选框支持的虚拟 ListView?

Virtual ListView with checkbox support for vsIcon and vsSmallIcon?

我在 Delphi 中使用 ListView。我将 OwnerData 属性 设置为 true,以便我将在 OnData 事件中提供该项目的数据。

此外,我想为列表视图的每个项目添加一个复选框。但是Checkbox属性只支持vsList和vsReport模式,不支持vsIcon和vsSmallicon。有解决方法吗?或者是否有支持此类功能的现成的第 3 方 VCL?

But the Checkbox property only supports vsList and vsReport mode ...

这是不正确的。您正在查看 VCL documentation,其中说明

Set Checkboxes to true to make check boxes appear next to the list items when ViewStyle is vsList or vsReport. ...

这是过时的信息。本机控件见documentation

Version 6.00 and later Check boxes are visible and functional with all list view modes except the tile view mode introduced in ComCtl32.dll version 6. ...

事实上,如果您在其中一种图标模式下的常规 TListView 控件上尝试它,您会发现复选框没有问题。



但是这对您没有帮助。在这方面,您的问题格式错误,它假设 Checkboxes 在列表和报告模式下使用虚拟列表视图控件可以正常工作。不是这样的。

当您可以在列表项上使用 Checked 属性 时,复选框很好。在虚拟列表视图控件中,没有您可以检查 的项目。我引用 LVM_SETITEMCOUNT 消息:

If the list-view control was created without the LVS_OWNERDATA style, sending this message causes the control to allocate its internal data structures for the specified number of items. ...

...

If the list-view control was created with the LVS_OWNERDATA style (a virtual list view), sending this message sets the virtual number of items that the control contains.

控件只知道有那么多项目,没有按项目存储。 VCL 反映 API 控件:当您请求一个项目并且您的控件设置了 OwnerData 时,将在临时项目上调用 OnData 事件处理程序以反映项目的属性。

在虚拟列表视图中,您可以使用状态图像管理支票。引用自 documentation:

... You can use state images, such as checked and cleared check boxes, to indicate application-defined item states. State images are displayed in icon view, small icon view, list view, and report view.



下面是一个基本实现,它将项目状态信息保存在一个单独的数组中。要 运行 它,创建一个空白的新表单,为该表单创建一个 OnCreate 处理程序并粘贴代码。

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics,   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.ImgList;

type
  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    FListView: TListView;
    FListViewCheckStateArray: array of 0..1;
    procedure ListViewData(Sender: TObject; Item: TListItem);
    procedure ListViewMouseDown(Sender: TObject; Button: TMouseButton;
        Shift: TShiftState; X, Y: Integer);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
var
  Bmp: TBitmap;
begin
  FListView := TListView.Create(Self);
  FListView.Parent := Self;
  FListView.Align := alClient;
  FListView.OwnerData := True;
  FListView.ViewStyle := vsSmallIcon;

  FListView.StateImages := TImageList.Create(Self);
  Bmp := TBitmap.Create;
  Bmp.PixelFormat := pf32bit;
  Bmp.SetSize(16, 16);
  DrawFrameControl(Bmp.Canvas.Handle, Rect(0, 0, 16, 16), DFC_BUTTON,
      DFCS_BUTTONCHECK);
  FListView.StateImages.Add(Bmp, nil);
  DrawFrameControl(Bmp.Canvas.Handle, Rect(0, 0, 16, 16), DFC_BUTTON,
      DFCS_BUTTONCHECK or DFCS_CHECKED);
  FListView.StateImages.Add(Bmp, nil);
  Bmp.Free;

  FListView.Items.Count := 257;
  SetLength(FListViewCheckStateArray, FListView.Items.Count);

  FListView.OnData := ListViewData;
  FListView.OnMouseDown := ListViewMouseDown;
end;

procedure TForm1.ListViewData(Sender: TObject; Item: TListItem);
begin
  Item.Caption := Format('This is item %.2d', [Item.Index]);
  Item.StateIndex := FListViewCheckStateArray[Item.Index];
end;

procedure TForm1.ListViewMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  Item: TListItem;
begin
  if (Button = mbLeft) and
      (htOnStateIcon in FListView.GetHitTestInfoAt(X, Y)) then begin
    Item := FListView.GetItemAt(X, Y);
    Assert(Assigned(Item));
    FListViewCheckStateArray[Item.Index] :=
        Ord(not Boolean(FListViewCheckStateArray[Item.Index]));
    FListView.UpdateItems(Item.Index, Item.Index);
  end;
end;

end.

PS: 绘图工件应该是另一个问题的主题。