在我的TComponent中,有一点我想要听取键事件并拦截ESC键并在我的组件中处理它,消耗/“吃掉”击键,以便例如所有者表单不会处理它阶段.就像在TDragObject中开始时一样,拖动并按ESC取消它.
问题是TDragObject具有由其所有者表单通知CN_KEYDOWN的AllocateHWnd.但是没有人通知我的组件.
我需要用自己的窗体替换窗体的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;
我想知道这是否是正确/唯一的方法.
解决方法
一种方法可能是在组件内部创建TApplicationEvents对象,然后使用其OnMessage事件在其他VCL处理它们之前查看来自主线程消息队列的消息,例如击键.