2013-07-23 5 views
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; 

을 그리고 (내가 희망으로) 내가 지금 이벤트 의 키를받을 수 있지만 지금은 왼쪽을 누르면 또는 오른쪽 커서 키를 사용하면 탭 순서에서 이전 또는 다음 컨트롤로 포커스가 이동합니다.

탭 키 을 눌러 이벤트를 수신 할 수있는 올바른 방법은 무엇입니까?

내가 MSDN 설명서를 말한다 일을 시도

보너스 읽기 :

의 wParam
문제이 통지에 윈도우를 묻는 메시지가 사용자가 누른 가상 키. 처리기는이 키를 선택적으로 처리해야합니다. 예를 들어 처리기가 VK_RETURN을 수락하고 처리하지만 소유자 창에 대리자 VK_TAB을 위임 할 수 있습니다. 값 목록은 가상 키 코드를 참조하십시오.

lParam MSG 구조체에 대한 포인터입니다 (시스템에서 쿼리를 수행 할 경우 인 경우 NULL).

그러나 wParamwParam은 모두 0입니다.

업데이트 두

는 내가 같은 bug as this answer을 실현 :

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; 

그 원래 코드가 잘못된 이유를 설명하는 데 도움이됩니다. DLGC_WANTTABMessage.Result을 설정하는 것은 잘못된 것입니다 :

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

Message.Resultbitwise or 플래그 DLGC_WANTTAB 시도도 잘못, Message.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; 

내가 먼저 전화를해야합니다 원래 창 절차, Windows 'EDIT 컨트롤을 Message.Result의 올바른 값을 설정하십시오.,

그것이 싶은 생각하는지 행동 원본 제어를 요구 한 후 :

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

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

는 레이몬드 첸의 블로그 항목 및 추가 중점을 의역 필요 : 그런 다음 내가 DLGC_WANTTAB 결합 비트 단위 수 DLGC_WANTTAB 플래그를 설정합니다.

이렇게 좋습니다. 커서 키는 계속 포커스를 이동하는 대신 편집 컨트롤의 텍스트를 탐색하며 Tab 키에 대해 OnKeyPress (및 OnKeyDownOnKeyUp) 이벤트를받습니다.

나머지 문제는 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; 

위의 코드는 작동합니다 - 사용자가 키를 누를 경우. 그러나 레이몬드 첸 (Raymond Chen)이 6 년 전에 메모 한 바에 따르면 코드가 깨졌습니다.

이 접근 방식에는 많은 문제가 있습니다. 이 코드가 대화 상자에서 포커스를 올바르게 설정하지 못하는 방법, 중첩 대화 상자를 고려하지 않는 방법, Shift + Tab 탐색 키를 처리하지 못하는 방법

내 경우에 깨 졌어요 시프트 + 입니다. 그리고 그 밖의 무엇을 알지.


그래서, 내 질문은 :

어떻게 편집 상자에 TAB 키 누름을받을 수? 그들이 먹을

은 내가 난 그냥 에 사용자가 키를 누르면을 알고 싶어하지 않습니다.에 메시지를 키를 감지 할 수도 있습니다

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


:

보너스, 공격을

+0

['this post'] (http://stackoverflow.com/q/2363456/960757)에서 영감을 얻을 수 있습니다. – TLama

+0

@TLama 내가 사용하고있는 접근 방법에서 (공통적 인) 버그를 찾는데 도움이되었습니다. 나는 완전히 잘못된 접근법을 사용하고 있을지 모르지만 적어도 버그가있는 잘못된 접근법을 고쳤다. –

+1

먼저 "편집 컨트롤이 포커스를 이동하는 대신 Tab 키를 가져 오도록"라고 말한 다음 "편집 컨트롤이 포커스를 이동하는 대신 Tab 키를 가져옵니다!"라고 불평합니다. 어느 쪽을 원하니? –

답변

7

당신은 CN_KEYDOWN 메시지를 처리 ​​할 수 ​​있습니다 에프 ORM 수준, 편집을 서브 클래 싱하지 않고 :

당신은 Message.Result이 기본적으로 원하는 TEdit 키 코드의 기본 값을 가져옵니다 그래서 그 결과에 DLGC_WANTTAB 플래그를 추가, 먼저 이전의 WndProc를 호출 할 필요가
procedure TfrmEnableVIPMode.CMDialogKey(var Message: TCMDialogKey); 
begin 
    if (Message.CharCode = VK_TAB) and (ActiveControl = edAccountNumber) then 
    ... 

    inherited; 
end; 
3

, 예 :

procedure TfrmEnableVIPMode.AccountNumberWindowProc(var Message: TMessage); 
begin 
    FOldAccountNumberWindowProc(Message); 
    if Message.Msg = WM_GETDLGCODE then 
    Message.Result := Message.Result or DLGC_WANTTAB; 
end; 
관련 문제