【问题标题】:Shift + mouse wheel horizontal scrollingShift + 鼠标滚轮水平滚动
【发布时间】:2011-12-11 07:17:05
【问题描述】:

shift + 滚轮的使用在水平滚动中相当普遍。

这两者都相当容易捕捉。我可以使用带有由 KeyDown、KeyUp 事件设置的标志的 MouseWheel 事件来跟踪按下 shift 键的时间。

但是,我如何真正触发水平滚动?我知道 WM_MOUSEHWHEEL,可以用来触发事件吗?

更新: 对于System.Windows.Form,有一个HorizontalScroll 属性,其类型为HScrollProperties。您可以操作该对象上的Value 属性来更改水平滚动条的位置。但是,到目前为止,我还没有发现可以使用该对象的任何其他控件。

【问题讨论】:

  • 好问题,我也一直想知道这个。

标签: c# .net vb.net winforms


【解决方案1】:

在您的设计器文件中,您需要手动添加 MouseWheel 事件委托。

this.richTextBox.MouseWheel += new System.Windows.Forms.MouseEventHandler(this.RichTextBox_MouseWheel);

然后,在您的代码后面,您可以添加以下内容。

private const int WM_SCROLL = 276; // Horizontal scroll 
private const int SB_LINELEFT = 0; // Scrolls one cell left 
private const int SB_LINERIGHT = 1; // Scrolls one line right

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); 

private void RichTextBox_MouseWheel(object sender, MouseEventArgs e)
{
    if (ModifierKeys == Keys.Shift)
    {
        var direction = e.Delta > 0 ? SB_LINELEFT : SB_LINERIGHT;

        SendMessage(this.richTextBox.Handle, WM_SCROLL, (IntPtr)direction, IntPtr.Zero);
    }
}

有关 const 值的更多信息,请参阅以下 SO:How do I programmatically scroll a winforms datagridview control?

更新

如果可能,请使用Alvin's solution好多了

【讨论】:

  • 这行得通,但会导致滚动只轻推滚动条,而不是像滚轮通常那样重击(是的,这是一个技术术语;))。 @Alvin Wong 的 hacky 解决方案完美运行。
  • 不,我会完全使用 Alvin 的(假设它有效)。它方式更干净,并且不使用外部方法或常量等。我强烈建议 OP 将答案更改为 Alvin 的答案。
【解决方案2】:

与 xixonia 在 VB.NET 中提供的代码相同

Private Const WM_SCROLL As Integer = 276 
Private Const SB_LINELEFT As Integer = 0 
Private Const SB_LINERIGHT As Integer = 1

<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SendMessage(hWnd As IntPtr, 
                                    wMsg As UInteger,
                                    wParam As IntPtr, 
                                    lParam As IntPtr) As Integer
End Function

Private Sub RichTextBox_MouseWheel(sender As Object, e As MouseEventArgs) Handles RichTextBox1.MouseWheel

  If ModifierKeys = Keys.Shift Then
    Dim direction = If(e.Delta > 0, SB_LINELEFT, SB_LINERIGHT)
    SendMessage(Me.RichTextBox1.Handle, WM_SCROLL, CType(direction, IntPtr), IntPtr.Zero)
  End If
End Sub

【讨论】:

    【解决方案3】:

    如果您要创建自己的源自UserControlScrollControlForm 的控件,您可以使用这个简单的解决方案:

    protected override void OnMouseWheel(MouseEventArgs e)
    {
        if (this.VScroll && (Control.ModifierKeys & Keys.Shift) == Keys.Shift)
        {
            this.VScroll = false;
            base.OnMouseWheel(e);
            this.VScroll = true;
        }
        else
        {
            base.OnMouseWheel(e);
        }
    }
    

    说明

    如果控件有AutoScroll 并且正在显示滚动条,当您滚动鼠标滚轮时,您将获得以下行为:

    1. 如果没有启用滚动条,它什么也不做。
    2. 如果只启用垂直滚动条,它会滚动垂直滚动条。
    3. 如果只启用水平滚动条,它会滚动水平滚动条。
    4. 如果同时启用垂直和水平滚动条,它会滚动垂直滚动条。

    注意到这种行为,我想出了这个 hack 来覆盖控件的OnMouseWheel,然后如果启用垂直滚动条并按住 Shift,它会在调用 @987654327 之前禁用垂直滚动条@。这将欺骗控件滚动水平滚动条(如上所示的行为 3)。

    【讨论】:

    • 我还没有测试过这个,但如果它有效,这就是要走的路。
    • @ChristopherHarris 是的,它可以在 Windows 下运行。不确定它是否可以在 Linux (Mono) 下工作(但无论如何使用 P/Invoke 肯定会失败。)不过,这个解决方案确实很 hacky。
    • 我不会说这个解决方案是 hacky。您正在根据一些外部标准更改事件的默认行为。您的代码直接反映了这一点,并且不依赖专有 dll。我想说的是 WindowsForms 类为您提供了一个 hacky、大量状态操作驱动的 api,但是您的代码在这个特定场景中以最好的方式使用它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-25
    相关资源
    最近更新 更多