7

OnKeyPressユーザーがキーを押したときにイベントを受け取りたいTab

procedure TForm1.Edit1(Sender: TObject; var Key: Char);
begin
   case Key of
   #09:
      begin
         //Snip - Stuff i want to do
      end;
   end;
end;

Editボックスのサブクラス化を試み、WM_GETDLGCODEメッセージを処理します。

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
   case Message.Msg of
   WM_GETDLGCODE: Message.Result := DLGC_WANTTAB;
   else
      FOldAccountNumberWindowProc(Message);
   end;
end;

Tab そして、 KeyPressイベントを受け取るようになりましたが(希望どおり)、LeftまたはRightカーソルキーを押すと、フォーカスがタブオーダーの前または次のコントロールに移動します。

Tab Key Pressイベントを受け取る正しい方法は何ですか?

ボーナスリーディング

私はMSDNのドキュメントが言うことをやってみました:

wParam
ユーザーが押した仮想キーで、Windows にこの通知を発行するよう促したものです。ハンドラーは、これらのキーを選択的に処理する必要があります。たとえば、ハンドラーは VK_RETURN を受け入れて処理しますが、VK_TAB はオーナー ウィンドウに委譲します。値のリストについては、Virtual-Key Codes を参照してください。

lParam MSG 構造体 (システムがクエリを実行している場合は NULL) へのポインター。

しかしwParam、 とwParamはどちらもゼロです。

アップデート 2

この回答と同じバグがあることに気付きました:

if Message.Msg = WM_GETDLGCODE then
   Message.Result:= Message.Result or DLGC_WANTTAB
else
   if Assigned(FOldWndProc) then FOldWndProc(Message);

同じ回答の他の場所にリストされている正しいコードの概念を実際に使用する必要がある場合:

if Assigned(FOldWndProc) then FOldWndProc(Message);
if Message.Msg = WM_GETDLGCODE then
   Message.Result:= Message.Result or DLGC_WANTTAB;

これは、元のコードが間違っている理由を説明するのに役立ちます。Message.Resultへの設定DLGC_WANTTABが間違っています:

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
   case Message.Msg of
   WM_GETDLGCODE: Message.Result := DLGC_WANTTAB;
   else
      FOldAccountNumberWindowProc(Message);
   end;
end;

にはまだ値がないためbitwise or、フラグDLGC_WANTTABをにしようとするのも間違っています。Message.ResultMessage.Result

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
   case Message.Msg of
   WM_GETDLGCODE: Message.Result := Message.Result or DLGC_WANTTAB;
   else
      FOldAccountNumberWindowProc(Message);
   end;
end;

EDITWindows のコントロール セットの正しい値を取得するには、最初に元のウィンドウ プロシージャを呼び出す必要がありますMessage.Result次に、ビットごとに組み合わせることができますDLGC_WANTTAB

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
    FOldAccountNumberWindowProc(Message);

    case Message.Msg of
    WM_GETDLGCODE: Message.Result := Message.Result or DLGC_WANTTAB;
    end;
end;

Raymond Chen のブログ エントリを言い換えると、必要に応じて強調が追加されます。

元のコントロールに必要な動作を尋ねた後、DLGC_WANTTAB フラグをオンにします。

だから、これは良いです。カーソル キーは、(フォーカスを移動するのではなく) エディット コントロール内のテキストをナビゲートし続け、キーのOnKeyPress(およびOnKeyDownおよびOnKeyUp) イベントを受け取りTabます。

残りの問題は、ユーザーが押してTabもフォーカスが移動しないことです。

私は自分自身を変更するフォーカスで手動でハッキングを開始しようとしました:

procedure TfrmEnableVIPMode.edAccountNumberKeyPress(Sender: TObject; var Key: Char);
begin
   case Key of
   #09:
      begin
         //Snip - Stuff i want to do

         { 
            The DLGC_WANTTAB technique broke Windows focus change. 
            Keep throwing in hacks until it's no longer obviously broken
         }
         //Perform(CM_DialogKey, VK_TAB, 0); //doesn't work
         Self.ActiveControl := Self.FindNextControl(edAccountNumber, True, True, False);
      end;
   end;
end;

上記のコードは機能します - ユーザーがTabキーを押した場合。しかし、Raymond Chen が 6 年前に指摘したように、コードは壊れています。

このアプローチには多くの問題があります。このコードがダイアログ ボックスに適切にフォーカスを設定できない方法、ネストされたダイアログを考慮に入れていない方法、Shift+Tab ナビゲーション キーの処理に失敗した方法など、細かい部分を掘り下げるのにかなりの時間を費やすことができます。

私の場合、私はShift+を壊しTabました。そして、誰が他に何を知っていますか。


だから、私の質問:

エディットボックスでTABキー押下を受け取るには?

私はそれらを食べたくありません。ユーザーがキーを押したことを知りTabたいだけです。

ボーナスおしゃべり

4

2 に答える 2

7

CN_KEYDOWNメッセージを処理できます。

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
   case Message.Msg of
   CN_KEYDOWN:
      if TWMKey(Message).CharCode = VK_TAB then
         ....
   end;
   FOldAccountNumberWindowProc(Message);
end;


編集をサブクラス化せずに、フォーム レベルでキーダウン メッセージを検出することもできます。

procedure TfrmEnableVIPMode.CMDialogKey(var Message: TCMDialogKey);
begin
  if (Message.CharCode = VK_TAB) and (ActiveControl = edAccountNumber) then
    ...

  inherited;
end;
于 2013-07-23T18:21:04.653 に答える
5

最初に前の WndProc を呼び出して、 Message.Result がTEditネイティブに必要なキー コードの既定値を取得しDLGC_WANTTAB、その結果にフラグを追加する必要があります。次に例を示します。

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage);
begin
  FOldAccountNumberWindowProc(Message);
  if Message.Msg = WM_GETDLGCODE then
    Message.Result := Message.Result or DLGC_WANTTAB;
end;
于 2013-07-23T19:44:57.117 に答える