我有一个源自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
参数,但我不能在组件源中使用它。
所以我想我想知道为什么我无法检测到按下的键,以及我是否应该以不同/更好的方式覆盖这些方法?
感谢。
答案 0 :(得分:4)
OnKeyDown
,OnKeyUp
和OnKeyPress
不是TNotifyEvents
。
OnKeyDown
和OnKeyUp
为TKeyEvent
,OnKeyPress
为TKeyPressEvent
。
TNotifyEvent
定义为
type
TNotifyEvent = procedure (Sender: TObject) of object;
TKeyEvent
和TKeyPressEvent
的定义如下:
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
。这同样适用于TMouseEvent
和OnClick
。
或者,更好的是,只是将它们宣传为从祖先发布,因为它们已在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会这样做。您可以选择不使用它,但无论您是否愿意,都可以获得它(并且必须声明您的程序是接收它)。