Reputation:
I have a custom control derived from TCustomListBox
and I am trying to override the OnKeyDown
method within my components source.
The problem I have run into is when using my component I cannot detect what key has been pressed. The parameter var Key: Word;
appears to have become redundant, so I am not sure if I am doing this the correct way or not which might explain my problem.
Here is a stripped down source example:
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;
When trying my component in a regular project:
procedure TForm1.MyListBox1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
if Key = VK_DELETE then
begin
ShowMessage('test'); // never triggers
end;
end;
I think it may be something to do with how I am overriding the event? The standard declaration for a listbox keydown looks like this:
procedure TForm1.ListBox1KeyDown(Sender: TObject; var Key: Word;
Shift: TShiftState);
begin
//
end;
The difference is the Sender
parameter but I dont and cant use that in my component source.
So I guess I want to know why I cannot detect the key pressed, and whether I should be overriding the methods in a different/better way?
Thanks.
Upvotes: 0
Views: 1463
Reputation: 125757
OnKeyDown
, OnKeyUp
, and OnKeyPress
are not TNotifyEvents
.
OnKeyDown
and OnKeyUp
are TKeyEvent
, and OnKeyPress
is a TKeyPressEvent
.
TNotifyEvent
is defined as
type
TNotifyEvent = procedure (Sender: TObject) of object;
TKeyEvent
and TKeyPressEvent
are defined as follows:
type
TKeyEvent = procedure(Sender: TObject; var Key: Word;
Shift: TShiftState) of object;
TKeyPressEvent = procedure(Sender: TObject; var Key: Char) of object;
So if you declare FOnKeyDown
as type TNotifyEvent
, the only parameter it can accept is Sender: TObject
. If you want it to accept the same parameters as TKeyEvent
, then declare it as TKeyEvent
. The same applies to TMouseEvent
and OnClick
.
Or, better yet, just promote them to published from the ancestor, as they're already declared as protected in 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
will automatically be provided for you; it's the component that triggered the event. So in an OnClick
handler for a TButton
, Sender
will be the button that was clicked. You don't have any choice whether to receive it or not; the VCL will do so. You can choose not to use it, but you're going to get it (and have to declare your procedure as receiving it) whether you want to or not.
Upvotes: 4