问题
I'm designing a form with a horizontal scroll bar docked at the bottom. I wanted to add support for side-scrolling using mouse tilt buttons and found this solution which, after a bit of tinkering, seemed to do the trick – that is, while the form only had GDI graphics drawn on its surface.
However, since then I've added some controls to the form and found that when the mouse is over any of them the tilt operation only fires once-at-a-time instead of repeatedly as it does when the mouse is over any other part of the form.
To see what I mean (if you have a mouse with tilt buttons) dock a horizontal scrollbar onto the bottom of a form, add a few other controls and paste in this code:
Public Class Form1
Const WM_MOUSEHWHEEL As Integer = &H20E
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If Me.IsDisposed OrElse m.HWnd <> Me.Handle Then Return
Select Case m.Msg
Case WM_MOUSEHWHEEL
With HScrollBar1
If CType(m.WParam, Integer) < 0 Then '______________ Left Scroll
If .Value > 0 Then .Value -= 1
Else '______________________________________________ Right Scroll
If .Value < (.Maximum - .LargeChange + 1) Then .Value += 1
End If
End With
m.Result = CType(1, IntPtr) 'Indicates the message has been handled
End Select
End Sub
Private Sub HScrollBar1_ValueChanged(sender As Object, e As System.EventArgs) Handles HScrollBar1.ValueChanged
Console.WriteLine(HScrollBar1.Value)
End Sub
End Class
You'll see that side-scrolling repeats when the mouse is over a blank part of the form, but only "one-shots" when it's over a control.
I'm guessing the solution lies somewhere in the message's .Result
value, but I'm at a loss as to what that should be. In fact I'm not even sure I'm returning a correct value anyway because the code in the original solution threw an exception to the DirectCast function so I swapped that for CType, which seemed to work okay. I've tried working it out using Spy++ but I can't see anything obvious.
Any ideas please?
UPDATE
I've noticed when I include 'Child' windows in Spy++ there are two (0x020E) messages and two return values, 1 then 0. I presume the message is being passed onto the control by the form. So I guess the question now is: can the message be prevented from being passed to the control? Or can the control's return value be intercepted and converted to 1?
回答1:
I've managed to contrive a workaround but I feel sure there must be a better method than this. What I've done is add a class for each type of control used on my form and inheriting from the control. Then I've added a WndProc procedure to each class so that 1
is always returned for WM_MOUSEHWHEEL
messages processed by these controls. For example, this is the button class:
Public Class scButton
Inherits Button
Protected Overrides Sub WndProc(ByRef m As Message)
MyBase.WndProc(m)
If Me.IsDisposed OrElse m.HWnd <> Me.Handle Then Return
If m.Msg = Win32Messages.WM_MOUSEHWHEEL Then m.Result = New IntPtr(1)
End Sub
End Class
Then it was just a matter of changing the references in the form's designer code.
As I say, I'm sure there must be a better method than this. It would be painful if you had to do it for a large number of different control classes, but in my case I just needed it for a few basic controls.
I left this open for a few days in the hope that someone would suggest a better solution but nothing has been forthcoming so I'm going to accept my own answer.
来源:https://stackoverflow.com/questions/10999659/make-mouse-tilt-horizontal-scrolling-always-repeat