TListView和鼠标滚轮滚动

7

我在表单中有一个TListView组件。它非常长,我希望用户能够在鼠标悬停在组件上并滚动鼠标滚轮时进行滚动。我没有找到任何TListView对象的OnMouseWheel、OnMouseWheelDown或OnMouseWheelUp事件。我该如何做呢?

敬礼, evilone

1个回答

9
这是我用来实现此功能的代码:
type
  TMyListView = class(TListView)
  protected
    function DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean; override;
    function DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean; override;
  end;

type    
  TMouseWheelDirection = (mwdUp, mwdDown);

function GenericMouseWheel(Handle: HWND; Shift: TShiftState; WheelDirection: TMouseWheelDirection): Boolean;
var
  i, ScrollCount, Direction: Integer;
  Paging: Boolean;
begin
  Result := ModifierKeyState(Shift)=[];//only respond to un-modified wheel actions
  if Result then begin
    Paging := DWORD(Mouse.WheelScrollLines)=WHEEL_PAGESCROLL;
    ScrollCount := Mouse.WheelScrollLines;
    case WheelDirection of
    mwdUp:
      if Paging then begin
        Direction := SB_PAGEUP;
        ScrollCount := 1;
      end else begin
        Direction := SB_LINEUP;
      end;
    mwdDown:
      if Paging then begin
        Direction := SB_PAGEDOWN;
        ScrollCount := 1;
      end else begin
        Direction := SB_LINEDOWN;
      end;
    end;
    for i := 1 to ScrollCount do begin
      SendMessage(Handle, WM_VSCROLL, Direction, 0);
    end;
  end;
end;

function TMyListView.DoMouseWheelDown(Shift: TShiftState; MousePos: TPoint): Boolean;
begin
  //don't call inherited
  Result := GenericMouseWheel(Handle, Shift, mwdDown);
end;

function TMyListView.DoMouseWheelUp(Shift: TShiftState; MousePos: TPoint): Boolean;
begin
  //don't call inherited
  Result := GenericMouseWheel(Handle, Shift, mwdUp);
end;
GenericMouseWheel 很实用,适用于任何带有垂直滚动条的控件。我将其用于树形视图、列表视图、列表框、备忘录、富文本编辑等等。
您可能会错过我的 ModifierKeyState 程序,但您可以替换自己的方法来检查鼠标滚轮事件是否被修改。原因是,例如,CTRL + 鼠标滚轮代表缩放而不是滚动。
就像这样,只供参考:
type
  TModifierKey = ssShift..ssCtrl;
  TModifierKeyState = set of TModifierKey;

function ModifierKeyState(Shift: TShiftState): TModifierKeyState;
const
  AllModifierKeys = [low(TModifierKey)..high(TModifierKey)];
begin
  Result := AllModifierKeys*Shift;
end;

1
够了吗?我认为滚轮消息并不总是发送到光标下的窗口,而是发送到顶层窗口(Delphi表单);所以列表视图并不总是接收到它们。我知道我必须为需要在框架中使用滚轮消息的项目进行大量的消息转发。 - Cosmin Prund
1
@David,我的项目中我试图直接处理WM_MOUSEHWHEEL消息,但是消息没有正确地流动(有时我会在框架上收到它,有时在表单上,有时在框架和表单上都会收到)。花了我5分钟的时间才发现其他人也面临这个问题,并花了另外5分钟开发我的hack。现在通过阅读TControl.WndProc()中的代码,我终于弄清楚了:滚轮消息不一定是WM_MOUSEWHEEL(因为WM_MOUSEWHEEL等于WM_MOUSELAST)。这就是为什么(a)我并不总是收到消息,(b)有时我会收到两次消息。谢谢并点赞。 - Cosmin Prund
@Cosmin 无论是在哪种控件类型中,滚动消息都可以正常工作,这一点从Windows 1.0开始就已经存在了。DefWindowProc提供了实现继承。考虑到它是在1985年发布的,这个设计相当周全。 - David Heffernan
2
@Cosmin 鼠标滚轮是后来发明的,正如您所说。在早期消息轮中不存在时,这确实是个大问题。我的观点是:WM_VSCROLL和DefWindowProc等的良好设计使得我发布的解决方案成为可能。就这些。 - David Heffernan
@David,我试图指出一个不同的问题,因为那是让我陷入麻烦的原因。当然,WM_VSCROLL实现得很好,但WM_MOUSEHWHEEL的实现并不同样出色(或者我没有正确理解它)。你的解决方案之所以有效,不仅仅是因为WM_VSCROLL,还因为DelphiTControl.WndProc中为奇怪的WM_MOUSEWHEEL实现了一个好的hack。 - Cosmin Prund
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接