【问题标题】:TListView and mouse wheel scrollingTListView 和鼠标滚轮滚动
【发布时间】:2011-03-14 10:14:38
【问题描述】:

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

问候, 恶人

【问题讨论】:

    标签: delphi mouseevent delphi-xe


    【解决方案1】:

    这是我的代码:

    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;
    

    【讨论】:

    • 够了吗?我认为轮子消息并不总是转到光标下的窗口,它们会转到顶层窗口(Delphi 形式);所以列表视图并不总是接收它们。我知道我必须在框架中为需要轮子消息的项目进行大量消息转发。
    • @David,在我的项目中,我试图直接处理 WM_MOUSEHWHEEL,但消息没有正确流动(我有时会在框架上,有时在表单上,​​有时在两者上框架和形式)。我花了 5 分钟来弄清楚其他人面临这个问题,又花了 5 分钟来开发我的 hack。现在阅读TControl.WndProc()中的代码,我终于明白了:轮子消息不需要WM_MOUSEWHEEL(因为WM_MOUSEWHEEL等于WM_MOUSELAST)。这就是为什么(a)我并不总是收到消息,并且(b)我有时会收到两次消息。谢谢和 +1。
    • @Cosmin 这是一个非常简洁的解决方案,它突出了 Win32 设计中的一些天才之处,即相同的消息适用于任何可滚动控件。
    • @David,我认为这更像是一种 hack,以适应操作系统本身较晚引入的鼠标滚轮处理(记住每个鼠标驱动程序实现滚动但感觉合适的时代)。
    • @Cosmin 鼠标滚轮是后来发明的,正如您所说。是的,在消息轮消息不存在的早期,这是一个真正的痛苦。我的观点是 WM_VSCROLL 和 DefWindowProc 等的良好设计使我发布的解决方案成为可能。就是这样。
    猜你喜欢
    • 2011-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多