Reputation: 402
I'm trying to implement a TDI interface in my project. It's working fine so far (the forms are created inside tabs on my PageControl - as expected). However, I'm facing an annoying issue: the OnKeyPress event isn't fired on my child forms just because they are "parented". I've tried both ways below, but with no success:
procedure TForm1.Button1Click(Sender: TObject);
var
f: TForm2;
begin
f := TForm2.Create(self);
f.ManualDock(PageControl1);
f.Show;
end;
-OR-
procedure TForm1.Button1Click(Sender: TObject);
var
f: TForm2;
tab: TTabSheet;
begin
tab := TTabSheet.Create(PageControl1);
tab.PageControl := PageControl1;
tab.Parent := PageControl1;
f := TForm2.Create(tab);
f.BorderStyle := bsNone;
f.Align := alClient;
f.Parent := tab;
tab.Caption := f.Caption;
f.Show;
end;
¹ needless to say that the KeyPreview property is set as True.
² if I just comment the following line, the event works fine (but the form is not created inside a TabSheet):
//f.Parent := tab;
Has anyone faced this issue before? Any help? Thanks!
Upvotes: 0
Views: 1158
Reputation: 1659
I had a look at the sources, it turns out that the control receiving the KeyPress
searches for its parent form, and if the form has KeyPreview
set, relays the event to that form:
function TWinControl.DoKeyPress(var Message: TWMKey): Boolean;
var
Form: TCustomForm;
Ch: Char;
begin
Result := True;
Form := GetParentForm(Self);
if (Form <> nil) and (Form <> Self) and Form.KeyPreview and
TWinControl(Form).DoKeyPress(Message) then Exit;
// [...]
Result := False;
end;
The parent form is the top level form in the chain. This means that your Form1
receives the event (if it has KeyPreview
set) in addition to the original control:
function GetRealParentForm(Control: TControl; TopForm: Boolean = True): TCustomForm;
begin
while (TopForm or not (Control is TCustomForm)) and (Control.Parent <> nil) do
Control := Control.Parent;
if Control is TCustomForm then
Result := TCustomForm(Control) else
Result := nil;
end;
This leaves you with a couple of options:
KeyPress
in Form1
instead, though you then probably have to find out which child form it came from originally.KeyPreview
to false, and instead add the handler to
the controls on Form2
directly.KeyPress
to the top level form, but
instead to the next form in the chain, I think that's what I would
do.Upvotes: 1