I have a TListview where I want to use the checkboxes to indicate whether an event has happened to an item in the list.
I can read and set the checkbox status, but what I really want to do is disable the ability of the user to change the status using a mouse click.
For a TCheckList I can set the checked state to the inverse using OnClickCheck
The same doesn't work for a TListview. At them moment I can see that the checkbox has been targeted in OnMouseDown but can't disable the click from going through..
procedure TMF.ListViewMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
MyHitTest : THitTests;
begin
MyHitTest := (Sender as TListView).GetHitTestInfoAt(X,Y);
if htOnStateIcon in MyHitTest then
(Sender as TListView).OnMouseDown := nil;
end;
Suggestions?
Use the event Onchanging and set AllowChange to False.
procedure TForm1.ListView1Changing(Sender: TObject; Item: TListItem;
Change: TItemChange; var AllowChange: Boolean);
begin
AllowChange := False;
end;
Update: OP want the user to be able to select the item. So, maybe, a little hack using OnItemChecked event can do.
procedure TForm1.ListView1ItemChecked(Sender: TObject; Item: TListItem);
begin
if TComponent(Sender).Tag = 0 then
begin
TComponent(Sender).Tag := 1;
Item.Checked := not Item.Checked;
TComponent(Sender).Tag := 0;
end;
end;
Update2: The problem using this trick is that you must disable it before you change any item status. For example:
Procedure LoadListViewItems;
begin
//Let's permit modification in ListView Items.
ListView1.OnItemChecked := nil;
try
//put Load Items code Here!
finally
//User cannot change Items statuses
ListView1.OnItemChecked := ListView1ItemChecked;
end;
end;
You could hook the window proc to force the item checked state before any VCL event handling takes place:
TForm1 = class(TForm)
...
private
fLVWndProc: TWndProc;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
// Save the original window proc and install the hook
fLVWndProc := Listview1.WindowProc;
Listview1.WindowProc := LVWndProcHook;
end;
procedure TForm1.LVWndProcHook(var aMessage: TMessage) ;
var
notify: PNMListView;
bItemState: Boolean;
begin
if (aMessage.Msg = CN_NOTIFY)
and (PNMHdr(aMessage.LParam).Code = LVN_ITEMCHANGED) then
begin
notify := PNMListView(aMessage.LParam);
if ((notify.uChanged and LVIF_STATE) <> 0) then
begin
// Determine actual item state and re-apply it before continuing
bItemState := GetUnderlyingItemState(notify.iItem);
ListView_SetCheckState(notify.hdr.hwndFrom, notify.iItem, bItemState);
end;
end;
//original ListView message handling
fLVWndProc(aMessage) ;
end;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With