2011-01-18 3 views
5

Delphi XE에서는 Firefox의 "검색 할 때 검색"과 비슷한 "즉시 검색"기능을 구현하려고하지만 비슷한 기능으로 더 잘 설명됩니다. 오픈 소스 클립 보드 익스텐더, Ditto :하나의 Windows 컨트롤에서 다른 키보드 컨트롤로 키보드 이벤트 전달

Ditto search interface

일반적인 네비게이션 이벤트를 처리 항목의 목록이 있습니다. 그러나 탐색 및 편집 명령 (오른쪽/왼쪽 화살표, Shift + 화살표, 백 스페이스, 삭제 등)뿐만 아니라 영숫자 키는 목록 아래의 편집 상자로 경로가 변경되어야합니다. 입력란의 OnChange 이벤트는 목록 새로 고침을 트리거합니다.

UI의 요점은 사용자가 컨트롤 사이에서 탭이나 Shift-Tab을 사용할 필요가 없다는 것입니다. 두 개의 컨트롤 (목록 및 편집 상자)은 하나의 컨트롤 인 것처럼 '느낌'을 가져야합니다. 검색 UI의 동작은 어떤 컨트롤에 포커스가 있는지에 따라 이 아니야

내 최고의 옵션 인 것 같습니다. 편집 상자에 (내가 TcxTreeList을 사용하고 있습니다), 그리고 목록에 편집 상자에서 탐색 키의 소수를 전달리스트 컨트롤에서 앞으로 특정 키보드 이벤트이다. 어떻게 그것을 달성 할 수 있는가?

을 메모 :

  1. TcxTreeList는 점진적 검색을 지원하지만 이것이 내가 원하는 것입니다. 검색은 SQLite 데이터베이스로 이동하여 하위 문자열 일치를 찾습니다. 목록에는 db에서 일치하는 항목 만 표시됩니다.

  2. 일부 중복이 있습니다. 두 컨트롤 모두 VK_HOME과 VK_END를 처리하지만 괜찮습니다.이 경우 키는 목록으로 이동합니다. 각 개별 키 누르기를 전달할지 또는 수신 한 컨트롤에서 처리할지 결정해야합니다. 편집에

:

type 
    THackEdit = class(TEdit); 

procedure TMainForm.cxTreeList1KeyDown(Sender: TObject; var Key: Word; 
    Shift: TShiftState); 
begin 
    THackEdit(edit1).KeyDown(Key, Shift); 
end; 

불행하게도,이 효과가 없습니다 : 한 가지 확실한 방법은과 같이, 편집 컨트롤의 각에서 KeyDown,의 keyup 키 누르기 메소드를 호출 할 듯 . TEdit은 포커스가 맞지 않는 한 주요 이벤트를 처리하지 않습니다. SendMessage (THackEdit (edit1) .Handle, WM_KEYDOWN, Key, 0)를 사용하면 효과가 없습니다.

답변

6

VCL 컨트롤의 메시지 처리 기능을 사용하여 관련 메시지를 서로 보낼 수 있습니다. 'TcxTreeList'에 대해서는 알지 못하지만, 다음은 편집 컨트롤과 키보드 이벤트에 동시에 응답하는 메모 컨트롤에 대한 아이디어를 보여줍니다 (물론 가능할 수도 있음).

type 
    TEdit = class(stdctrls.TEdit) 
    private 
    FMsgCtrl: TWinControl; 
    FRecursing: Boolean; 
    procedure WmChar(var Msg: TWMChar); message WM_CHAR; 
    procedure WmKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; 
    procedure WmKeyUp(var Msg: TWMKeyUp); message WM_KEYUP; 
    end; 

    TMemo = class(stdctrls.TMemo) 
    private 
    FMsgCtrl: TWinControl; 
    FRecursing: Boolean; 
    procedure WmChar(var Msg: TWMChar); message WM_CHAR; 
    procedure WmKeyDown(var Msg: TWMKeyDown); message WM_KEYDOWN; 
    procedure WmKeyUp(var Msg: TWMKeyUp); message WM_KEYUP; 
    end; 

    TForm1 = class(TForm) 
    Edit1: TEdit; 
    Memo1: TMemo; 
    procedure FormCreate(Sender: TObject); 
    private 
    public 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

{ TEdit } 

procedure TEdit.WmChar(var Msg: TWMChar); 
begin 
    if not FRecursing then begin 
    inherited; 

    // Insert test here to see if the message will be forwarded 
    // exit/modify accordingly. 

    if Assigned(FMsgCtrl) then begin 
     FRecursing := True; 
     try 
     FMsgCtrl.Perform(Msg.Msg, 
         MakeWParam(Msg.CharCode, Msg.Unused), Msg.KeyData); 
     finally 
     FRecursing := False; 
     end; 
    end; 
    end; 
end; 

procedure TEdit.WmKeyDown(var Msg: TWMKeyDown); 
begin 
    // exact same contents as in the above procedure 
end; 

procedure TEdit.WmKeyUp(var Msg: TWMKeyUp); 
begin 
    // same here 
end; 

{ TMemo } 

procedure TMemo.WmChar(var Msg: TWMChar); 
begin 
    // same here 
end; 

procedure TMemo.WmKeyDown(var Msg: TWMKeyDown); 
begin 
    // same here 
end; 

procedure TMemo.WmKeyUp(var Msg: TWMKeyUp); 
begin 
    // same here 
end; 


{ TForm1 } 

procedure TForm1.FormCreate(Sender: TObject); 
begin 
    Edit1.FMsgCtrl := Memo1; 
    Memo1.FMsgCtrl := Edit1; 
end; 

추가 메시지를 개입시켜야하지만 아이디어를 얻을 수 있습니다.

새 컨트롤을 파생 시키거나 메시지 처리를 무시할 수없는 경우 컨트롤의 하위 클래스를 고려할 수 있습니다. this question에 응답하면 어떻게하는지 보여줍니다.

+0

이상하지만 TEdit의 Perform 메서드를 사용하면 아무 효과가 없습니다. 즉, 내 OP의 SendMessage 예제와 같습니다. 백 스페이스 키 (편집 컨트롤에 텍스트와 캐럿 위치가> 0 인 곳)를 보내는 것과 같은 간단한 작업도 수행합니다. edit1.Perform (WM_KEYDOWN, 8, 0); –

+1

@mood - 백 스페이스를 위해'edit1.Perform (WM_CHAR, VK_BACK, 0);을 시도하십시오. 그래서 WM_CHAR, WM_KEYDOWN, WM_KEYUP 메시지를 샘플 프로젝트에 포함 시켰습니다. –

2

당신이 원하는 것은 아니지만 비슷한 결과를 얻으려면 다음 트릭을 사용하십시오.

TEdit가 이고 TListbox가 Listbox1 인 것으로 가정합니다. 에 ListBox1의 OnEnter 이벤트에서

, 단순히 EDIT1

procedure TForm1.ListBox1Enter(Sender: TObject); 
begin 
    edit1.SetFocus; 
end; 

에 포커스를 얻을 그리고 EDIT1의 onKeyDown에 경우에, 목록 상자의 항목을 이동하려면 위쪽 화살표와 아래쪽 화살표를 사용하여 키를 입력 사용 선택한 항목을 편집 상자로 이동하십시오.

procedure TForm1.Edit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); 
var k:word; 
begin 
    if (Shift=[]) and (key=VK_DOWN) then  
    begin 
    listbox1.ItemIndex:=listbox1.ItemIndex+1; 
    key:=0;  
    end 
    else if (Shift=[]) and (key=VK_UP) then 
    begin 
    listbox1.ItemIndex:=listbox1.ItemIndex-1; 
    key:=0;  
    end 
    else if (Shift=[]) and (key=VK_RETURN) then 
    begin 
    edit1.text:=listbox1.items[listbox1.itemindex]; 
    end; 
end; 
+0

감사합니다. 나는이 접근법을 고려했으며 가능성이 남아있다. 단점은 TEdit가 항상 초점을 맞출 것이고 목록을 선호하는 편이 낫다고 생각하는 것입니다. (Ditto는 아직 다른 작업을 수행합니다. 목록에 초점을 맞추고 영숫자 키 누르기로 편집 상자에 초점을 맞추고 * 해당 키를 편집에 전달합니다. 따라서이 방법을 사용하면 앞으로 전달할 방법이 필요합니다. keypress.) –