2013-01-15 55 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是一個對話框鍵。我現在只有1分鐘沒有查找代碼/ API/windows消息。 –

+0

@Cosmin拖動操作的模態循環擁有並泵送隊列。所以可以抓住按鍵。但是一個表單上的組件並不具備這種奢侈。你打算如何進入應用程序的消息循環? –

回答

4

一種方法可能是在組件內部創建一個對象TApplicationEvents,然後使用它的OnMessage事件在VCL的其餘部分處理它們之前,查看主線程消息隊列中的消息,例如按鍵。

+1

組件可以逼真地做到嗎?如果應用分配了OnMessage,該怎麼辦?這不是衝突嗎? –

+3

'TApplicationEvents'被設計爲一個多播類。多個實例接收相同的事件。 IOW,當單個消息到達隊列中時,如果每個人都使用TApplicationEvents,則所有分配的TApplicationEvents.OnMessage處理程序都會獲得批處理。如果有人直接使用「TApplication.OnMessage」,則「TApplicationEvents.OnMessage」可能會中斷,反之亦然。這不是一個完美的系統,但總比沒有好。 –

+1

來自多個「TApplicationEvents」組件的「OnMessage」事件將以創建這些組件的相反順序觸發。 – NGLN