Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to have a KeyPreview-like functionality when working with Frames?

I would like to have a KeyPreview functionality within Frames, I mean, that when the input (say, one of the controls of the frame is selected, or the mouse is inside) is in a frame (which would have several panels and other controls) then the keys pressed by the user are first processed by the frame.

Is there a way to do this? I haven't found a property similar to KeyPreview in TFrame.

I'm using version XE5 of RAD Studio, altough I mostly work with C++Builder.

like image 800
Rodrigo Gómez Avatar asked Dec 13 '14 19:12

Rodrigo Gómez


1 Answers

Thanks to my recent "When does a ShortCut fire"-investigation, I have worked out a stand alone solution for your Frame.

In short: all key messages enter in TWinControl.CNKeyDwon of the active control. That method calls TWinControl.IsMenuKey which traverses all parents while determining whether the message is a ShortCut. Is does so by calling its GetPopupMenu.IsShortCut method. I have overridden the Frame's GetPopupMenu method by creating one if it is not present. Note that at all time you still can add a PopupMenu to the Frame yourself. By subclassing TPopupMenu and overriding the IsShortCut method, the Frame's KeyDown method is called, which serves as the KeyPreview functionality you require. (I could also have assigned the OnKeyDdown event handler).

unit Unit2;

interface

uses
  Winapi.Messages, System.Classes, Vcl.Controls, Vcl.Forms, Vcl.Menus,
  Vcl.StdCtrls;

type
  TPopupMenu = class(Vcl.Menus.TPopupMenu)
  public
    function IsShortCut(var Message: TWMKey): Boolean; override;
  end;

  TFrame2 = class(TFrame)
    Label1: TLabel;
    Edit1: TEdit;
  private
    FPreviewPopup: TPopupMenu;
  protected
    function GetPopupMenu: Vcl.Menus.TPopupMenu; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
  end;

implementation

{$R *.dfm}

{ TPopupMenu }

function TPopupMenu.IsShortCut(var Message: TWMKey): Boolean;
var
  ShiftState: TShiftState;
begin
  ShiftState := KeyDataToShiftState(Message.KeyData);
  TFrame2(Owner).KeyDown(Message.CharCode, ShiftState);
  Result := Message.CharCode = 0;
  if not Result then
    Result := inherited IsShortCut(Message);
end;

{ TFrame2 }

function TFrame2.GetPopupMenu: Vcl.Menus.TPopupMenu;
begin
  Result := inherited GetPopUpMenu;
  if Result = nil then
  begin
    if FPreviewPopup = nil then
      FPreviewPopup := TPopupMenu.Create(Self);
    Result := FPreviewPopup;
  end;
end;

procedure TFrame2.KeyDown(var Key: Word; Shift: TShiftState);
begin
  if (Key = Ord('X')) and (ssCtrl in Shift) then
  begin
    Label1.Caption := 'OH NO, DON''T DO THAT!';
    Key := 0;
  end;
end;

end.
like image 133
NGLN Avatar answered Sep 28 '22 10:09

NGLN