Delphi XE - TRibbon-Aktionen senden immer den Fokus an MainForm
Frage
Wenn ich ein TRibbon-Steuerelement in einem Formular platziere, das nicht die Hauptform der Anwendung ist, wird durch die Aktionen von TRibbon (d. h. Ausschneiden, Einfügen) nach Ausführung der Aktion immer der Fokus auf die Hauptform zurückgesetzt.
Dies tritt auch dann auf, wenn die TForm, die den TRibbon enthält, kein untergeordnetes Element der Hauptform ist.
Ich verwende Windows 7 64-Bit, Embarcadero RAD Studio XE Version 15.0.3953.35171.
Benutze ich das TRibbon-Steuerelement falsch oder ist dies ein Problem mit dem TRibbon?
Lösung
Dies ist offensichtlich beabsichtigt. Beispielcode-Snippet aus 'ribbonactnctrls.pas':
procedure TRibbonBaseButtonControl.Click;
begin
inherited;
SetFocus(Application.MainForm.Handle);
end;
Wie Sie sehen, wurden keine Bedingungen überprüft, die uns helfen würden, den Anruf zu vermeiden. Diesen Code gibt es auch bei der Auswahl von Menüelementen und den Handgriffen für Tastendruck.
Ich würde wahrscheinlich die Quelle ändern, die die Fokusaufrufe kommentiert, und versuchen, festzustellen, ob es irgendwelche Nebenwirkungen gibt.
Alternativ können Sie den Fokus wieder auf Ihr Formular zurücksetzen, nachdem es auf das Hauptformular umgeschaltet wurde. Angenommen, 'ActionList1' ist die TActionList, die Standardaktionen im Hauptformular not enthält:
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;
Dies führt jedoch dazu, dass das Hauptformular bei jeder Ausführung einer Aktion kurz blinkt. Wenn Sie das nicht möchten, können Sie das Design so ändern, dass das Hauptformular weiß, wann es einen unerwünschten Fokus erhält, und vortäuschen, dass es nicht fokussiert ist.
In Einheit1:
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 Einheit2:
uses
unit1;
procedure TForm2.ActionList1Execute(Action: TBasicAction; var Handled: Boolean);
begin
Form1.IgnoreFocus := True;
PostMessage(Form1.Handle, UM_CANCELIGNOREFOCUS, NativeInt(Self), 0);
end;
Dies reicht jedoch nicht aus, wenn Sie 'MainFormOnTaskBar' nicht in der Projektquelle festgelegt haben, da dann das Hauptformular nicht nur den Fokus erhält, sondern in den Vordergrund gerückt wird. In diesem Fall könnten beide Formen auf die unerwünschte Änderung / Aktivierung des Fokus reagieren, indem sie ihre Z-Ordnungen einfrieren. Der Code würde dann für unit1: werden
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;
und für Einheit2:
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;