Delphi Tshift Vcl.Controls和System.class中的状态

Delphi Tshift Vcl.Controls和System.class中的状态,delphi,Delphi,我正在为我的应用程序编写一个新组件,它使用鼠标事件和按键事件。鼠标事件和按键事件都需要参数类型TShiftState,尽管在引入按键事件声明后,我收到以下三种方法的错误“E2009不兼容类型:'参数列表不同'” 申报代码如下: TOnKeyDownEvent = procedure(Sender: TObject; Key : Word; Shift : TShiftState) of object; TOnKeyPressEvent = procedure(Sender: TObject; K

我正在为我的应用程序编写一个新组件,它使用鼠标事件和按键事件。鼠标事件和按键事件都需要参数类型TShiftState,尽管在引入按键事件声明后,我收到以下三种方法的错误“E2009不兼容类型:'参数列表不同'”

申报代码如下:

TOnKeyDownEvent = procedure(Sender: TObject; Key : Word; Shift : TShiftState) of object;
TOnKeyPressEvent = procedure(Sender: TObject; Key : Char) of object;
TOnKeyUpEvent = procedure(Sender: TObject; Key : Word; Shift : TShiftState) of object;

FOnKeyDownEvent     : TOnKeyDownEvent;
FOnKeyPressEvent    : TOnKeyPressEvent;
FOnKeyUpEvent       : TOnKeyUpEvent;

property OnKeyDownEvent     : TOnKeyDownEvent     read FOnKeyDownEvent write FOnKeyDownEvent;
property OnKeyPressEvent    : TOnKeyPressEvent    read FOnKeyPressEvent write FOnKeyPressEvent;
property OnKeyUpEvent       : TOnKeyUpEvent       read FOnKeyUpEvent write FOnKeyUpEvent;


procedure KeyDown(Sender: TObject; Key : Word; Shift : TShiftState);
procedure KeyPress(Sender: TObject; Key : Char);
procedure KeyUp(Sender: TObject; Key : Word; Shift : TShiftState);
Self.OnKeyDown := Self.KeyDown;
Self.OnKeyPress := Self.KeyPress;
Self.OnKeyUp := Self.KeyUp;
导致错误的代码如下所示:

TOnKeyDownEvent = procedure(Sender: TObject; Key : Word; Shift : TShiftState) of object;
TOnKeyPressEvent = procedure(Sender: TObject; Key : Char) of object;
TOnKeyUpEvent = procedure(Sender: TObject; Key : Word; Shift : TShiftState) of object;

FOnKeyDownEvent     : TOnKeyDownEvent;
FOnKeyPressEvent    : TOnKeyPressEvent;
FOnKeyUpEvent       : TOnKeyUpEvent;

property OnKeyDownEvent     : TOnKeyDownEvent     read FOnKeyDownEvent write FOnKeyDownEvent;
property OnKeyPressEvent    : TOnKeyPressEvent    read FOnKeyPressEvent write FOnKeyPressEvent;
property OnKeyUpEvent       : TOnKeyUpEvent       read FOnKeyUpEvent write FOnKeyUpEvent;


procedure KeyDown(Sender: TObject; Key : Word; Shift : TShiftState);
procedure KeyPress(Sender: TObject; Key : Char);
procedure KeyUp(Sender: TObject; Key : Word; Shift : TShiftState);
Self.OnKeyDown := Self.KeyDown;
Self.OnKeyPress := Self.KeyPress;
Self.OnKeyUp := Self.KeyUp;

有人能告诉我为什么上面的代码不起作用吗?

您缺少
参数必须是
var
参数,以便匹配
TKeyEvent
的签名,我猜您正试图将其分配给:

procedure(Sender: TObject; var Key : Word; Shift : TShiftState) of object;

这是因为事件处理程序可以更改密钥代码。

由于编译器声明的原因,您的代码无法编译。赋值右侧的值类型与左侧的属性类型不匹配,具体原因是参数列表不同

如问题所述,没有明显的原因。参数列表确实匹配。唯一可能的解释是,参数列表中使用的类型名称相同,但类型不同

如果在不同的单元中使用相同的名称声明多个类型,这是可能的。您可以通过对
uses
子句重新排序来解决问题,以确保所有代码引用相同的类型。或者通过以
UnitName.TypeName
的形式给出其全名来显式指定类型


另一个看似合理的解释是,事实并非如问题所述。例如,可能
Self.KeyDown
指的是方法
TWinControl.KeyDown
,而不是您的方法

你走错了路。不要让组件将处理程序分配给它自己的事件。现有的
Key(Down/Up/Press)
方法由
TWinControl
公开,您应该覆盖这些方法;现有的
OnKey(Down/Up/Press)
事件可以升级到
已发布的
。不要定义自己的方法和事件,请使用本机方法和事件,例如:

type
  TMyComp = class(...)
  protected
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure KeyUp(var Key: Word; Shift: TShiftState); override;
    procedure KeyPress(var Key: Char); override;
  published
    property OnKeyDown;
    property OnKeyUp;
    property OnKeyPress;
  end;

procedure TMyComp.KeyDown(var Key: Word; Shift: TShiftState);
begin
  ...
  inherited; // trigger the native OnKeyDown event
end;

procedure TMyComp.KeyUp(var Key: Word; Shift: TShiftState);
begin
  ...
  inherited; // trigger the native OnKeyUp event
end;

procedure TMyComp.KeyPress(var Key: Char);
begin
  ...
  inherited; // trigger the native OnKeyPress event
end;

鼠标事件以类似的方式工作。

在您显示的代码上下文中,什么是
Self
?另外,组件的祖先是什么?在我看来,你正在重新说明已经做了什么…@James_Hill你在哪里宣布了按键关闭程序。如果它在类声明之外,那么很明显您会遇到这样的错误。因为FOnKeyDownEvent是一种需要在对象中声明的TOnKeyDownEvent类型(请参见TOnKeyDown声明前面的对象的
)。我想你可以在你的单位里,在全球范围内宣布这个键控程序。我同意特拉玛的观点。您的祖先是什么?请提供SSCCE。问题中的代码很好。请尝试演示演示问题的代码。特拉玛:代码格式正确,我刚刚提取了相关部分。除对象过程外,第一段代码是类型,其余代码包含在对象中。第二个块在构造函数中。洛格曼:同上。All:@jpfollenius有这个问题的答案,这代表我是一个愚蠢的错误。关于公认的答案,问题中的代码是假的。这假设控件来自TWinControlI,我正在使用我正在制作的组件创建一组新事件,尽管它的代码稍微多一些,我想以类似的方式构造所有事件。我知道鼠标事件和按键事件可以通过重写来完成,但是我创建的新事件不能以这种方式完成。如果有一个强有力的理由使用重写的方法,那么我会考虑改变我的方法,但是关于可读性和一致性,我想这样做,因为有很多事件需要编写。@ DavidHeffernan:非窗口控件不能接收键盘输入。是的,假设组件是一个
TWinControl
后代。@James_-Hill:这并不否定我在回答中所说的。要处理用户输入,请使用覆盖。这就是他们在那里的目的。对于创建新的自定义事件,您仍然不会让组件将处理程序分配给自己的事件,这会阻止其他任何人分配处理程序,而且它是冗余的。如果您在实现自定义事件时遇到问题,则需要提出新问题并提供这些详细信息。我无法理解这是如何回答您提出的问题的@James,问题中哪里有var param?@DavidHeffernan问题是试图找出为什么会出现错误“E2009不兼容类型:'参数列表不同'”。我认为这是由于类和控件中存在的tshift状态,但这是因为参数'Key:Word'应该是'var-Key:Word'。我很快排除了参数列表的差异,因为当在IDE中悬停在单词上时,它表明参数列表是相同的,除了拥有TShiftState的类之外。在我的代码声明中,它说它是在System.Class中声明的,在继承的对象中,它说它来自VCL.Controls。问题代码中没有
var
参数。那么赋值运算符的任一侧如何具有
var
param,或期望具有
var
param呢。事件类型没有
var
param。指定给事件的方法没有
var
param。显然问题中的信息是错误的。@DavidHeffernan问题是我们不知道
Self
所指的是什么(请注意,所使用的属性称为
OnKeyDown
,而不是如上所述的
OnKeyDownEvent
),所以我只是猜测,因为我记得我自己把签名弄错了,并处理了那个错误