0

I have an app that opens a non-modal form from the main form. The non-modal form has a TMemo on it. The main form menu uses "space" as one of its accelerator characters.

When the non-modal form is open and the memo has focus, every time I try to enter a space into the memo on the non-modal form, the main form event for the "space" shortcut fires!

I have tried turning MainForm.KeyPreview := false while the other form is open but no dice.

Any ideas?

Kromster
  • 7,181
  • 7
  • 63
  • 111
rossmcm
  • 5,493
  • 10
  • 55
  • 118
  • I think the same subject is here: http://stackoverflow.com/questions/1104380/tmenuitem-shortcuts-overwrite-shortcuts-from-controls-tmemo – SimaWB Apr 21 '10 at 06:33

3 Answers3

2

This may be an old topic, but i had the same issue a moment ago and searched for a suitable solution. Your topic came up but not with a solution i would want to use.

My problem was: I have a main form with a lot of shortcuts (Backspace, Delete, etc) and a second form with an edit box. The edit box didn't get any key actions, which are handled by the main form shortcuts.

My solution: Set the child forms OnShortCut, wich will catch the shortcuts before they get interpreted by the main form with:

procedure ChildForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  Handled := True;
  Self.DefaultHandler(Msg);
end;

That did the trick for me, the child form catches the shortcuts and handles them as common key messages. The edit box can be used as intended.

Hugie
  • 455
  • 5
  • 17
  • It should be added that i did not need any shortcuts in the child form. So this solution might not work as intended for child windows with their own shortcuts. – Hugie May 07 '14 at 08:31
2

Disable the menu item on the main form while the memo has focus, and re-enable it when the memo loses it. You can do this from the TMemo.OnEnter and TMemo.OnExit events.

procedure TOtherForm.Memo1Enter(Sender: TObject);
begin
  if Application.MainForm is TYourMainForm then
    TYourMainForm(Application.MainForm).MenuItemWithSpace. Enabled := False;
end;

procedure TOtherForm.Memo1Exit(Sender: TObject);
begin
  if Application.MainForm is TYourMainForm then
    TYourMainForm(Application.MainForm).MenuItemWithSpace. Enabled := True;
end;

The use of Application.MainForm and the typecast are to prevent hard-coding in a form variable name in the child form.

Kromster
  • 7,181
  • 7
  • 63
  • 111
Ken White
  • 123,280
  • 14
  • 225
  • 444
  • 1
    I don't like that your asking TOtherForm to control TYourMainForm. It feels like a tight coupling. The problem is down in the key events somewhere. – Preston Apr 21 '10 at 15:27
  • I agree, its a bit inelegant, but I just put: MyMainForm.MenuEntry1.Enabled := false ; in the OnShow event, and MainForm.MenuEntry1.Enabled := true ; in the OnClose event. Seems to work a treat. – rossmcm Apr 22 '10 at 00:52
  • 1
    @Preston: Neither do I. The problem, though, is that the OP wants to use a non-modal form and disable a shortcut only when a *specific control* on that non-modal form is active. The non-modal form is the only place to do it, unless you disable the shortcut for the entire period the child form is in existence (which the OP said wasn't desired). – Ken White Apr 26 '10 at 16:16
0

If you have many menu items, or many controls, could be very difficult to threat the problem for each of them. Instead, you could use a function in FormActivate() and FormDeActivate() methods of main window in order to clean and restore all shortcuts in a easy and simple way:

var sstore : TStrings;

procedure Tmain_form.FormActivate(Sender: TObject);
begin
    if (sstore <> NIL) then tratta_shortcuts_menu(main_menu, {read_shortcuts}FALSE, sstore)
end;

procedure Tmain_form.FormDeactivate(Sender: TObject);
begin
    tratta_shortcuts_menu(main_menu, {read_shortcuts}TRUE, sstore)
end;

procedure tratta_shortcuts_menu(menu : TMainMenu;bo_read_shortcuts : boolean;var sstore : TStrings);
{ if BO_READ_SHORTCUTS then 1) read shortcuts 2) save them on SSTORE (Shortcuts STORE) 3) delete them from menu;
ELSE restore all shortcuts from SSTORE  }

procedure sostituisci(im : TMenuItem);
const INDICATORE_SHORTCUT = '~ ';
begin
    if bo_read_shortcuts then begin
        if (im.ShortCut <> 0) then begin
            sstore.Add(im.name);
            sstore.Add(INDICATORE_SHORTCUT + menus.ShortCutToText(im.ShortCut));    
            im.ShortCut := 0
        end
    end
    else begin
        var i : smallint := sstore.indexof(im.Name);
        if (i <> -1) then begin
            im.ShortCut := menus.TextToShortCut(copy(sstore[i + 1], length(INDICATORE_SHORTCUT) + 1, MAXINT))
        end
    end
end;

procedure tratta(im : TMenuItem);
begin
    sostituisci(im);
    for var i : smallint := 0 to im.Count-1 do tratta(im.Items[i])
end;

begin
    if (menu = NIL) then exit;

    if bo_read_shortcuts then begin if (sstore = NIL) then sstore := TStringList.Create else sstore.Clear end;
    for var i : smallint := 0 to menu.Items.Count-1 do tratta(menu.Items[i]);
    if NOT bo_read_shortcuts then begin sstore.Free;sstore := NIL end
end;
Feacio
  • 80
  • 1
  • 1
  • 7