如何指示鼠标滚轮输入控制光标而不是聚焦?

时间:2010-02-12 10:13:48

标签: delphi mousewheel

我使用了许多滚动控件:TTreeViews,TListViews,DevExpress cxGrids和cxTreeLists等。当旋转鼠标滚轮时,无论鼠标光标处于何种控制状态,焦点控件都会收到输入。

如何将鼠标滚轮输入指向鼠标光标所在的控制? Delphi IDE在这方面非常有效。

7 个答案:

答案 0 :(得分:22)

尝试覆盖您的表单MouseWheelHandler这样的方法(我没有彻底测试过):

procedure TMyForm.MouseWheelHandler(var Message: TMessage);
var
  Control: TControl;
begin
  Control := ControlAtPos(ScreenToClient(SmallPointToPoint(TWMMouseWheel(Message).Pos)), False, True, True);
  if Assigned(Control) and (Control <> ActiveControl) then
  begin
    Message.Result := Control.Perform(CM_MOUSEWHEEL, Message.WParam, Message.LParam);
    if Message.Result = 0 then
      Control.DefaultHandler(Message);
  end
  else
    inherited MouseWheelHandler(Message);

end;

答案 1 :(得分:7)

覆盖TApplication.OnMessage事件(或创建一个 TApplicationEvents组件)并重定向WM_MOUSEWHEEL消息 事件处理程序:

procedure TMyForm.AppEventsMessage(var Msg: tagMSG;
  var Handled: Boolean);
var
  Pt: TPoint;
  C: TWinControl;
begin
  if Msg.message = WM_MOUSEWHEEL then begin
    Pt.X := SmallInt(Msg.lParam);
    Pt.Y := SmallInt(Msg.lParam shr 16);
    C := FindVCLWindow(Pt);
    if C = nil then 
      Handled := True
    else if C.Handle <> Msg.hwnd then begin
      Handled := True;
      SendMessage(C.Handle, WM_MOUSEWHEEL, Msg.wParam, Msg.lParam);
    end;
   end;
end;

这里工作正常,但你可能想要添加一些保护 如果出现意外情况,它就会重复发生。

答案 2 :(得分:2)

您可能会发现这篇文章很有用:send a scroll down message to listbox using mousewheel, but listbox doesn't have focus [1],它是用C#编写的,但转换为Delphi不应该是一个太大的问题。它使用钩子来实现想要的效果。

要找出鼠标当前所在的组件,可以使用FindVCLWindow函数,可以在本文中找到此示例:Get the Control Under the Mouse in a Delphi application [2]

[1] http://social.msdn.microsoft.com/forums/en-US/winforms/thread/ec1fbfa2-137e-49f6-b444-b634e4f44f21/
[2] http://delphi.about.com/od/delphitips2008/qt/find-vcl-window.htm

答案 3 :(得分:2)

这是我一直在使用的解决方案:

  1. amMouseWheel单元之后,将<{1}}添加到表单单元的实现部分的uses子句中:

    forms
  2. 将以下代码保存到unit MyUnit; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, // Fix and util for mouse wheel amMouseWheel; ...

    amMouseWheel.pas

答案 4 :(得分:0)

我遇到了同样的问题并用一些小黑客解决了它,但它确实有效。

我不想搞乱消息,并决定调用DoMouseWheel方法来控制我的需要。 Hack是DoMouseWheel是受保护的方法,因此无法从表单元文件访问,这就是我在表单单元中定义我的类的原因:

procedure TForm1.FormMouseWheel(Sender: TObject; Shift: TShiftState;
    WheelDelta: Integer; MousePos: TPoint; var Handled: Boolean);
var i: Integer;
    c: TControlHack;
begin
  for i:=0 to ComponentCount-1 do
    if Components[i] is TControl then begin
      c:=TControlHack(Components[i]);
      if PtInRect(c.ClientRect,c.ScreenToClient(MousePos)) then 
      begin
        Handled:=c.DoMouseWheel(shift,WheelDelta,MousePos);
        if Handled then break;
      end;
   end;
end;

然后我写了TForm1.onMouseWheel事件处理程序:

{{1}}

如您所见,它会搜索表单上的所有控件,而不仅仅是直接的孩子,并且会从父母搜索到孩子。

可以更好地(但更多代码)对孩子进行递归搜索,但上面的代码工作得很好。

要使只有一个控件响应mousewheel事件,在执行时应始终设置Handled:= true。例如,如果您在面板中有列表框,那么面板将首先执行DoMouseWheel,如果它没有处理事件,则listbox.DoMouseWheel将执行。如果鼠标光标下的控件没有处理DoMouseWheel,那么聚焦控件就会显得相当充分。

答案 5 :(得分:0)

仅适用于使用DevExpress控件

适用于XE3。它没有在其他版本上测试过。

SendMessage(LControl.Handle, AMsg.message, AMsg.WParam, AMsg.lParam);

如果您不使用DevExpress控件,则执行 - &gt; SendMessage消息

/var/www/html/myweb

答案 6 :(得分:-2)

在每个可滚动控件的OnMouseEnter事件中,添加对SetFocus的相应调用

所以对于ListBox1:

procedure TForm1.ListBox1MouseEnter(Sender: TObject);  
begin  
    ListBox1.SetFocus;  
end;  

这是否达到了预期的效果?