2013-01-15 9 views
8

私のTComponentには、キーイベントを聞き取り、ESCの鍵を傍受し、それを私のコンポーネントで処理し、キーストロークを消費/「食べる」ようにして、所有者のフォームがそれを処理しないようにしますその段階でちょうど開始するときTDragObjectのようにドラッグし、ESCを押して、それをキャンセルします。私のTComponentはどのようにしてESC鍵を傍受し、それを処理できますか?

問題はTDragObjectにはAllocateHWndがあり、オーナーフォームでCN_KEYDOWNと通知されています。しかし、誰も私のコンポーネントに通知しません。

フォームのWindowProcを自分で置き換える必要がありますか?はいの場合は、どのように正しく "本で"それを行うには話す?


ただ、100%明確にするために:

TMyComponent = class(TComponent) 

私は小さなテストを作り、動作しているようです:

TMyComponent = class(TComponent) 
    private 
    FOldWindowProc: TWndMethod; 
    FParentForm: TCustomForm; 
    procedure FormWindowProc(var Message: TMessage); 
    public 
    constructor Create(AOwner: TComponent); override; 
    destructor Destroy; override;  
end; 

... 

constructor TMyComponent.Create(AOwner: TComponent); 
begin 
    if not (AOwner is TWinControl) then 
    raise Exception.Create('TMyComponent.Create: Owner must be a TWinControl'); 
    inherited Create(AOwner); 
    // hook parent form 
    FParentForm := GetParentForm(TWinControl(Owner)); 
    if Assigned(FParentForm) then 
    begin 
    FOldWindowProc := FParentForm.WindowProc; 
    FParentForm.WindowProc := FormWindowProc; 
    end; 
end; 

destructor TMyComponent.Destroy; 
begin 
    // unhook parent form 
    if Assigned(FParentForm) then 
    FParentForm.WindowProc := FOldWindowProc; 
    inherited; 
end; 

procedure TMyComponent.FormWindowProc(var Message: TMessage); 
begin 
    FOldWindowProc(Message); 
    if Message.Msg = CM_CHILDKEY then // CM_CHILDKEY -> CM_DIALOGKEY -> CM_DIALOGCHAR 
    begin 
    OutputDebugString('CM_CHILDKEY'); 
    if Message.WParam = VK_ESCAPE then 
    begin 
     Beep; 
     // do my stuff... 
     Message.Result := 1; // consume keystroke 
    end; 
    end; 
end; 

これがある場合、私は思ったんだけど右/唯一のアプローチ。

+0

ドラッグすると、新しいモーダルループが発生します。それはあなたのための選択肢ではありません。あなたがホストからの協力なしにこれをきれいに行う方法を理解することは難しいです。 –

+2

@DavidHeffernan、OPは「TDragObjectのように」と言っていますが、これは単なる例であり、私はOPがESCキーを望んでいると思います。 ESCはダイアログキーです。私はちょうどコード/ API /ウィンドウのメッセージを今すぐルックアップするために必要な1分を持っていない。 –

+0

@Cosminドラッグ操作のモーダルループは、キューを所有し、ポンピングします。キープレスを手に入れることができます。しかし、フォーム上のコンポーネントにはその贅沢はありません。あなたはどのようにアプリケーションのメッセージループの中に入ることを提案しますか? –

答えて

4

TApplicationEventsオブジェクトをコンポーネント内に作成し、そのOnMessageイベントを使用して、キーストロークなどのメインスレッドメッセージキューからのメッセージを、VCLの残りの部分を処理する前に調べることがあります。

+1

コンポーネントは現実的にそれを行うことができますか?アプリがOnMessageを割り当てたらどうなりますか?それは紛争ではありませんか? –

+3

'TApplicationEvents'はマルチキャストクラスとして設計されています。複数のインスタンスが同じイベントを受け取ります。 IOWでは、単一のメッセージが待ち行列に到着すると、割り当てられたすべての 'TApplicationEvents.OnMessage'ハンドラは、誰もが' TApplicationEvents'を使用している場合には、そのダブを取得します。誰かが 'TApplication.OnMessage'を直接使用すると、' TApplicationEvents.OnMessage'が中断する可能性があります。逆も同様です。それは完璧なシステムではありませんが、何よりも優れています。 –

+1

複数の 'TApplicationEvents'コンポーネントからの' OnMessage'イベントは、それらのコンポーネントが作成されたときの逆の順序で起動されます。 – NGLN

関連する問題