5

Delphi XEでは、「インスタント検索」機能を実装しようとしています。これは、Firefoxの「入力時に検索」に似ていますが、オープンソースのクリップボードエクステンダーであるDittoの同様の機能によってよりよく示されています。

同上検索インターフェース

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

UIのポイントは、ユーザーがコントロール間でタブまたはShiftキーを押しながらタブを押す必要がないことです。2つのコントロール(リストと編集ボックス)は、単一のコントロールであるかのように「感じる」必要があります。検索UIの動作は、どちらのコントロールにフォーカスがあるかによって決まることはありません。

私の最善の選択肢は、特定のキーボードイベントをリストコントロール(TcxTreeListを使用しています)から編集ボックスに転送し、いくつかのナビゲーションキーを編集ボックスからリストに転送することです。どうすればそれを達成できますか?

ノート:

  1. TcxTreeListはもちろんインクリメンタルサーチをサポートしていますが、これは私が求めているものではありません。検索はSQLiteデータベースに行き、部分文字列の一致を探します。リストには、データベースから一致するアイテムのみが表示されます。

  2. いくつかの重複があります。たとえば、両方のコントロールは通常VK_HOMEとVK_ENDを処理しますが、それは問題ありません。この場合、キーはリストに移動します。個々のキー押下を転送するか、それを受け取ったコントロールで処理するかを決定する必要があります。

編集時: 1つの明白な方法は、次のように、編集コントロールのそれぞれのKeyDown、KeyUp、およびKeyPressメソッドを呼び出すことであるように思われました。

type
  THackEdit = class( TEdit );

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

残念ながら、これは効果がありません。私の推測では、TEditは、フォーカスされていない限り、主要なイベントを処理しません。SendMessage(THackEdit(edit1).Handle、WM_KEYDOWN、Key、0)を使用しても効果はありません。

4

2 に答える 2

7

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;

追加のメッセージに介入する必要があるかもしれませんが、アイデアは得られます。

何らかの理由で新しいコントロールを派生させたり、メッセージ処理をオーバーライドしたりできない場合は、コントロールをサブクラス化することを検討できます。この質問への回答は、その方法を示しています。

于 2011-01-18T18:14:02.200 に答える
2

あなたが求めているものとは正確には異なりますが、同様の結果を得るために、次のトリックを使用します。

1 つの TEditEdit1と 1 つの TListboxがあるとしますListbox1

Listbox1 の OnEnter イベントで、フォーカスを Edit1 に渡すだけです。

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

Edit1 の OnKeyDown イベントでは、上矢印と下矢印を使用してリストボックスの項目を移動し、Enter キーを使用して選択した項目を編集ボックスに移動します。

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;
于 2011-01-18T15:47:12.877 に答える