加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

delphi – TListView标题栏中的复选框 – 如何防止它窃取焦点?

发布时间:2020-12-15 04:03:33 所属栏目:大数据 来源:网络整理
导读:这与问题 How to show a check box in TListView header column?有关. 我想使用@Sertac Akyuz的this answer代码. (我还需要这个在WinXP中工作) 但我想让标题CheckBox不从ListView或其他活动控件中窃取焦点. 一个快速的解决方法是将焦点始终设置为ListHeaderW
这与问题 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;

什么都行不通.我错过了什么?

解决方法

不要为BN_CLICKED通知处理WM_COMMAND消息,在按下按钮时想要点击一下然后在点击之后向外拖动的行为将不起作用.单击包括按下并释放控件上的按钮.

相反,您可以查找是否在控件内单击鼠标,然后切换检查状态(如果是).之后您可以吃掉鼠标消息,因此控件将无法获得焦点.但是应该在复选框的窗口过程中检查,而不是列表视图.修改后的代码

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.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读