我已经在应用程序的主窗口中添加了一个鼠标滚轮处理程序,它似乎可行,但不是我期望从MSDN在线文档中获得的方式。
根据MSDN帮助,结果应设置为零以指示消息已被处理,但如果我这样做,则例程被调用两次。设置为非零值(在我的情况下为-1)结果只会被调用一次。
以下是一些说明问题的测试代码:
unit Mouse_Wheel_Testing;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls;
type
TForm1 = class(TForm)
Debug: TEdit;
procedure MouseWheelHandler(var Message: TMessage); override;
procedure FormCreate(Sender: TObject);
private
Call_Count: integer;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.FormCreate(Sender: TObject);
begin
Call_Count := 0;
Debug.Text := IntToStr(Call_Count);
end;
procedure TForm1.MouseWheelHandler(var Message: TMessage);
begin
inc(Call_Count);
Debug.Text := IntToStr(Call_Count);
Message.Result := -1;
end;
end.
答案 0 :(得分:3)
从最初的问题和以下评论来看,这个问题分为两部分:
MouseWheelHandler
被调用两次,OnMouseWheel
从未调用,具体取决于表单上的控件?对于第一部分,VCL代码假定Message.Result <> 0
表示已处理的消息。在测试中,您将Message.Result
设置为-1,因此会进行处理。正如Sertac Akyuz所言,这可能不是MSDN所定义的,而是VCL中的设计决策。
第二部分有两个基本原则。首先是WM_MOUSEWHEEL
,系统生成的消息。其次,CM_MOUSEWHEEL
,德尔福自己的 C ontrol M 消息内部分发。
MouseWheelHandler
处理WM_MOUSEWHEEL
OnMouseWheel
(并且取决于结果和轮次增量OnMouseWheelUp
/ OnMouseWheelDown
)针对CM_MOUSEWHEEL
滚动鼠标滚轮让Windows生成一个WM_SCROLLWHEEL
,它在焦点窗口控件的WndProc
中收到。在这种情况下,这可能是TForm
,很可能是TEdit
,因为它只是可调焦控件。此消息将被分派到处理程序MouseWheelHandler
。 TControl.MouseWheelHandler
会尝试找到它所在的ParentForm并调用TForm.MouseWheelHandler
,第一次进入您的程序。这里 - 通常 - Delphi将Perform
CM_MOUSEWHEEL
表单的焦点控件。但是,您重写的程序不会调用inherited
并禁用此。如果邮件仍然未处理,它将向上传播到父链,表格MouseWheelHandler
第二次被调用,第二次进入您的程序。
如果生成CM_MOUSEWHEEL
条消息,则会将其分派到TControl.CMMouseWheel
。此处,根据DoMouseWheel
函数的结果,CM_MOUSEWHEEL
结果设置为1或者Parent
控件,Parent
上会执行相同的消息。
TStringGrid
例如{}将处理MouseWheel事件。 CM_MOUSEWHEEL
不会传递给父级,也不会传递给表单的滚轮事件。