25-Jan-2001
Re: Shortcuts don't work in docked form
In article <94nqf5$✉bornews.inprise.com>, 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) ✉compuserve.com)
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.
|