复选框TListView的标题列 - 如何prevent它偷焦点? [英] check box in TListView header column - How to prevent it from stealing focus?

查看:148
本文介绍了复选框TListView的标题列 - 如何prevent它偷焦点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此有关的问题<一href=\"http://stackoverflow.com/questions/8730212/how-to-show-a-check-box-in-tlistview-header-column\">How以显示TListView的标题列复选框?。

我想通过来使用来自这个答案中的code @Sertac Akyuz 。 (我需要这在WinXP也工作)

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

不过,我想使头复选框不从的ListView或其他主动控制窃取焦点。

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

一个快速的解决方法是设置焦点的总是的在ListView中 ListHeaderWndProc

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

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

但是,这是有点难看。由于该复选框是第一集中,然后焦点返回到ListView。另外,如果我点击复选框并拖动鼠标无法接收的 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;

没有什么工作。我缺少什么?

Nothing works. What am I missing?

推荐答案

不处理的 WM_COMMAND 消息 BN_CLICKED 的通知,要了解其同时pressing按钮,点击后行为的 draggging外的点击后会不会以其他方式使用。咔嗒由pressing和释放上的控制按钮。

Do not process the WM_COMMAND message for a BN_CLICKED notification, the behavior you want about having a click while pressing the button and then draggging outside after the click won't work otherwise. A click consists of pressing and releasing the button on the control.

相反,你可以看一下如果单击控件中的鼠标,然后切换选中状态,如果它是。你可以以后吃鼠标消息,因此控制将不会收到焦点。但是,这应该复选框,而不是列表视图的窗口过程中进行检查。修改code:

Instead you can look for if the mouse is clicked inside the control and then switch the checked state if it is. You can eat the mouse message after that, so the control won't receive the focus. But this should be checked in the window procedure of the checkbox, not the list view. 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.

这篇关于复选框TListView的标题列 - 如何prevent它偷焦点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆