Delphi-WM_鼠标滚轮双重处理
我已经在应用程序的主窗口中添加了一个鼠标滚轮处理程序,它似乎可以工作,但并不像我从MSDN在线文档中期望的那样 根据MSDN帮助,结果应设置为零,以指示消息已被处理,但如果我这样做,则例程将被调用两次。设置为非零值(在我的例子中为-1)会导致只调用一次 下面是一些说明问题的测试代码:Delphi-WM_鼠标滚轮双重处理,delphi,winapi,mousewheel,Delphi,Winapi,Mousewheel,我已经在应用程序的主窗口中添加了一个鼠标滚轮处理程序,它似乎可以工作,但并不像我从MSDN在线文档中期望的那样 根据MSDN帮助,结果应设置为零,以指示消息已被处理,但如果我这样做,则例程将被调用两次。设置为非零值(在我的例子中为-1)会导致只调用一次 下面是一些说明问题的测试代码: unit Mouse_Wheel_Testing; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Form
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
Message.Result 0
表示已处理的消息。在测试中,您将Message.Result
设置为-1,因此将对其进行处理。正如Sertac Akyuz所言,这可能不是MSDN所定义的,而是VCL中的设计决策
第二部分有两个基本原则。首先,WM_鼠标滚轮是系统生成的消息。其次,CM_鼠标轮
,德尔福自己的CcontrolM消息在内部分发
handlesmouseweelhandler
WM\u mouseweel
(并取决于结果和车轮增量OnMouseWheel
/OnMouseWheelUp
)响应OnMouseWheelDown
CM_MOUSEWHEEL
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将始终触发。有趣。