Embedded Frames do not receive Shortcut key input

Dear Experts,

I am using TFrames in Delphi 7.

At application's main form create I create my Frames all descent from TBaseFrame.
These frames then get's showed and hide on the appropriate button's onclick() events.

The problem I have here is there are 2 frames which have a TListView component on it.
I have created an action to select / deselect all items in the TListView components.
The shortcut key for these actions are CTRL+A.

Ok, when I show my first Frame the CTRL+A is working but when showing the second and hiding the first the input still goes to the first (hidden) frame.

How can I force the keyboard input to the visible Frame?

Thanks in advance!
Marius0188Asked:
Who is Participating?
 
House_of_DexterCommented:
k...do you have an actionlist for each frame?

If so...  ActionList1.State :=  asSuspended for the disabled frame; and   ActionList1.State :=  asNormal for the visible frame;

This will stop the ActionList from grabbing Shortcuts...

0
 
Marius0188Author Commented:
I should also mention that I have tried:
SetFocus()
BringToFront()
SentToBack()
and it's not working.
0
 
Ivanov_GCommented:
Make KeyPreview = True on your form. This will make sure your form receive the Key pressed before all other controls. The in OnKeyDown, OnKeyUp, OnKeyPress handle the events.
0
Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

 
Marius0188Author Commented:
Can you maybe please show me the code for OnKeyDown, OnKeyUp and OnKeyPress events to effectively forward all key strokes to a TFrame?

Thanks so far!
0
 
Ivanov_GCommented:
Example:

parent form:
------------------------------------------------------
uses Unit2;

procedure TForm1.FormCreate(Sender: TObject);
var
  Frame2 : TFrame2;
begin
  Frame2 := TFrame2.Create(Self);
  Frame2.Parent := Panel1;
  Frame2.Align := alClient;
  Frame2.Show;
end;

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
var
  i : Integer;
begin
  for i := 0 to Self.ComponentCount - 1 do
    begin
      if (Self.Components[i] is TFrame) then
        if ((Self.Components[i] as TFrame).Visible) and ((Self.Components[i] as TFrame).Name = 'Frame2') then
          begin
            // frame is visible
            (Self.Components[i] as TFrame).Perform(WM_KEYDOWN, ord(Key), 0);
          end;
    end;
end;

-------------------------------------------------------------------------------
frame:
-------------------------------------------------------------------------------

type
  TFrame2 = class(TFrame)
  private
    { Private declarations }
    procedure OnKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN;
  public
    { Public declarations }
  end;

implementation

{$R *.dfm}

{ TFrame2 }

procedure TFrame2.OnKeyDown(var Msg: TWMKeyDown);
begin
  ShowMessage(IntToStr(Msg.CharCode));
end;
0
 
House_of_DexterCommented:
procedure PassKeyToFrame(aParent: TWinControl; aKey: TWMKey; var aHandled: Boolean );
var
  a_iIndex: integer;
begin
  for a_iIndex := 0 to aParent.ControlCount -1 do
  begin
  {we loop through all the children}
    if aParent.Controls[a_iIndex] is TBaseFrame then
    begin
      aHandled := TBaseFrame(aParent.Controls[a_iIndex]).HandleKey(aKey);
      if aHandled then
        break;
    end;
    if aParent.Controls[a_iIndex] is TWinControl then
{if its a WinControl...meaning it can be a Parent to other controls...we loop
 through them, and so and so on.}
      PassKeyToFrame(TWinControl(aParent.Controls[a_iIndex]), aKey, aHandled);
  end;
end;

procedure TForm1.FormShortCut(var Msg: TWMKey; var Handled: Boolean);
begin
  PassKeyToFrame(Form1, Msg, Handled);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Frame1 := TBaseFrame.Create(Self);
  Frame1.Parent := Panel1;
end;


type
  TBaseFrame = class(TFrame)
    Label1: TLabel;
    Button1: TButton;
  private
    { Private declarations }
  public
    { Public declarations }
    function HandleKey(aKey: TWMKey): boolean;
  end;


{ TBaseFrame }

function TBaseFrame.HandleKey(aKey: TWMKey): boolean;
begin
  Result := Visible;
  if Result then
    ShowMessage('rcvd');
end;
0
 
Marius0188Author Commented:
Thanks all so far.

1. May I ask why does the visible Frame not automatically receive keystrokes?
Why does it feel like I have to hack it (or something like that) in order to work normal?
If one frame is hidden and another frame is visible isn't it logical that the hidden one should not respond to keystrokes
but instead the visible one? Can someone please explain to me why?


2. I have quickly looked over all the comments and it feels to me there should be a simple more elegant way of handling this. Please understand I am not being difficult. :)
a) But can't I just force a Frame to be the ActiveControl of my MainForm?
The comments if not complex at all but like I said. If embedding Frames in a TForm is should behave like any other control? Or not?

0
 
House_of_DexterCommented:
procedure EnableFrame(aFrame: TFrame; aEnable: boolean);
begin
  aFrame.Visible := aEnable;
  aFrame.Enabled := aEnable;
  if aFrame.Enabled then
    if aFrame.CanFocus then
      Form1.ActiveControl := aFrame;
end;

when you make the Frame Not Visible...also set it Not Enabled ...that should stop it from getting keyboard input
0
 
Marius0188Author Commented:
I have tried enabling and disabling the frame according to it's visible state.
Have also set ActiveControl but still it's not working.

0
 
Marius0188Author Commented:
Maybe I should mention.
On my MainForm I have a TPanel which is Parent control of Frames.
0
 
Marius0188Author Commented:
Just for testing purposes I have set
the Frame.Parent := nil when hidden.

Then the Key stokes are working fine but obviously lots of errors.
0
 
Ivanov_GCommented:
In my example I used

Form1.KeyPreview := true;
Frame.Parent := Panel1;
0
 
ziolkoCommented:
try this:
PostMessage(valid_handke_here, WM_ACTIVATE, WA_ACTIVE, 0);

ziolko.
0
 
Marius0188Author Commented:
Hi All,

I have tried everything so far to get the Frame to be the active control.
Nothing is working.
Maybe if I show my code you will understand better.



procedure TfrmMain.SetCurrentFrame(const Value: TBaseFrame);
begin
  If Assigned(CurrentFrame) then
  begin
    If CurrentFrame = Value then Exit;
    CurrentFrame.Enabled := False;
    CurrentFrame.Hide;
  end;

  FCurrentFrame := Value;

  CurrentFrame.Enabled := True;
  CurrentFrame.Parent := panMain;
  CurrentFrame.Align := alClient;
  CurrentFrame.Show;

  CurrentFrame.LoadData;

  frmMain.ActiveControl := CurrentFrame;

//  frmMain.ActiveControl := CurrentFrame;
//    frmMain.FocusControl(CurrentFrame);
//  CurrentFrame.BringToFront;
//  CurrentFrame.SetFocus;
 
end;
0
 
House_of_DexterCommented:
Can I see the code that you are executing on Ctrl + A

Are you using an ActionList?
0
 
Marius0188Author Commented:
Yes I am using a TActionList and assign my shortcuts via actions properties.
0
 
Marius0188Author Commented:
This is the code executed on the action which have the shortcut: CTRL+A.
-----------------------------------------------------------------------------------------
procedure TAnalyzeFrame.actSelectAllExecute(Sender: TObject);
begin
  inherited;
  Busy := True;
  Try
    Case tbtnSelectAll.Tag of
      0:
        begin
          tbtnSelectAll.Tag := 1;
          lsvDownloads.SelectAll;
        end;
      1:
        begin
          tbtnSelectAll.Tag := 0;
          lsvDownloads.ClearSelection;
        end;
    end;
  Finally
    Busy := False;
  end;
end;
-----------------------------------------------------------------------------

Please note that there are another frame with similar action to select all in it's TListView.
0
 
Marius0188Author Commented:
Yes the 2 Frames giving problems each have their own TActionList.

Ok I will test your example and let you know.

Thanks!
0
 
Marius0188Author Commented:
OK thanks House of Dexter.

It worked!
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.