Ruslan Popov
Re: Shortcuts don't work in docked form
Shortcut to this article
Printer Friendly

Re: Shortcuts don't work in docked form

In article <94nqf5$✉>, Ruslan Popov wrote:
> I have two forms: a main form and a child form that's generic form and it is
> docked into the main form by use of ManualDock. In the child form, there's
> action list, and its actions are assigned some shortcuts. It turns that when
> the child from is embedded into the main form, its (child's) shortcuts do
> not work. How can I make child shortcuts working?

The VCL is not designed to expect actionlists on controls, and if you dock a 
form to another form it becomes a control. The effect is that a control on the 
embbed form that calls GetParentForm to get a reference to its parent form 
will get the "outer" form back, not the embedded form. This is of relevance
in the context of shortcut handling. The following quote comes from a reply to 
a message that asked about a similar problem with frames that have 
actionlists. You should be able to adapt the fix given for your situation.
I have added a few notes at the appropriate places to highlight things that 
work differently with embedded forms vs. frames.

<quote> key handling in Delphi is fairly complex. The sequence of events as they relate to your question are:
- user hits a key, a keydown message is placed into the message queue - Application.ProcessMessage gets it from the queue, feeds it through a   number of Application methods, one of these is IsKeyMsg. - IsKeyMsg sends the key down as a CN_KEYDOWN message to the control   with focus. - TwinControl.CNKeyDown calls TwinControl.IsMenuKey - after checking the popup menu of the control (if any) for the shortcut   without success IsMenuKey locates the controls parent form and calls its   IsShortcut method.   <NOTE: this would find the outer formm not the embedded form!> - Tcustomform.IsShortcut first checks the forms menu, if any. If not   finding a matching shortcut it then walks over the action lists registered   with the form and calls each lists IsShortcut method, which in turn walks   over the actions in the list looking for a shortcut. - If nobody wanted the key as shortcut yet a CM_APPKEYDOWN message is send to   the Application window for the key, TApplication.WndProc handles this by   calling the main forms IsShortCut (if the window is enabled only, not when   a modal form is up). Note that this means that the main forms IsShortcut   will be called twice if the active control is on the main form and the   key is not a shortcut!    The critical part for you is the sequence in which TCustomform.IsShortcut walks over the action lists. A TFrame will add its TActionlist to the parent forms actionlists list when the parent is assigned to its Parent property (see TCustomFrame.SetParent) and remove it when the Parent changes or the actionlist is destroyed. <NOTE: a form does not do this when it is docked!>
As far as i see the sequence of the actionlists does not change afterwards. So if you have several enabled frames on your form their action lists will be queried in the sequence the frames were added to the form, so the frame containing the active control may not be the first to be queried.
What this boils down to is this: if you have colliding shortcuts that may act differently on different frames on your form then you need to override the forms IsShortcut method and take steps there to make sure the frame the active control is on gets first crack at the shortcut. Something like this:
 Function TMyform.IsShortcut( var Message: TWMKey): Boolean; { override }  Var    ctrl: TWinControl;    comp: TComponent;    i: Integer;  Begin    ctrl := ActiveControl;    If ctrl <> Nil Then Begin      Repeat        ctrl := ctrl.Parent      Until (ctrl = nil) or (ctrl Is TCustomframe);      // Note: replace TCustomFrame with TForm, check if the found form is      // self, if not, execute the following block of code.      If ctrl <> nil Then Begin        For i:= 0 To ctrl.componentcount-1 Do Begin          comp:= ctrl.Components[i];          If comp Is TCustomActionList Then Begin            result := TCustomActionList(comp).IsShortcut( message );            If result Then              Exit;          End;        End;      End;    End;    inherited;  End;   Untested!
For efficacies reason you may want to make sure the actionlist on each frame is the first item created (set it to first in the designers createorder menu) and you may also want to assume only one action list will be on a frame and Exit the form loop once you found it, regardless of Result. </quote> Peter Below (TeamB) ✉ No e-mail responses, please, unless explicitly requested! Note: Till Feb.2001 i will only visit the groups on weekends, so be patient if i don't reply immediately.
FYI: Phrase searches are enclosed in either single or double quotes
24-Jul 11:00 utc Operating system upgrade in process, expect some down time.
Originally created by
Mon, 23 Jan 2017 14:40:52 UTC
Copyright © 2009-2017
HREF Tools Corp.