Check box in the TListView header column. How to prevent his theft of focus?

This is due to the question. How do I display a checkmark in the TListView header column? .

I want to use the code this answer @Sertac Akyuz . (I also need to work in WinXP)

But I want the CheckBox title to not steal focus from ListView or other active controls.

A quick workaround is to always set focus on the ListView in ListHeaderWndProc :

 ... FListHeaderChk.Checked := not FListHeaderChk.Checked; ListView1.SetFocus; // code that checks/clears all items 

But this is disgusting. Since the CheckBox is first focused, then the focus returns to the ListView. also If I clicked a CheckBox and dragged the mouse outside of the CheckBox, it could not receive the BN_CLICKED message.

I also tried:

 TCheckBox = class(StdCtrls.TCheckBox) private procedure WMMouseActivate(var Message: TWMMouseActivate); message WM_MOUSEACTIVATE; protected procedure CreateParams(var Params: TCreateParams); override; public procedure DefaultHandler(var Message); override; end; procedure TCheckBox.WMMouseActivate(var Message: TWMMouseActivate); begin Message.Result := MA_NOACTIVATE; // no effect! end; procedure TCheckBox.CreateParams(var Params: TCreateParams); const WS_EX_NOACTIVATE = $08000000; begin inherited; Params.ExStyle := Params.ExStyle or WS_EX_NOACTIVATE; // no effect! end; procedure TCheckBox.DefaultHandler(var Message); begin case TMessage(Message).Msg of WM_SETFOCUS: begin if IsWindow(TWMSetFocus(Message).FocusedWnd) then begin TMessage(Message).Result := 1; // ??? // inherited // ??? Windows.SetFocus(TWMSetFocus(Message).FocusedWnd); Exit; // Checkbox fails to receive `BN_CLICKED` message end; end; end; inherited; end; 

Nothing works. What am I missing?

+8
checkbox listview delphi delphi-5
source share
1 answer

Do not process the WM_COMMAND message to notify BN_CLICKED , the behavior that you want to have when you click by clicking the button and then dragging it outside after the click does not work otherwise. A click consists of pressing and releasing a button on a control.

Instead, you can search by clicking inside the control, and then toggle the checked state, if any. After that, you can eat the mouse message, so the control will not receive focus. But this needs to be checked in the check box procedure, and not as a list. Modified Code:

 unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls; type TForm1 = class(TForm) ListView1: TListView; CheckBox1: TCheckBox; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private FListHeaderChk: TCheckBox; FSaveListHeaderChkWndProc: TWndMethod; FListHeaderWnd: HWND; procedure ListHeaderChkWndProc(var Msg: TMessage); end; var Form1: TForm1; implementation uses commctrl; {$R *.dfm} function GetCheckSize: TPoint; // from checklst.pas begin with TBitmap.Create do try Handle := LoadBitmap(0, PChar(OBM_CHECKBOXES)); Result.X := Width div 4; Result.Y := Height div 3; finally Free; end; end; procedure TForm1.FormCreate(Sender: TObject); var CheckSize: TPoint; HeaderSize: TRect; begin ListView1.HandleNeeded; FListHeaderWnd := ListView_GetHeader(ListView1.Handle); FListHeaderChk := TCheckBox.Create(nil); CheckSize := GetCheckSize; FListHeaderChk.Height := CheckSize.X; FListHeaderChk.Width := CheckSize.Y; ShowWindow(ListView1.Handle, SW_SHOWNORMAL); windows.GetClientRect(FListHeaderWnd, HeaderSize); FListHeaderChk.Top := (HeaderSize.Bottom - FListHeaderChk.Height) div 2; FListHeaderChk.Left := FListHeaderChk.Top; FListHeaderChk.Parent := Self; FListHeaderChk.TabStop := False; windows.SetParent(FListHeaderChk.Handle, FListHeaderWnd); FSaveListHeaderChkWndProc := FListHeaderChk.WindowProc; FListHeaderChk.WindowProc := ListHeaderChkWndProc; end; procedure TForm1.FormDestroy(Sender: TObject); begin FListHeaderChk.Free; end; procedure TForm1.ListHeaderChkWndProc(var Msg: TMessage); begin if (Msg.Msg = WM_MOUSEACTIVATE) and (Msg.LParamLo = HTCLIENT) then begin Msg.Result := MA_NOACTIVATEANDEAT; FListHeaderChk.Checked := not FListHeaderChk.Checked; Exit; end; FSaveListHeaderChkWndProc(Msg); end; end. 
+7
source share

All Articles