我有一个只包含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;
答案 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
事件的表单(或者可能是模板顶部的模板)框架),并添加关闭按钮。挑战在于让它在视觉上可以接受。