这与问题How to show a check box in TListView header column?有关。
我希望@Sertac Akyuz
使用this answer中的代码。 (我还需要这个在WinXP中工作)
但是我想让标题CheckBox不从ListView或其他活动控件中窃取焦点。
快速解决方法是将焦点始终设置为ListHeaderWndProc
中的ListView:
...
FListHeaderChk.Checked := not FListHeaderChk.Checked;
ListView1.SetFocus;
// code that checks/clears all items
但这有点难看。因为CheckBox首先被聚焦,然后焦点返回到ListView。如果我单击CheckBox并将鼠标拖到CheckBox外部,它将无法收到BN_CLICKED
消息。
我也尝试过:
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;
没有任何作用。我错过了什么?
答案 0 :(得分:7)
请勿处理WM_COMMAND
通知BN_CLICKED
消息,按下按钮时想要点击的行为,然后在点击赢取后在外面拖动否则。单击包括按下并释放控件上的按钮。
相反,您可以查找是否在控件内单击鼠标,然后切换检查状态(如果是)。之后您可以吃掉鼠标消息,因此控件将无法获得焦点。但是应该在复选框的窗口过程中检查,而不是列表视图。修改后的代码:
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.