Delphi - WM_MOUSEWHEEL双处理

时间:2017-08-13 02:26:59

标签: delphi winapi mousewheel

我已经在应用程序的主窗口中添加了一个鼠标滚轮处理程序,它似乎可行,但不是我期望从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.

1 个答案:

答案 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,因为它只是可调焦控件。此消息将被分派到处理程序MouseWheelHandlerTControl.MouseWheelHandler会尝试找到它所在的ParentForm并调用TForm.MouseWheelHandler第一次进入您的程序。这里 - 通常 - Delphi将Perform CM_MOUSEWHEEL表单的焦点控件。但是,您重写的程序不会调用inherited并禁用此。如果邮件仍然未处理,它将向上传播到父链,表格MouseWheelHandler第二次被调用,第二次进入您的程序

如果生成CM_MOUSEWHEEL条消息,则会将其分派到TControl.CMMouseWheel。此处,根据DoMouseWheel函数的结果,CM_MOUSEWHEEL结果设置为1或者Parent控件,Parent上会执行相同的消息。 TStringGrid例如{}将处理MouseWheel事件。 CM_MOUSEWHEEL不会传递给父级,也不会传递给表单的滚轮事件。