Reputation: 373
To solve some problems in our system, I need to implement the events OnKeyDown
and OnKeyPress
in Frames (TFrame). Currently did a palliative solution, but it is very ugly and present any problems.
The process is more or less the following:
1) I created the event OnKeyDown
and OnKeyPress
in a base class inherited from TFrame.
2) In a standard form based on TForm, implemented a control that intercepts execution keys. So, this process execute first key events on frame and after key events on the form.
I had to do way, because I wanted the OnKeyDown events execute before in frame and after on the Form. The implementation work, but I'll think in better code.
Can anyone suggest a better solution? Is there a more elegant way to solve this problem?
Upvotes: 2
Views: 5963
Reputation: 373
I did some more tests and got a simpler solution that principle worked without problems.
1) I get an object of type base of my frame through a recursive function.
2) If the active control is inclue in standard frame, call the OnKeyDown, OnKeyPress event execution.
If someone needs something, below is the code of my application testing.
Unit UnFrameBase;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ActnList;
Type
TFrameBase = Class(TFrame)
PnlBase: TPanel;
Private
Public
Procedure EventFrameKeyDown(Sender: TObject; Var Key: Word; Shift: TShiftState); Virtual;
End;
Implementation
{$R *.dfm}
{ TFrameBase }
Procedure TFrameBase.EventFrameKeyDown(Sender: TObject; Var Key: Word; Shift: TShiftState);
Begin
//nothing
End;
End.
Unit UnControlsClassTest;
interface
uses Classes, Controls;
Function ActiveControlAs(AControl: TWinControl;
AClass: TWinControlClass): TWinControl;
Function CheckControl(Var C: TWinControl; ControlClass: TWinControlClass): Boolean;
Var
Parent: TWinControl;
Begin
Result := (C Is ControlClass);
If (Result = False) And (C <> Nil) And (C.Parent <> Nil) Then
Begin
Parent := C.Parent;
Result := CheckControl(Parent, ControlClass);
If Result Then
C := Parent;
End;
End;
Var
C: TWinControl;
Begin
C := AControl;
If CheckControl(C, AClass) Then
Result := C
Else
Result := Nil;
End;
Unit UnMainFormTest;
Interface
Uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ComCtrls, UnFrameCustomer, UnFrameBase;
Type
TFormMain = Class(TForm)
Procedure FormCreate(Sender: TObject);
Procedure BtnTestarClick(Sender: TObject);
Procedure FormKeyDown(Sender: TObject; Var Key: Word; Shift: TShiftState);
Private
Function GetInstanceActiveFrame(AActiveControl: TWinControl): TFrameBase;
Public
{ Public declarations }
End;
Implementation
Uses UnControlsClassTest;
{$R *.dfm}
Function TFormMain.GetInstanceActiveFrame(AActiveControl: TWinControl): TFrameBase;
Begin
Result := TFrameBase(ActiveControlAs(AActiveControl, TFrameBase));
End;
Procedure TFormMain.FormKeyDown(Sender: TObject; Var Key: Word; Shift: TShiftState);
Var
LActiveFrame: TFrameBase;
Begin
LActiveFrame := GetInstanceActiveFrame(ActiveControl);
If Assigned(LActiveFrame) Then
LActiveFrame.EventoFrameKeyDown(Sender, Key, Shift);
If Key In [VK_DOWN, VK_RETURN] Then
Begin
Perform(WM_NEXTDLGCTL, 0, 0);
Key := 0;
End
Else If Key = VK_UP Then
Begin
Perform(WM_NEXTDLGCTL, 1, 0);
Key := 0;
End;
End;
Upvotes: 1
Reputation: 1610
Try this. Instead of creating a TFrame descendent, create KeyDown and KeyPress procedures in the frame like
procedure TFrame2.KeyDown(var Key: Word; Shift: TShiftState);
begin
Memo1.Lines.Add('KeyDown: '+IntToStr(Key));
end;
procedure TFrame2.KeyPress(var Key: Char);
begin
Memo1.Lines.Add('KeyPress: '+IntToStr(ord(Key)));
end;
Then call them from the OnKeyDown and OnKeyPress of the form like
procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
Frame21.KeyDown(Key,Shift);
end;
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
Frame21.KeyPress(Key);
end;
Upvotes: 2