6

TRibbon コントロールをアプリケーションの MainForm ではないフォームに配置すると、TRibbon のアクション (切り取り、貼り付けなど) は、アクションの実行後に常にフォーカスを MainForm に戻します。

これは、TRibbon を保持する TForm が MainForm の子でない場合でも発生します。

Windows 7 64 ビット、Embarcadero RAD Studio XE バージョン 15.0.3953.35171 を使用しています。

TRibbon コントロールを間違って使用していますか、それとも TRibbon の問題ですか?

4

1 に答える 1

2

これは明らかに設計によるものです。「ribbonactnctrls.pas」のサンプル コード スニペット:

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

ご覧のとおり、呼び出しを回避するのに役立つ条件はチェックされていません。メニュー項目の選択とキー押下ハンドラーにも同じコードがあります。


おそらく、フォーカス呼び出しをコメントするソースを変更し、副作用があるかどうかを確認します。

別の方法として、フォームがメイン フォームに切り替えられた後、フォームにフォーカスを戻すことができます。「ActionList1」がメイン フォームの標準アクションを含む TActionList であるとします。

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;

ただし、これにより、アクションが実行されるたびにメイン フォームが短時間点滅します。それを望まない場合は、メイン フォームが不要なフォーカスを得ていることを認識できるようにデザインを変更し、フォーカスされていないように見せかけることができます。

ユニット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;

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 のコードは次のようになります。

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;
于 2012-01-13T16:30:12.467 に答える