Delphi XE - TRibbon操作总是将焦点转移到MainForm [英] Delphi XE - TRibbon actions always send focus to MainForm
问题描述
当我在不是应用程序主窗体的表单上放置一个TRIBOB控件时,TRIBBB的动作(即剪切,粘贴)将在执行操作后始终将焦点返回到MainForm。
When I place a TRibbon control on a form that is not the MainForm of the application, that TRibbon's actions (i.e. Cut, Paste) will always return focus to the MainForm after the action is executed.
即使持有Tribbon的TForm不是MainForm的孩子,也会发生这种情况。
This occurs even if the TForm that holds the TRibbon is not a child of the MainForm.
我正在使用Windows 7 64位, Embarcadero RAD Studio XE版本15.0.3953.35171。
I am using Windows 7 64-bit, Embarcadero RAD Studio XE Version 15.0.3953.35171.
我使用TRibbon控件错误,或者这是TRibbon的问题?
Am I using the TRibbon control incorrectly, or is this an issue with the TRibbon?
推荐答案
这显然是设计的。来自'ribbonactnctrls.pas'的示例代码片段:
This is evidently by design. Sample code snippet from 'ribbonactnctrls.pas':
procedure TRibbonBaseButtonControl.Click;
begin
inherited;
SetFocus(Application.MainForm.Handle);
end;
如您所见,没有任何条件可以帮助我们避免通话。在菜单项选择和按键处理程序中也有相同的代码。
As you see there are no conditions checked that would help us avoid the call. There's the same code also in menu item selection and key press handlers.
我可能会修改焦点调用的源注释,并尝试看看是否有任何副作用。
I would probably modify the source commenting the focus calls, and try to see if there're any side effects.
作为替代,您可以将焦点重新切换回您的表单,然后再切换到主窗体。假设ActionList1是包含不是主窗体的标准操作的TActionList:
As an alternative you can restore the focus back to your form after it is switched to the main form. Suppose 'ActionList1' is the TActionList that contains standard actions on the not main form:
type
TForm2 = class(TForm)
..
procedure ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
private
..
procedure TForm2.ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
begin
PostMessage(Handle, WM_SETFOCUS, WPARAM(True), 0);
end;
然而,这将导致主窗体在每次执行操作时都会短暂闪烁。如果你不想要的话,你可以改变设计,使主窗体知道什么时候得到一个不需要的焦点,并假定它没有集中。
This will however cause the main form to flash briefly every time an action is executed. If you don't want that, you can change the design so that the main form knows when it is getting an unwanted focus, and fake that it's not focused.
unit1:
const
UM_CANCELIGNOREFOCUS = WM_USER + 7;
type
TForm1 = class(TForm)
..
private
FIgnoreFocus: Boolean;
procedure UMCancelIgnoreFocus(var Msg: TMessage); message UM_CANCELIGNOREFOCUS;
procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCACTIVATE;
public
property IgnoreFocus: Boolean write FIgnoreFocus;
end;
...
uses Unit2;
procedure TForm1.WMNCActivate(var Msg: TWMNCActivate);
begin
Msg.Result := 0;
if not (Msg.Active and FIgnoreFocus) then
inherited;
end;
procedure TForm1.UMCancelIgnoreFocus(var Msg: TMessage);
begin
FIgnoreFocus := False;
TForm(Msg.WParam).SetFocus;
end;
in unit2:
uses
unit1;
procedure TForm2.ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
begin
Form1.IgnoreFocus := True;
PostMessage(Form1.Handle, UM_CANCELIGNOREFOCUS, NativeInt(Self), 0);
end;
但是,如果您没有设置MainFormOnTaskBar项目来源,从那时起,主要形式将不仅仅是获得关注,而且会被带到前方。在这种情况下,两种形式都可以通过冻结其z阶来响应不需要的焦点更改/激活。然后,代码将成为unit1:
However, this is not enough if you don't have 'MainFormOnTaskBar' set in project source, since then the main form will not only gain focus but will be brought to front. In this case both forms could respond to the unwanted focus change/activation by freezing their z-orders. The code would then become for unit1:
const
UM_CANCELIGNOREFOCUS = WM_USER + 7;
type
TForm1 = class(TForm)
..
private
FIgnoreFocus: Boolean;
procedure UMCancelIgnoreFocus(var Msg: TMessage); message UM_CANCELIGNOREFOCUS;
procedure WMNCActivate(var Msg: TWMNCActivate); message WM_NCACTIVATE;
procedure WMWindowPosChanging(var Msg: TWMWindowPosChanging);
message WM_WINDOWPOSCHANGING;
public
property IgnoreFocus: Boolean read FIgnoreFocus write FIgnoreFocus;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
uses Unit2;
procedure TForm1.WMNCActivate(var Msg: TWMNCActivate);
begin
Msg.Result := 0;
if not (Msg.Active and FIgnoreFocus) then
inherited;
end;
procedure TForm1.WMWindowPosChanging(var Msg: TWMWindowPosChanging);
begin
inherited;
if FIgnoreFocus then
Msg.WindowPos.flags := Msg.WindowPos.flags or SWP_NOZORDER;
end;
procedure TForm1.UMCancelIgnoreFocus(var Msg: TMessage);
begin
FIgnoreFocus := False;
TForm(Msg.WParam).SetFocus;
end;
和unit2:
type
TForm2 = class(TForm)
..
procedure ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
private
procedure WMWindowPosChanging(var Msg: TWMWindowPosChanging);
message WM_WINDOWPOSCHANGING;
public
end;
var
Form2: TForm2;
implementation
uses
unit1;
{$R *.dfm}
procedure TForm2.ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
begin
Form1.IgnoreFocus := True;
PostMessage(Form1.Handle, UM_CANCELIGNOREFOCUS, NativeInt(Self), 0);
end;
procedure TForm2.WMWindowPosChanging(var Msg: TWMWindowPosChanging);
begin
inherited;
if Form1.IgnoreFocus then
Msg.WindowPos.flags := Msg.WindowPos.flags or SWP_NOZORDER;
end;
这篇关于Delphi XE - TRibbon操作总是将焦点转移到MainForm的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!