2011-12-06 7 views
6

Cuando coloco un control TRibbon en un formulario que no es el MainForm de la aplicación, las acciones de TRibbon (es decir, Cut, Paste) siempre devolverán el foco al MainForm después de la acción es ejecutado.Delphi XE - Las acciones de TRibbon siempre envían focus a MainForm

Esto ocurre incluso si el TForm que contiene el TRibbon no es un elemento secundario de MainForm.

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

¿Estoy usando el control TRibbon incorrectamente, o es esto un problema con el TRibbon?

+2

Una cinta pretende ser un elemento de interfaz de usuario en el formulario principal, lo hace, de hecho, "modificar" la forma es añadido a. Si pones una cinta en algún lugar que no sea en la forma principal de tu programa, y ​​envía el foco a la aplicación. MainForm, no me sorprende; espera que sea parte de la forma principal. El VCL viene con el código fuente para que pueda abrir la unidad y ver si puede encontrar el código en cuestión. –

+1

La aplicación que estoy diseñando va para una sensación de "Outlook", que, en su implementación, utiliza una cinta para el programa principal y una cinta diferente para crear correos electrónicos, elementos de calendario, contactos, etc. Siempre que utilizo una acción de cinta de Outlook en un correo electrónico, no devuelve mi enfoque a la ventana principal de Outlook. He buscado un poco a través de la fuente para el componente TRibbon, pero es cierto que es un poco grueso. Continuaré haciéndolo para ver si puedo descubrir dónde está sucediendo esto y si puedo anular este comportamiento.Hasta ahora, sin embargo, no he tenido suerte. – Aaron

+2

Suena terriblemente como un error para mí. Ese comportamiento no debería suceder. Si puede repro en una aplicación simple, entonces debe informarlo al QC –

Respuesta

2

Esto es evidentemente por diseño. Código de la muestra fragmento de '' ribbonactnctrls.pas:

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

Como se puede ver que no hay condiciones controladas que ayudarían a evitar la llamada. También hay el mismo código en la selección de elementos del menú y en los controladores de pulsación de teclas.


Probablemente modificaría la fuente comentando las llamadas de enfoque, y trataré de ver si hay algún efecto secundario.

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

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; 

Este será sin embargo causar la forma principal a parpadear brevemente cada vez que se ejecuta una acción. Si no quieres eso, puedes cambiar el diseño para que el formulario principal sepa cuándo está recibiendo un enfoque no deseado y simular que no está enfocado.

En unidad1:

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 unit2:

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 se ha configurado 'MainFormOnTaskBar' en la fuente del proyecto, desde entonces, la forma principal no solo ganará foco, sino que será llevado al frente. En este caso, ambas formas podrían responder al cambio/activación de foco no deseado congelando sus z-órdenes. El código entonces convertido para unidad1:

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; 
+1

¡Gran respuesta! Todavía no sé si alguien puede decirme por qué diseñaron el control para comportarse de una manera tan forzada, cuando podría haber devuelto el control al padre de la cinta, supongo que es solo un misterio délfico. – Aaron

Cuestiones relacionadas