简体   繁体   中英

Shortcut triggers TAction on first created form instead of form with focus

I found (in Delphi 2010) that shortcuts always end up on first form (as owned by main form) that has that action, but not the currently focused form. My TMainFrm owns several TViewFrm . Each has a TActionManager with the same TActons .

I see some ways out, but wonder whats the best fix.. (and not a bad hack)

  • The forms are navigated using a tabset which calls their Hide() and Show(). I'd did not expect hidden forms to receive keypresses. Am i doing something wrong?
  • It seems that action shortcuts are always start at the main form, and using TCustomForm.IsShortCut() get distributed to owned forms. I see no logic there to respect hidden windows, should i override it and have it trigger the focused form first?
  • Disabling all TActions in TViewFrm.Hide() .. ?
  • Moving the TActionToolBar to TMainFrm but that is a pit of snakes and last resort.

I have found a workaround thats good enough for me; my main form now overrides TCustomForm.IsShortcut() and first checks visible windows from my list of editor tabs.

A list which i conveniently already have, so this might not work for everyone.

// Override TCustomForm and make it check the currently focused tab/window first.
function TFormMain.IsShortCut(var Message: TWMKey): Boolean;
  function DispatchShortCut(const Owner: TComponent) : Boolean; // copied function unchanged
  var
    I: Integer;
    Component: TComponent;
  begin
    Result := False;
    { Dispatch to all children }
    for I := 0 to Owner.ComponentCount - 1 do
    begin
      Component := Owner.Components[I];
      if Component is TCustomActionList then
      begin
        if TCustomActionList(Component).IsShortCut(Message) then
        begin
          Result := True;
          Exit;
        end
      end
      else
      begin
        Result := DispatchShortCut(Component);
        if Result then
          Break;
      end
    end;
  end;
var
  form : TForm;
begin
  Result := False;

  // Check my menu
  Result := Result or (Menu <> nil) and (Menu.WindowHandle <> 0) and
    Menu.IsShortCut(Message);

  // Check currently focused form   <-------------------  (the fix)
  for form in FEditorTabs do
    if form.Visible then
    begin
      Result := DispatchShortCut(form);
      if Result then Break;
    end;
  // ^ wont work using GetActiveWindow() because it always returns Self.

  // Check all owned components/forms (the normal behaviour)
  if not Result then
    Result := inherited IsShortCut(Message);
end;

Another solution would be to change DispatchShortCut() to check for components being visible and/or enabled, but that might impact more than i'd like. I wonder whether the original code architects had a reason not to -- by design. Best would be have it called twice: first to give priority to visible+enabled components, and second call as fallback to normal behavior.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM