Domanda

Quando metto un controllo TRibbon su un form che non è il MainForm dell'applicazione, le azioni di TRibbon (cioè Taglia, Incolla) restituiranno sempre il focus al MainForm dopo che l'azione è stata eseguita.

Ciò si verifica anche se il TForm che contiene il TRibbon non è un figlio del MainForm.

Utilizzo Windows 7 a 64 bit, Embarcadero RAD Studio XE versione 15.0.3953.35171.

Sto usando il controllo TRibbon in modo errato o questo è un problema con TRibbon?

È stato utile?

Soluzione

Questo è evidentemente di progettazione. Esempio di snippet di codice da "ribbonactnctrls.pas":

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

Come vedi non ci sono condizioni controllate che ci aiutino a evitare la chiamata. C'è lo stesso codice anche nella selezione delle voci di menu e nei gestori di pressione dei tasti.


Probabilmente modificherei la fonte commentando le chiamate al focus e proverei a vedere se ci sono effetti collaterali.

In alternativa puoi ripristinare il focus sul tuo form dopo che è passato al form principale. Supponiamo che "ActionList1" sia la TActionList che contiene azioni standard nel modulo principale non :

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;

Questo farà sì che il form principale lampeggi brevemente ogni volta che viene eseguita un'azione. Se non lo desideri, puoi modificare il design in modo che il modulo principale sappia quando sta ottenendo un focus indesiderato e fingere di non essere focalizzato.

Nell'unità 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;

nell'unità 2:

uses
  unit1;

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


Tuttavia, questo non è sufficiente se non hai "MainFormOnTaskBar" impostato nel sorgente del progetto, da allora il form principale non solo guadagnerà il focus ma sarà portato in primo piano. In questo caso entrambe le forme potrebbero rispondere al cambiamento / attivazione indesiderata del focus congelando i loro ordini z. Il codice diventerebbe quindi per unità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;
    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;

e per l'unità2:

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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top