Delphi-WM_鼠标滚轮双重处理

Delphi-WM_鼠标滚轮双重处理,delphi,winapi,mousewheel,Delphi,Winapi,Mousewheel,我已经在应用程序的主窗口中添加了一个鼠标滚轮处理程序,它似乎可以工作,但并不像我从MSDN在线文档中期望的那样 根据MSDN帮助,结果应设置为零,以指示消息已被处理,但如果我这样做,则例程将被调用两次。设置为非零值(在我的例子中为-1)会导致只调用一次 下面是一些说明问题的测试代码: unit Mouse_Wheel_Testing; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Form

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

从最初的问题和以下评论来看,该问题分为两部分:

  • 如何将消息指示为已处理
  • 为什么对消息处理程序的调用看起来如此不连贯,
    mouseweelhandler
    被调用了两次,
    onmouseweel
    根据表单上的控件从未调用过
对于第一部分,VCL代码假定
Message.Result 0
表示已处理的消息。在测试中,您将
Message.Result
设置为-1,因此将对其进行处理。正如Sertac Akyuz所言,这可能不是MSDN所定义的,而是VCL中的设计决策

第二部分有两个基本原则。首先,WM_鼠标滚轮是系统生成的消息。其次,
CM_鼠标轮
,德尔福自己的CcontrolM消息在内部分发

  • mouseweelhandler
    handles
    WM\u mouseweel
  • OnMouseWheel
    (并取决于结果和车轮增量
    OnMouseWheelUp
    /
    OnMouseWheelDown
    )响应
    CM_MOUSEWHEEL
滚动鼠标滚轮让Windows生成一个
WM_滚动滚轮
,该滚动滚轮在聚焦窗口控件的
WndProc
中接收。在本例中,这可能是
t表单
,最有可能是
TEdit
,作为唯一的可聚焦控件。此消息将被发送到处理程序
mouseweelhandler
t控制.mouseweelHandler
将尝试查找它所在的父窗体,并调用
t窗体.mouseweelHandler
过程的第一个条目。此处-通常情况下-Delphi将
在窗体的焦点控件上执行
鼠标滚轮
。但是,您被重写的过程不会调用继承的
并禁用它。如果消息仍然未处理,它将向上传播到父链,表单的
mouseweelhandler
将被再次调用,成为过程的第二个条目

如果生成了
CM\u鼠标滚轮
消息,它们将被分派到
TControl.cmmouseheel
。这里,根据
domouseheel
功能的结果,
CM_mouseheel
结果设置为1,或者存在
父控件,在
父控件上执行相同的消息。

TStringGrid
例如,将处理鼠标滚轮事件。
CM\u鼠标滚轮
将不会传递给父级,您的表单没有滚轮事件

您是否有不使用表单现有事件的特定原因:
onmouseheel
onmouseheeldown
onmouseheeldup
?是。根据我的测试,onmouseheel事件仅在表单上支持鼠标滚轮滚动的控件具有焦点时触发。如果我能确定它会一直启动,那么我很乐意使用现有的事件。因此,您希望将所有鼠标滚轮消息定向到特定窗体,即使另一窗体上的组件具有焦点,对吗?我看不出重写
mouseweelhandler()
在这方面有什么帮助。OTOH,一个
OnMessage
处理程序,用于
TApplicationEvents
这样的
过程,用于m19.ApplicationEvents1Message(var Msg:tagMSG;var Handled:Boolean);如果Msg.message=WM_鼠标滚轮,则开始Msg.hwnd:=Form19.Handle;结束
会将所有鼠标滚轮消息定向到
表单19
(在本例中),您可以使用
OnMouseWheel()
事件。谢谢Tom。出于某种原因,过度驾驶的MouseWheelhandler每次都会开火,但OnMouseWheel不会。我不知道为什么,因为我本以为他们会有类似的行为。感谢您提供有关应用程序事件处理程序的提示。如果需要的话,这给了我另一个选择。我仍然想知道为什么onmouseheel事件并不总是触发,以及为什么我在处理程序中返回的结果代码似乎与MSDN文档相反。不符合文档要求的事情总是让我紧张。我正在进步。我刚刚发现,如果我的表单上有一个组件,比如字符串网格,并且该组件具有焦点,那么表单的onmouseheel事件将不会触发,即使重写的mouseweelHandler将始终触发。有趣。