Pregunta

Cuando coloco un control TRibbon en un formulario que no es el MainForm de la aplicación, las acciones de TRibbon (es decir, Cortar, Pegar) siempre devolverán el foco al MainForm después de que se ejecute la acción.

Esto ocurre incluso si el TForm que contiene el TRibbon no es un hijo del MainForm.

Estoy usando Windows 7 de 64 bits, Embarcadero RAD Studio XE versión 15.0.3953.35171.

¿Estoy usando el control TRibbon de forma incorrecta o se trata de un problema con TRibbon?

¿Fue útil?

Solución

Esto es evidentemente por diseño. Fragmento de código de muestra de 'ribbonactnctrls.pas':

procedure TRibbonBaseButtonControl.Click;
begin
  inherited;
  SetFocus(Application.MainForm.Handle);
end;

Como puede ver, no hay ninguna condición marcada que nos ayude a evitar la llamada. También existe el mismo código en la selección de elementos del menú y en los controladores de pulsaciones de teclas.


Probablemente modificaría la fuente comentando las llamadas de enfoque y trataría de ver si hay efectos secundarios.

Como alternativa, puede restaurar el foco de nuevo a su formulario después de cambiarlo al formulario principal. Supongamos que 'ActionList1' es TActionList que contiene acciones estándar en el no formulario principal:

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;

Sin embargo, esto hará que el formulario principal parpadee brevemente cada vez que se ejecute una acción. Si no quiere eso, puede cambiar el diseño para que el formulario principal sepa cuándo está recibiendo un enfoque no deseado y fingir que no está enfocado.

En la unidad 1:

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;

en la unidad 2:

uses
  unit1;

procedure TForm2.ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
begin
  Form1.IgnoreFocus := True;
  PostMessage(Form1.Handle, UM_CANCELIGNOREFOCUS, NativeInt(Self), 0);
end;


Sin embargo, esto no es suficiente si no tiene 'MainFormOnTaskBar' configurado en el código fuente del proyecto, ya que entonces el formulario principal no solo ganará el foco sino que se traerá al frente. En este caso, ambas formas podrían responder al cambio / activación de enfoque no deseado congelando sus órdenes z. El código sería entonces para 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;

y para 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;
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top