我使用了许多滚动控件:TTreeViews,TListViews,DevExpress cxGrids和cxTreeLists等。当旋转鼠标滚轮时,无论鼠标光标处于何种控制状态,焦点控件都会收到输入。
如何将鼠标滚轮输入指向鼠标光标所在的控制? Delphi IDE在这方面非常有效。
答案 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)
这是我一直在使用的解决方案:
在 amMouseWheel
单元之后,将<{1}}添加到表单单元的实现部分的uses子句中:
forms
将以下代码保存到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;
这是否达到了预期的效果?