2011-12-23 11 views
10

フォームに矢印キーを処理するようにしたいのですが、フォームにボタンがない限り、できます。どうしてこれなの?Delphi XEとトラップ矢印キー(OnKeyDownを使用)

+4

大きな質問です。このようなものの根本的な複雑さを掘り起こすことは、観光客と専門家を分けるものです。がんばり続ける! –

答えて

8

矢印キーは、フォーム上のボタン間を移動するために使用します。これは標準的なWindowsの動作です。この標準的な動作を無効にすることはできますが、プラットフォームの標準に逆行する前に2度考える必要があります。矢印キーはナビゲーションのためのものです。

キー・プレスがメッセージ・ループをどのように見つけているかを完全に把握したい場合は、A Key's Odysseyを読むことをお勧めします。ナビゲーションキーになる前にキープレスを傍受したい場合は、IsKeyMsgまたはそれ以前のバージョンで行う必要があります。例えば、Sertacのanswerはそのような可能性を与えます。

+0

Peter Below(そのKey's Odysseyの著者)は、Delphiの重要なコミュニティの男(TeamB)であり、JVCLの偉大な貢献者です。素敵な記事。 –

3

次の使用可能なWinControlに焦点を当てることに対処するために、それらは先取りされているためです。
(ボタンの代わりに[編集]ボタンを押すと、同じことが分かります)

自分で処理したい場合は、OnMessageイベントをアプリケーションに提供し、処理する前にそれらをフィルタリングし、そこで処理することができます。

10

重要なメッセージは、これらのメッセージを受信するコントロール自身によって処理されるため、ボタンをクリックしてもフォームがメッセージを受信しないのはこのためです。だから、通常、あなたはこれらのコントロールをサブクラス化する必要があるだろうが、VCLは親切にもフォームが興味を持っている場合はどうするか子育てのフォームを依頼することです:

type 
    TForm1 = class(TForm) 
    .. 
    private 
    procedure DialogKey(var Msg: TWMKey); message CM_DIALOGKEY; 
    .. 


procedure TForm1.DialogKey(var Msg: TWMKey); 
begin 
    if not (Msg.CharCode in [VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT]) then 
    inherited; 
end; 

フランソワ・編集:、あなたのOP元の質問に答えるためにOnKeyDownを呼び出して、イベントコードが機能するようにする必要があります(自由に編集できます;コメントが長すぎました)。

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Button2: TButton; 
    Button3: TButton; 
    Button4: TButton; 
    procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 
    private 
    { Private declarations } 
    procedure DialogKey(var Msg: TWMKey); message CM_DIALOGKEY; 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

procedure TForm1.DialogKey(var Msg: TWMKey); 
begin 
    case Msg.CharCode of 
    VK_DOWN, VK_UP, VK_RIGHT, VK_LEFT: 
     if Assigned(onKeyDown) then 
     onKeyDown(Self, Msg.CharCode, KeyDataToShiftState(Msg.KeyData)); 
    else 
     inherited 
    end; 
end; 

procedure TForm1.FormKeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    case Key of 
    VK_DOWN: Top := Top + 5; 
    VK_UP: Top := Top - 5; 
    VK_LEFT: Left := Left - 5; 
    VK_RIGHT: Left := Left + 5; 
    end; 
end; 
+0

私はあなたが 'CM_DIALOGKEY'について特別なことについてもう少し説明が必要だと思います。これは確かに行動を変えるための滑らかな方法です。私の答えと重なり合うように自由に感じてください。このコードを使った包括的な答えが私がやったことに勝つので、私はそれを削除します。 –

+0

@David - あなたの投稿を削除することはできません。私がCM_DIALOGKEYについて説明することはあまりありません。主要なメッセージをブロードキャストするために使用されるVCLメッセージです。これは、私のヘルプファイルが言っていることです:* "これは一定のControls.CM_DIALOGKEY" * :)です。アップデート:[documentation](http://docwiki.embarcadero.com/VCL/2010/en/Controls.CM_DIALOGKEY)が改善されました:* "CM_DIALOGKEYはコントロールメッセージを表し、VCLフレームワークで内部的に使用されます" * –

+0

うーん、私はTApplication.IsDlgMsgに関連しているように聞こえたと思った。実際、ここではTApplication.IsDlgMsgも関連していますか、VCLはWindowsのダイアログではなくこれらのナビゲーションキーを処理していますか? –

5

フォーカスのあるオブジェクトだけがキーボードイベントを受け取ることができます。

フォームが矢印キーイベントにアクセスできるようにするには、 はフォームのパブリック部分にMsgHandlerと宣言します。 フォーム作成コンストラクタで、Application.OnMessageをこのMsgHandlerに割り当てます。

以下のコードは、矢印キーの子孫からのものである場合にのみ、矢印キーを傍受します。必要に応じて、より多くのコントロールを追加することができます。

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Application.OnMessage := Self.MsgHandler; 
end; 

procedure TForm1.MsgHandler(var Msg: TMsg; var Handled: Boolean); 
var 
    ActiveControl: TWinControl; 
    key : word; 
begin 
    if (Msg.message = WM_KEYDOWN) then 
    begin 
     ActiveControl := Screen.ActiveControl; 
     // if the active control inherits from TButton, intercept the key. 
     // add other controls as fit your needs 
     if not ActiveControl.InheritsFrom(TButton) 
     then Exit; 

     key := Msg.wParam; 
     Handled := true; 
     case Key of // intercept the wanted keys 
     VK_DOWN : ; // doStuff 
     VK_UP : ; // doStuff 
     VK_LEFT : ; // doStuff 
     VK_RIGHT : ; // doStuff 
     else Handled := false; 
     end; 
    end; 
end; 
0
var 
KBHook: HHook; {this intercepts keyboard input} 

implementation 

{$R *.dfm} 

function KeyboardHookProc(Code: Integer; WordParam: Word; LongParam: LongInt): LongInt; stdcall; 
begin 
case WordParam of 
    vk_Space: ShowMessage ('space') ; 
    vk_Right:ShowMessage ('rgt') ; 
    vk_Left:ShowMessage ('lft') ; 
    vk_Up: ShowMessage ('up') ; 
    vk_Down: ShowMessage ('down') ; 
    end; {case} 
end; 

procedure TForm4.FormCreate(Sender: TObject); 
begin 
KBHook:=SetWindowsHookEx(WH_KEYBOARD,@KeyboardHookProc,HInstance,GetCurrentThreadId()); 
end; 

このコードは、コントロールが(ボタン、リストボックス)に重点を置いている場合でも動作しますので、いくつかのコントロールが自分のキーボードイベントを(デビッドhaffernans答えを読む)ゆるくなることに注意してください。集束コントロール

キーボードイベントなど:あなたのアプリでテキストボックスを持つと(集中している場合)も、その後、

がapplicationevent1を追加したテキストをreciveしたい場合

procedure TForm4.ApplicationEvents1Message(var Msg: tagMSG;var Handled: Boolean); 
begin 
if Msg.message = WM_KEYFIRST then 
    KBHook:=SetWindowsHookEx(WH_KEYBOARD,@KeyboardHookProc,HInstance,GetCurrentThreadId()); 
end; 

function KeyboardHookProc

UnhookWindowsHookEx(KBHook); 
012の下に次のコードを追加します

とOnCreateのイベントから

KBHook:=SetWindowsHookEx(WH_KEYBOARD,@KeyboardHookProc, HInstance, 
GetCurrentThreadId()); 

を削除します。

関連する問題