listviewdelphidelphi-10.3-rio

How to use Checkboxes in TListView (OwnerData True) in Delphi


I am trying to implement checkboxes in a TListView component with OwnerData=True in Delphi 10.3.3 VCL project.

Here's a minimal example of what I have tried so far:

procedure TForm1.FormCreate(Sender: TObject);
begin
  ListView1.ViewStyle := vsReport;
  ListView1.OwnerData := True;
  ListView1.Checkboxes := True;

  // MyData with some initial data
end;

procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
begin
  Item.Caption := 'Item ' + IntToStr(Item.Index + 1);
  Item.Checked := MyData[Item.Index].FChecked;
end;

However, it doesn't display checkboxes.

Is there a recommended approach or workaround to handle this effectively? Any code examples or guidance would be greatly appreciated!


Solution

  • This issue seems to have been discussed multiple times, but no one has shared a complete code solution. Thanks to Remy's answer, I was finally able to write the full code, and it works!

    ListView properties:

    ViewStyle = vsReport
    OwnerData = True
    OwnerDraw = False
    CheckBoxes = False
    StateImages = VirtualImageList1
    

    Code:

    procedure TForm1.ListView1Data(Sender: TObject; Item: TListItem);
    begin
      Item.Caption := MyData[Item.Index].FColumn1;
      Item.SubItems.Add(MyData[Item.Index].FColumn2);
      if MyData[Item.Index].FChecked then
      begin
        Item.Checked:=True;
        Item.StateIndex:=1;
      end else
      begin
        Item.Checked:=False;
        Item.StateIndex:=0;
      end;
    end;
    
    procedure TForm1.ListView1MouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    var
      HitTestInfo: THitTests;
      Item: TListItem;
    begin
      HitTestInfo := ListView1.GetHitTestInfoAt(X, Y);
      if htOnStateIcon in HitTestInfo then
      begin
        Item := ListView1.GetItemAt(X, Y);
        if Assigned(Item) then
        begin
          MyData[Item.Index].FChecked := not MyData[Item.Index].FChecked;
          ListView1.Items[Item.Index].Update;
        end;
      end;
    end;
    
    procedure TForm1.ListView1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      if key=32 then // space key
      begin
        if ListView1.ItemIndex>-1 then
        begin
          MyData[ListView1.ItemIndex].FChecked := not MyData[ListView1.ItemIndex].FChecked;
          ListView1.Items[ListView1.ItemIndex].Update;
        end;
      end;
    end;