如何在拖动时避免表单获得焦点

时间:2017-06-27 13:09:52

标签: delphi window focus

我有一个只包含TTouchKeyboard的简单表单。表单BorderStyle设置为bsToolWindow。为了避免在单击触摸键盘时获得焦点,我使用此实现处理WM_MOUSEACTIVATE消息:

procedure TKeyboardForm.WMMouseActivate(var Message: TWMMouseActivate);
begin
  Message.Result := MA_NOACTIVATE;
end;

BorderStyle设置允许使用标题栏拖动表单,但在这种情况下,表单仍然会获得焦点。有没有办法避免这种情况?

更新:我尝试在CreateParams中将WS_EX_NOACTIVATE添加到ExStyle,但不幸的是,这不会阻止表单在拖动时获得焦点。

procedure TKeyboardForm.CreateParams(var Params: TCreateParams);
begin
  inherited;
  Params.ExStyle := Params.ExStyle or WS_EX_NOACTIVATE;
end;

2 个答案:

答案 0 :(得分:3)

因为我对要求我手动更新键盘形式的聚焦表单变量的方法不满意,所以我搜索了一个更透明的解决方案并提出了这种方法。

更新:之前的方法存在VCL样式的一些问题。此外,并非所有的消息处理程序都是必要的,尽管其他消息处理程序也是有用的。此版本适用于VCL样式,尽可能避免任何闪烁:

type
  TKeyboardForm = class(TForm)
    TouchKeyboard1: TTouchKeyboard;
  private
    FLastFocusedForm: TCustomForm;
    procedure SetLastFocusedForm(const Value: TCustomForm);
  protected
    procedure WMActivate(var Message: TWMActivate); message WM_ACTIVATE;
    procedure WMMouseActivate(var Message: TWMMouseActivate); message WM_MOUSEACTIVATE;
    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    property LastFocusedForm: TCustomForm read FLastFocusedForm write SetLastFocusedForm;
  public
    class constructor Create;
    destructor Destroy; override;
    function SetFocusedControl(Control: TWinControl): Boolean; override;
  end;

type
  TKeyboardFormStyleHook = class(TFormStyleHook)
  protected
    procedure WMNCActivate(var Message: TWMNCActivate); message WM_NCACTIVATE;
  end;

procedure TKeyboardFormStyleHook.WMNCActivate(var Message: TWMNCActivate);
begin
  { avoids the title bar being drawn active for blink }
  Message.Active := False;
  inherited;
end;

class constructor TKeyboardForm.Create;
begin
  TCustomStyleEngine.RegisterStyleHook(TKeyboardForm, TKeyboardFormStyleHook);
end;

destructor TKeyboardForm.Destroy;
begin
  LastFocusedForm := nil;
  inherited;
end;

procedure TKeyboardForm.Notification(AComponent: TComponent; Operation: TOperation);
begin
  if (Operation = opRemove) and (AComponent = FLastFocusedForm) then begin
    FLastFocusedForm := nil;
  end;
  inherited;
end;

function TKeyboardForm.SetFocusedControl(Control: TWinControl): Boolean;
begin
  LastFocusedForm := Screen.FocusedForm;
  result := inherited;
end;

procedure TKeyboardForm.SetLastFocusedForm(const Value: TCustomForm);
begin
  if FLastFocusedForm <> Value then
  begin
    if FLastFocusedForm <> nil then begin
      FLastFocusedForm.RemoveFreeNotification(Self);
    end;
    FLastFocusedForm := Value;
    if FLastFocusedForm <> nil then begin
      FLastFocusedForm.FreeNotification(Self);
    end;
  end;
end;

procedure TKeyboardForm.WMActivate(var Message: TWMActivate);
begin
  Message.Active := WA_INACTIVE;
  inherited;
end;

procedure TKeyboardForm.WMMouseActivate(var Message: TWMMouseActivate);
begin
  inherited;
  Message.Result := MA_NOACTIVATE;
end;

procedure TKeyboardForm.WMSetFocus(var Message: TWMSetFocus);
begin
  inherited;
  if (FLastFocusedForm <> nil) and (message.FocusedWnd <> FLastFocusedForm.Handle) then begin
    SendMessage(FLastFocusedForm.Handle, WM_SETFOCUS, 0, 0);
    Message.FocusedWnd := FLastFocusedForm.Handle;
  end;
end;

答案 1 :(得分:2)

以下WMMouseActivate()WMNCActivate()和重置焦点的组合似乎符合您的愿望:

键盘表单(BorderStyle = bsToolWindow)包含WM_MOUSEACTIVATE(正如您已有)和WM_NCACTIVATE的消息处理程序。后者有一个点,用编辑控件将焦点重置到窗口。

此外,keyboardform将跟踪哪个表单包含具有焦点的编辑(或其他)控件,并通过引入一种新的显示方法(我称之为ShowUnfocused())和一个名为{{的字段来实现。 1}}。

FocusedForm: THandle

键盘形式由以下编辑控件的常用代码调用:

procedure TKbdForm.ShowUnfocused(FocusedWindow: THandle);
begin
  FocusedForm := FocusedWindow;
  Show;
end;

procedure TKbdForm.FormShow(Sender: TObject);
begin
  SetForegroundWindow(FocusedForm);
end;

procedure TKbdForm.WMMouseActivate(var Message: TWMMouseActivate);
begin
  Message.Result := MA_NOACTIVATE;
end;

procedure TKbdForm.WMNCActivate(var Message: TWMNCActivate);
begin
  Message.Result := 1; // important
  SetForegroundWindow(FocusedForm);
end;

上述内容的替代方法可以是设置procedure TForm17.EditClick(Sender: TObject); begin KbdForm.ShowUnfocused(self.Handle); (Sender as TWinControl).SetFocus; end; 并安排直接从表单表面拖动带有BorderStyle = bsNone事件的表单(或者可能是模板顶部的模板)框架),并添加关闭按钮。挑战在于让它在视觉上可以接受。