2011-01-18 14 views
5

Delphi XEでは、「インスタント検索」機能を実装しようとしています。これは、Firefoxの「タイプすると検索する」と似ていますが、オープンソースのクリップボードエクステンダー、DittoキーボードのイベントをあるWindowsコントロールから別のWindowsコントロールに転送する

Ditto search interface

典型的なナビゲーションイベントを処理する項目のリストがあります。ただし、英数字キー、ナビゲーションおよび編集コマンド(右矢印または左矢印、シフト+矢印、バックスペース、削除など)は、リストの下にある編集ボックスに再ルーティングする必要があります。編集ボックスのOnChangeイベントは、リストのリフレッシュをトリガします。

UIのポイントは、ユーザーがコントロール間でタブまたはシフトタブを使用する必要がないことです。彼らは、単一のコントロールであるかのように2つのコントロール(リストと編集ボックス)「は、「感じるべき。制御する上でUIがは偶発的ではありません検索の動作がフォーカスを持っている。

それは私の最良の選択肢と思われますどのように私はそれを達成することができます。編集ボックスに(私はTcxTreeListを使用しています)、リストコントロールから前方特定のキーボードイベントにあり、そしてエディットボックスからリストへのナビゲーションキーの握りを転送する?

注:

  1. TcxTreeListはもちろんインクリメンタルサーチをサポートしていますが、これは私が後にしたものではありません。検索はSQLiteデータベースに行き、部分文字列の一致を探します。このリストには、dbの一致する項目のみが表示されます。いくつかの重なりがあります。両方のコントロールは通常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; 

は残念ながら、これは効果がありません: 1つの明らかな方法はそうのように、エディットコントロールのそれぞれのKeyDown、keyUpイベントとKeyPressイベントメソッドを呼び出すように見えました。私の推測では、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

Strangeですが、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

あなたが求めているのは正確ではありませんが、似たような結果を得るために、私は以下のトリックを使用します。

1つのTEdit と1つのTListbox Listbox1があるとします。 listbox1をフォーカス取得時のイベントに

、単にリストボックスの項目を移動し、Enterキーを使用する上下の矢印を使用して、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

ありがとう、PA。私はこのアプローチを考えており、それは可能性のままです。欠点は、TEditが常に集中していることですが、代わりにリストを集中させたいと思っています。 (Dittoはまだ何かをしています:それはリストの焦点を維持し、英数字のキー入力では編集ボックスにフォーカスを当てて*そのキーを編集に渡します。 keypress) –

関連する問題