8

私のTComponentでは、キーイベントをリッスンし、キーをインターセプトESCしてコンポーネントで処理し、キーストロークを消費/「食べる」ことで、たとえば所有者フォームがその段階でそれを処理しないようにするポイントがあります。TDragObjectドラッグを開始したときと同じように、 を押してキャンセルしESCます。

問題は、それTDragObjectAllocateHWnd所有者フォームによって通知されること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; 

これが正しい/唯一のアプローチであるかどうか疑問に思っています。

4

1 に答える 1

4

TApplicationEvents1 つの方法として、コンポーネント内にオブジェクトを作成し、そのOnMessageイベントを使用してメイン スレッドのメッセージ キューからメッセージ (キーストロークなど) を確認してから、残りの VCL がそれらを処理する方法があります。

于 2013-01-16T01:42:53.643 に答える