Delphi XE - TRibbon操作总是将焦点转移到MainForm [英] Delphi XE - TRibbon actions always send focus to MainForm

查看:273
本文介绍了Delphi XE - TRibbon操作总是将焦点转移到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屋!

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