在自定义控件中使用TNotifyEvent时无法检测按键

时间:2014-10-20 18:03:07

标签: delphi

我有一个源自TCustomListBox的自定义控件,我试图覆盖组件源中的OnKeyDown方法。

我遇到的问题是当使用我的组件时,我无法检测到已按下了哪个键。参数var Key: Word;似乎已经变得多余,所以我不确定我是否以正确的方式执行此操作,这可能解释了我的问题。

这是一个精简的源代码示例:

type
  TMyListBox = class(TCustomListBox)
  private
    FOnClick: TNotifyEvent;
    FOnKeyDown: TNotifyEvent;
    FOnMouseDown: TNotifyEvent;
  protected
    procedure Click; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnClick: TNotifyEvent read FOnClick write FOnClick;
    property OnKeyDown: TNotifyEvent read FOnKeyDown write FOnKeyDown;
    property OnMouseDown: TNotifyEvent read FOnMouseDown write FOnMouseDown;
  end;

implementation

constructor TMyListBox.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);

  OnClick := FOnClick;
  OnKeyDown := FOnKeyDown;
  OnMouseDown := FOnMouseDown;
end;

destructor TMyListBox.Destroy;
begin
  inherited Destroy;
end;

procedure TMyListBox.Click();
begin
  inherited;

  // do something

  if Assigned(FOnClick) then
    FOnClick(Self);
end;

procedure TMyListBox.KeyDown(var Key: Word; Shift: TShiftState);
begin
  inherited;

  // do something

  if Assigned(FOnKeyDown) then
    FOnKeyDown(Self);
end;

procedure TMyListBox.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
  inherited;

  // do something

  if Assigned(FOnMouseDown) then
    FOnMouseDown(Self);
end;

在常规项目中尝试我的组件时:

procedure TForm1.MyListBox1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = VK_DELETE then
  begin
    ShowMessage('test'); // never triggers
  end;
end;

我认为这可能与我如何压倒事件有关?列表框keydown的标准声明如下所示:

procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  //
end;

不同之处在于Sender参数,但我不能在组件源中使用它。

所以我想我想知道为什么我无法检测到按下的键,以及我是否应该以不同/更好的方式覆盖这些方法?

感谢。

1 个答案:

答案 0 :(得分:4)

OnKeyDownOnKeyUpOnKeyPress不是TNotifyEvents

OnKeyDownOnKeyUpTKeyEventOnKeyPressTKeyPressEvent

TNotifyEvent定义为

type
  TNotifyEvent = procedure (Sender: TObject) of object;

TKeyEventTKeyPressEvent的定义如下:

type
  TKeyEvent = procedure(Sender: TObject; var Key: Word;
    Shift: TShiftState) of object;
  TKeyPressEvent = procedure(Sender: TObject; var Key: Char) of object;

因此,如果您将FOnKeyDown声明为TNotifyEvent类型,则它可以接受的唯一参数是Sender: TObject。如果您希望它接受与TKeyEvent相同的参数,请将其声明为TKeyEvent。这同样适用于TMouseEventOnClick

或者,更好的是,只是将它们宣传为从祖先发布,因为它们已在TCustomListBox中声明为受保护:

type
  TMyListBox = class(TCustomListBox)
  protected
    procedure Click; override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property OnClick;
    property OnKeyDown;
    property OnMouseDown;
  end;
将自动为您提供

Sender;它是触发事件的组件。因此,在OnClick的{​​{1}}处理程序中,TButton将是单击的按钮。您无论是否收到它都没有任何选择; VCL会这样做。您可以选择不使用它,但无论您是否愿意,都可以获得它(并且必须声明您的程序是接收它)。