6

フレーム内に KeyPreview 機能を持たせたいと思います。つまり、入力 (たとえば、フレームのコントロールの 1 つが選択されているか、マウスが内部にある) がフレーム (複数のパネルと他のコントロールを持つ) にある場合です。 ) 次に、ユーザーが押したキーが最初にフレームによって処理されます。

これを行う方法はありますか?TFrame で KeyPreview に似たプロパティを見つけられませんでした。

私は主に C++Builder を使用していますが、RAD Studio のバージョン XE5 を使用しています。

4

3 に答える 3

6

最近の「ShortCut が起動するとき」調査のおかげで、フレームのスタンドアロン ソリューションを見つけました。

要するに、すべての重要なメッセージがTWinControl.CNKeyDwonアクティブ コントロールに入力されます。メッセージが ShortCut であるかどうかを判断しながら、すべての親TWinControl.IsMenuKeyをトラバースするそのメソッド呼び出し。これは、そのメソッドを呼び出すことによって行われます。Frame のメソッドが存在しない場合は、Frame を作成してオーバーライドしました。いつでも、PopupMenu を自分で Frame に追加できることに注意してください。メソッドをサブクラス化してオーバーライドすることにより、必要な KeyPreview 機能として機能するFrame のメソッドが呼び出されます。(OnKeyDdown イベント ハンドラーを割り当てることもできます)。GetPopupMenu.IsShortCutGetPopupMenuTPopupMenuIsShortCutKeyDown

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.
于 2014-12-14T11:23:09.900 に答える
2

その時点でフォームにフレームが 1 つしかない場合は、フォームの KeyPreview 機能を利用して、必要な情報をフレームに転送できます。

情報を転送するだけの場合は、元の VCL コードを変更する必要はありません。変更した TFrame クラスを作成するだけです。したがって、これを行うと VCL 全体が壊れる心配はありません。

簡単なコード例を次に示します。

メインフォーム コード:

unit Unit2;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Unit3, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TForm2 = class(TForm)
    Panel1: TPanel;
    ModifiedFrame: TModifiedFrame;
    Edit1: TEdit;
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form2: TForm2;

implementation

{$R *.dfm}

procedure TForm2.FormCreate(Sender: TObject);
begin
  //This is required since I'm asigning frames OnKeyDown event method manually
  ModifiedFrame.OnKeyDown := ModifiedFrame.FrameKeyDown;
end;

procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  //Forward key down information to ModifiedFrame
  ModifiedFrame.DoKeyDown(Sender, Key, Shift);
  if Key = 0 then
    MessageDlg('Key was handled by the modified frame!',mtInformation,[mbOK],0)
  else
    MessageDlg('Key was not handled!',mtInformation,[mbOK],0);
end;

end.

ModifiedFrame コード:

unit Unit3;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes,
  Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;

type
  TModifiedFrame = class(TFrame)
    Edit1: TEdit;
    //Normally this method would be added by the Delphi IDE when you set the
    //OnKeyDown event but here I created this manually in order to avoid crating
    //design package with modified frame
    procedure FrameKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    { Private declarations }
    FOnKeyDown: TKeyEvent;
  public
    { Public declarations }
    //This is used to recieve forwarded key down information from the Form
    procedure DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  published
    //Property to alow setting the OnKeyDown event at design-time
    //NOTE: In order for this to work properly you have to put this modified
    //frame class into separate unti and register it as new design time component
    property OnKeyDown: TKeyEvent read FOnKeyDown write FOnKeyDown;
  end;

implementation

{$R *.dfm}

procedure TModifiedFrame.DoKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  //Check to see if OnKeyDownEvent has been assigned. If it is foward the key down
  //information to the event procedure
  if Assigned(FOnKeyDown) then FOnKeyDown(Self, Key, Shift);
end;

procedure TModifiedFrame.FrameKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  //Do something
  if Key = VK_RETURN then
  begin
    MessageBeep(0);
    Key := 0;
  end;
end;

end.

同様のアプローチを使用して、他の重要なイベントを転送できます。

于 2014-12-13T22:08:39.540 に答える