Each item in a list view can have an icon next to it. The list of icons is defined by the SmallImages (and/or LargeImages) property. Further, the StateImages property defines additional images to display next to each item in the list view.
Each item in the Items list can be associated with an image by setting its StateIndex property. The state image appears to the left of the normal list item.
Radio Style Checkable Items
I needed to have a way to allow a user to select / check / mark one item from the list. I could not use the Selected property as it was also needed that one item can be selected while the other can be "checked".The Checkboxes property was not of help. Checkboxes allows checking several items at a time.
What I needed is something like a radio group where only one list item in a list view can be checked at a time.
I also needed for some items to be non-checkable.
Here's what I finally did:
- Use the StateIndex of an item to display a custom radio like image for the item.
- Handle OnClick to implement OnStateImageClick
- Apply bold to the checked item
//maps to the position of the state image in the TImageListIn the OnClick event, ScreenToClient converts mouse position coordinates to list view's coordinate system. Next, GetHitTestInfoAt determines what elements of the list view are under the mouse. If the user clicked on the state icon, the htOnStateIcon is included in the result of the GetHitTestInfoAt.
const
lisSelected = 5;
lisNotSelected = 4;
lisNonSelectable = -1;
//handles ListView OnClick
procedure TlvForm.lvClick(Sender: TObject);
var
hts : THitTests;
lvCursosPos : TPoint;
li, lii : TListItem;
begin
inherited;
//position of the mouse cursor related to ListView
lvCursosPos := lv.ScreenToClient(Mouse.CursorPos) ;
//click where?
hts := lv.GetHitTestInfoAt(lvCursosPos.X, lvCursosPos.Y);
//locate the state-clicked item
if htOnStateIcon in hts then
begin
li := lv.GetItemAt(lvCursosPos.X, lvCursosPos.Y);
if Assigned(li) then
begin
if li.StateIndex = lisNonSelectable then Exit;
for lii in lv.Items do
if lii.StateIndex <> lisNonSelectable then lii.StateIndex := lisNotSelectd;
li.StateIndex := lisSelected;
end;
end;
end;
//handles ListView AdvancedCustomDrawItem
procedure TlvForm.lvAdvancedCustomDrawItem(Sender: TCustomListView;
Item: TListItem; State: TCustomDrawState; Stage: TCustomDrawStage;
var DefaultDraw: Boolean);
begin
if Assigned(Item) then
begin
if Item.StateIndex = lisSelected then
Sender.Canvas.Font.Style := [fsBold]
else
Sender.Canvas.Font.Style := [];
end;
end;
Now, mark the "clicked" item as checked (lisSelected) and also make sure all other checkable items are unchecked.
That's it.
Note that you will need some glyphs that look like checked and non-checked radio buttons. Use those to display the state of the item.

