I have a TPopupMenu
where one of the items should (after doing other stuff) select the item of the TChecklistBox
(CategoryFilter) the mouse cursor is at. Currently I do this with the following code, but this is inaccurate as it selects the next or 2ndnext item!
var
ClickedItem: Integer;
CategoryFilter: TChecklistBox;
begin
CategoryFilter.CheckAll(cbUnchecked, FALSE, FALSE);
ClickedItem := CategoryFilter.ItemAtPos(Mouse.CursorPos.Subtract(CategoryFilter.ClientOrigin), TRUE);
if ClickedItem > -1 then
CategoryFilter.Checked[ClickedItem] := TRUE;
end;
How can I fix this and get the correct item, the mouse is over?
The important thing here is that the mouse's screen coordinates (x, y) at the time you right click a list item are generally not the same as the mouse's screen coordinates (x', y') at the time you click (or otherwise invoke) the menu item. I mean, often you move the mouse to the menu item in order to click it. So you need to save the coordinates at mouse down time.
Fortunately, the VCL does this for you. The popup menu's PopupPoint
property contains these coordinates.
So you can do
procedure TForm1.MenuItem1Click(Sender: TObject);
begin
var LIdx := CheckListBox1.ItemAtPos
(
CheckListBox1.ScreenToClient(PopupMenu1.PopupPoint),
True
);
if LIdx <> -1 then
CheckListBox1.Checked[LIdx] := True;
end;
Actually, I do essentially this myself:
Please note that you also should make sure that right-clicking an item also selects (not checks) it. It's poor UX otherwise.
If you do so, you can, as a bonus, simply use the ItemIndex
property to find the clicked item, so you don't need PopupPoint
at all:
for var i := 0 to Count - 1 do
Checked[i] := i = ItemIndex; // check only this one
(Here Self
is the check list box, because I have created my own check list box descendant with all these enhancements built in. That's the right thing to do, obviously.)
I also make double-clicking an item toggle its checkbox, make ^A check all, make ^C copy the selected item to clipboard, add convenient functions to obtain the array of checked strings and/or objects, etc.