ListView’s OnCheckboxClick event

Unfortunately, the TListView object does not have a specific event fired, when the Checked state changes for a TListItem (an item in the ListView). If you need to react in such situation, you have to mimic this behaviour yourself. Here are some tips on this.

Every Delphi's Guru will probably think about subclassing and catching windows messages here. If you're one of them -- at delphi.about.com you'll find an example. But, there's an easier way to achieve the same.

I crafted it together out of two separate solutions -- DelphiPages.com forum and Delphi forum at cjcsoft.net.

All you have to do is to catch OnMouseDown or OnMouseUp and use two methods of TListView there -- GetHitTestInfoAt and GetItemAt. Here is full example:

procedure TMainForm.ListViewMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
    ht: THitTests;
    Item: TListItem;
begin
    ht := (Sender as TCustomListView).GetHitTestInfoAt(X, Y);

    if htOnStateIcon in ht then
    begin
        Item := (Sender as TCustomListView).GetItemAt(X, Y);

        ShowMessage('OnCheckboxClick fired on item "' + Item.Caption + '"');
    end;
end;

If, for any reason, you need to use OnClick event (which does not provides X and Y variables), you still can do this, but you need to add these lines to your code:

var
    P: TPoint;
begin
    GetCursorPos(P);
    P := (Sender as TCustomListView).ScreenToClient(P);

and then change:

ht := (Sender as TCustomListView).GetHitTestInfoAt(X, Y);

with:

ht := (Sender as TCustomListView).GetHitTestInfoAt(P.X, P.Y);

Leave rest untoched and your code should work the same even in OnClick event.

This example uses (Sender as TCustomListView) construction, because I use the same procedure as OnMouseUp even handler for more than one TListView. If you only need to use this solution for one ListView, you can use its name directly (i.e. ListView1.GetItemAt assuming that it's name is ListView1).

Of course, this solutions mimic OnCheckboxClick, not OnCheckBoxStateChange. This means, that with it, you can react only on user clicking checbox. You can't react this way on checkbox changing state by programical meanings -- i.e. changing TListItem.Checked property from your code.

Leave a Reply