Can I alter the mouse event evaluation order?
-
Tuesday, August 07, 2012 3:22 PM
Hello,
I need to handle 2 events:MouseDown and MouseMove for the same object.
My research (http://msdn.microsoft.com/en-us/library/system.windows.forms.control.mousedown.aspx) shows that MouseMove events are handled before MouseDown events.
My problem is that the MouseDown event is not being triggered when I right-click on the Mouse (I am running debug with a breakpoint at the MouseDown subroutine). I suspect that it is challenging to click the mouse without moving it and moving takes precedence.
If I disable the MouseMove event (by commenting out the MouseMove code or the MouseMove Handles clause) the MouseDown event is triggered. So the code is OK.
Is it possible to alter the mouse event evaluation order to get the MouseDown event to evaluate before the MouseMove event? Any other ideas?
Thanks.
All Replies
-
Tuesday, August 07, 2012 4:38 PM
No, it should not be possible to change the order that the events occur without creatig an inherited control and spending lots of time to explore the event sequencing. These are preset in the .NET library code.
I have doubts that the MouseDown event is never being raised when the mouse is moving. Can you confirm that you are not hitting a breakpoint in your MouseMove handler which would then not allow you to see it continue to the MouseDown event? In other words, this sounds like a debugging issue, which is not a good reason to go messing around with the event sequencing. Does this sound right to you?
For instance, if I take new form in a new project and use the following code behind for the form I can trap the down event while moving (be sure your Output window is pinned open to see the debug lines). How does this code differ from yours in terms of functionality?
Public Class Form1 Private Sub Form1_MouseDown(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown Debug.WriteLine(e.Button.ToString & " DOWN") End Sub Private Sub Form1_MouseMove(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove Debug.WriteLine("m") End Sub End Class -
Tuesday, August 07, 2012 4:56 PM
"...shows that MouseMove events are handled before MouseDown events."
It depends on what occurs first. You can click the button before moving the mouse before clicking the button before moving the mouse. The order mentioned in the link only means that you first must move the pointer into the bounds of the control before clicking on it, but that's logical. While the pointer is inside the bounds, the events can occur in any order, and if the control captures the mouse, the move event can also occur if the pointer is outside the bounds.
Which control are you referring to? Related to a Form I can not reproduce the problem.
Armin
-
Tuesday, August 07, 2012 8:24 PMMouseMove and MouseDown aren't really ordered. MouseMove events occur repeatedly anythime the mouse is over a control irrespective of the state of the mouse buttons. If the MouseDown event doesn't fire when you wish it would, your code is the culprit. You're probably blocking the UI thread with code in the MouseMove event.
-
Tuesday, August 07, 2012 9:00 PM
Hello Armin and Dig-Boy,
I do not believe that MouseDown is being raised while the mouse is being moved either.
I have been running in debug with breakpoints at the MouseDown subroutine and the MouseMove subroutines. If I comment the MouseMove routine out, then the MouseDown routine works as desired, otherwise it does not work.
While debugging, with a breakpoint on the MouseDown sub statement, I push pf5 to continue and it keeps stopping on the MouseDown breakpoint. i.e. it never goes back to the screen. This is with the mouse just sitting there.
I have tried holding the mouse up, so that no motion is detected while clicking the right button. MouseDown is not raised.
The MouseDown routine is very simple ... less than 20 lines including 3 Dim statements ... and it is self-contained, there are no branches, etc.
The control that I am working with is a label. I am clicking the right mouse button while doing my best to not move the mouse button.
As an added note, this code is an upgrade from VB6. The VB6 code does the MouseDown and MouseMove as desired. MouseDown works while the mouse is in motion. I am running a deployed version of the VB6, while I am running in debug mode in the .net.
I have put together a very simple test and am getting odd results. I am going to give it up for today and revisit it tomorrow and post my findings.
Thanks for your help! Gary
- Edited by GPfromSC Tuesday, August 07, 2012 9:02 PM
-
Tuesday, August 07, 2012 9:16 PM
Hi JohnWein,
Are you sure that MouseDown and MouseMove are not ordered?
The Microsoft website says the following: Mouse events occur in the following order:
-
MouseHover / MouseDown / MouseWheel
Am I reading this wrong?
-
Tuesday, August 07, 2012 9:17 PM
"I have tried holding the mouse up, so that no motion is detected while clicking the right button. MouseDown is not raised."
"MouseMove events occur repeatedly anythime the mouse is over a control irrespective of the state of the mouse buttons."
The mouse doesn't have to move for the MouseMove event to fire. It fires with or without movement when the mouse is over a control.
Only code that blocks the UI thread can prevent other code from executing. Remove your code from the MouseMove event and click a mouse button. Does the MouseDown event fire?
-
Tuesday, August 07, 2012 9:22 PM
Hi JohnWein,
Are you sure that MouseDown and MouseMove are not ordered?
The Microsoft website says the following: Mouse events occur in the following order:
-
MouseHover / MouseDown / MouseWheel
Am I reading this wrong?
Would you really expect MouseMove to only occur one time? It occurs repeatedly between MouseEnter and MouseLeave. -
Tuesday, August 07, 2012 9:44 PM
- "I do not believe that MouseDown is being raised while the mouse is being moved either."
How do you define "while the mouse is being moved"? The movement of the mouse is not a process that takes x seconds without any interruption. Instead, a movement is recognized by receiving events caused by mouse IRQs at a rate of usually 125 to 1000 Hz. Between these events, there's plenty of time for MouseDown events. So it's less a matter of believing as the code shows that it's possible. However, we don't know your code exactly.
Similar to Dig-Boy's code you can try this after putting a Listbox on the Form:
Public Class Form1 Dim watch As Stopwatch = Stopwatch.StartNew Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs) MyBase.OnMouseMove(e) Log("OnMouseMove") End Sub Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs) MyBase.OnMouseDown(e) Log("OnMouseDown " & e.Button.ToString) End Sub Sub Log(ByVal Text As String) ListBox1.Items.Add(watch.Elapsed.TotalSeconds.ToString("0.000 000") & " " & Text)
ListBox1.SelectedIndex = ListBox1.Items.Count - 1 End Sub End Class
The output while moving the mouse and almost simultaneously pressing both buttons is...:
Doing the same with a Label's events doesn't behave differently.
The way you've described debugging is confusing me. Excuse the question, but have you also tried without setting breakpoints? As soon as you continue (F5) you get the next mousemove event as long as the window is under the cursor, but that's normal. So you're in break mode again. Hence you do not have the time to click on anything because the process is always interrupted. If you comment out the MouseMove event, there's no breakpoint, and consequently you now have the chance to click the mouse buttons.
- "I have tried holding the mouse up, so that no motion is detected while clicking the right button. MouseDown is not raised."
Now MouseDown is not even raised if you do not move the mouse? I thought it's only not raised if you do move it. I'm confused.
Can you show us these 20 lines in MouseDown? Maybe also the code in MouseMove?
- "I am running a deployed version of the VB6, while I am running in debug mode in the .net. "
In .Net, the debugee (your tested process) is not running in the same process as the VB6 IDE because it's not interpreted code anymore. So in VB.Net, it shouldn't matter if a debugger is attached or not. I assume you are not referring to the configuration names "Debug" and "Release" (which also shouldn't make the difference in this case).
I have the faint suspicion Application.DoEvents is used in your code. Is it?
Armin
-
Tuesday, August 07, 2012 9:46 PM
As I said: "The order mentioned in the link only means that you first must move the pointer into the bounds of the control before clicking on it, but that's logical." After that, as I also said, the order is the order in which the events occur.Are you sure that MouseDown and MouseMove are not ordered?
The Microsoft website says the following: Mouse events occur in the following order:
-
MouseHover / MouseDown / MouseWheel
Am I reading this wrong?
Armin
-
Tuesday, August 07, 2012 9:53 PM
Pressing buttons while moving the mouse: (sorry for flashing...that's default Listbox behavior...)
EDIT: assuming your browser plays animated gifs
Armin
- Edited by Armin Zingler Tuesday, August 07, 2012 9:54 PM
- Marked As Answer by GPfromSC Wednesday, August 08, 2012 12:36 PM
-
Wednesday, August 08, 2012 1:16 PM
Hi Armin,
I missed your questions.
You had asked what kind of control I was using, that is why I mentioned that it is a label.
In one of JohnWein's replies, he says the following: "MouseMove events occur repeatedly anythime the mouse is over a control irrespective of the state of the mouse buttons." The mouse doesn't have to move for the MouseMove event to fire. It fires with or without movement when the mouse is over a control.
I can't include the code, but I can confirm that commenting out the original MouseMove subroutine and adding a new one does work correctly. The new one is only the code that VB generates plus a few simple statements to prove that it is working. The original is several hundred lines which I will be digging thru today. The problem does seem to be in the original MouseMove code.
I was not familiar with Application.DoEvents, so I looked it up. I searched the project and there are some "System.Windows.Forms.Application.DoEvents()" statements.
Thanks.
-
Wednesday, August 08, 2012 1:37 PM
- "In one of JohnWein's replies, he says the following: "MouseMove events occur repeatedly anythime the mouse is over a control irrespective of the state of the mouse buttons." The mouse doesn't have to move for the MouseMove event to fire. It fires with or without movement when the mouse is over a control."
It is correct that the mousemove event also fires even if you only press a mouse button. Yet I do not know why that is, but I also think it does not hurt, does it?
Your main issue, if I got it correctly, is that there's no mousedown event while moving the mouse, and this really seems to be an invidiual situation in your code.
Regarding DoEvents I do not know if it can cause the issue. It was a guess. My problem with DoEvents is that it is a hack because the thread already has a message loop. If the application doesn't respond, the cause for this should be removed instead of adding another message processing loop. The cause is code preventing the UI thread from doing it's work, so the solution is not to do the longer running task in the UI thread but in a different thread. That's the default protocol for doing two things simultaneously in general, so also in this situation. In opposite to VB6, this can be implemented very easily today.
Armin
- Edited by Armin Zingler Wednesday, August 08, 2012 1:38 PM
-
Wednesday, August 08, 2012 1:49 PM
"Yet I do not know why that is,..."
I guess this is because releasing the mouse button causes the mouse is not captured anymore. Consequently the mouse pointer might change (visually). I haven't found a perfect explanation, but you may want to read the last-but-one paragraph here: http://blogs.msdn.com/b/oldnewthing/archive/2003/10/01/55108.aspx
Armin
-
Wednesday, August 08, 2012 1:57 PM
OK, I found the line of code (in MouseMove) that is causing the problem.
Why ... baffles me, but there is no denying that it is the culprit. If I comment it out, MouseMove and MouseDown function perfectly. When I uncomment it, MouseDown no longer works.
I am going to put a small test so that I can show the code.
Question. To show code, do I just past it into my reply?
Thanks.
-
Wednesday, August 08, 2012 3:07 PMUse the "insert code" icon
at the top of this message editor to paste code.
Armin
-
Wednesday, August 08, 2012 6:29 PM
Public Class Form1 Private pMouseLock As Boolean Private Sub DisplayPanel_MouseDown(ByVal sender As Object, ByVal e As _ System.Windows.Forms.MouseEventArgs) Handles DisplayPanel.MouseDown Dim Button As Integer = e.Button Select Case Button ' show which button was clicked Case MouseButtons.Right ButtonLabel.Text = "Right" pMouseLock = Not (pMouseLock) MonitorLockLabel.Visible = pMouseLock Case MouseButtons.Left : ButtonLabel.Text = "Left" Case Else : ButtonLabel.Text = "?????" End Select End Sub Private Sub DisplayPanel_MouseMove(ByVal sender As Object, ByVal e As _ System.Windows.Forms.MouseEventArgs) Handles DisplayPanel.MouseMove Dim X As Single = e.X : Dim Y As Single = e.Y MouseXLabel.Text = X.ToString : MouseYLabel.Text = Y.ToString If pMouseLock Then Exit Sub 'The "FreqLabel.Left = CType(X, Integer)" line below is the problem. 'When commented, MouseDown works. 'When uncommented, MouseDown does not work FreqLabel.Left = CType(X, Integer) ' moves line left & right to follow cursor End Sub End ClassHere is the code for my test (which is pulled from the larger program). I have been able to duplicate the problem.
The line containing "FreqLabel.Left = CType(X, Integer)" is the problem. When commented out, MouseDown works; when not, MouseDown does not work.
MouseMove moves the line (label) left & right to follow the cursor. The background image will be a graph and the line will move along the graph as desired by the user. MouseDown executes code to lock the line when desired.
A little background: This code is from a VB6 application. In the VB6 DisplayPanel was a picture box, and FreqLabel was a line and there names were different to reflect VB6 naming conventions and purpose. The upgrade process changed them to a panel/label respectively.
Any ideas/thought?
Thanks.
- Marked As Answer by GPfromSC Wednesday, August 08, 2012 7:43 PM
-
Wednesday, August 08, 2012 7:19 PM
Thx for providing the code. Though I think there's too much we don't have here to be able to reproduce the problem. If I use the standard Panel and Label, everything works as expected.
You're mentioning a background image. So I'm guessing what happens: Moving the label all the time with the mouse causes repainting. This is a heavy action that can slow down message processing considerably, hence mousedown events arrive delayed. EDIT: On the other side, WM_PAINT has lowest priority, and the invalid region is accumulated, so it was really only guessing....
I've tried to reproduce this scenario by assigning a background image to the panel, andalso set CPU Frq to 800 MHz. Unfortunately it's still not reproducable, but I think in your real code there might be more going on that could be similar to what I've described.
Armin
- Edited by Armin Zingler Wednesday, August 08, 2012 7:22 PM
-
Wednesday, August 08, 2012 7:43 PM
Actually the background image doesn't affect this. I have not used it in test code.
But repainting does come into play and may be the underlying reason.
At any rate, using the code above, I can turn the problem on and off by commenting/uncommenting the 1 line.
Thanks for your time and effort. Gary.
-
Wednesday, August 08, 2012 8:29 PM
Actually the background image doesn't affect this. I have not used it in test code.
But repainting does come into play and may be the underlying reason.
At any rate, using the code above, I can turn the problem on and off by commenting/uncommenting the 1 line.
Thanks for your time and effort. Gary.
So you do not get a mousedown event while moving the mouse, right? Please excuse this question again, but I can't believe this. For testing, I also added
Debug.Print(Environment.TickCount & " " & e.Button.ToString)
at the start of the mousedown handler so that I see when it's clicked. Only using your code, I see the label changing to "left" a single time but not the consecutive times, so how are you able to make a statement about it?
BTW, all labels but FreqLabel, and the panel are on the form. FreqLabel is within the panel.
But wait: Only the label displaying "left" or "right" indeed does not update while the mouse is moved. The reason is as I said: Due to heavy screen updates, label refreshing is delayed. This doesn't mean the click event does not occur! Put debug.print into your code and you will see. (and don't set breakpoints) Again, this only happens if a Backgroundimage is assigned.
EDIT: The labels for the mouse position are not refreshed immediatelly, too, even though the mouse is moved. Have you noticed this also?EDIT #2: Which machine do you have? Set to 800 MHz, I can repro it even without a background image.
Armin
- Edited by Armin Zingler Wednesday, August 08, 2012 8:33 PM
- Edited by Armin Zingler Wednesday, August 08, 2012 8:34 PM
- Edited by Armin Zingler Wednesday, August 08, 2012 8:36 PM
-
Wednesday, August 08, 2012 9:32 PM
I guess this code works as it's supposed to. FreqLabel moves when MonitorLockLabel isn't visible.
Public Class Form1 Dim WithEvents DisplayPanel As New Panel Dim MouseXLabel As New Label Dim MouseYLabel As New Label Dim ButtonLabel As New Label Dim MonitorLockLabel As New Label Dim FreqLabel As New Label Protected Overrides Sub OnLoad(e As EventArgs) MyBase.OnLoad(e) Dim Lbls() As Label = {MouseXLabel, MouseYLabel, ButtonLabel, MonitorLockLabel, FreqLabel} Dim Clrs() As Color = {Color.Red, Color.Orange, Color.Yellow, Color.LightGreen, Color.LightBlue} For I As Integer = 0 To Lbls.Count - 1 Lbls(I).Top = I * Lbls(0).Height Lbls(I).BackColor = Clrs(I) Lbls(I).Parent = DisplayPanel Next DisplayPanel.BackColor = Color.White DisplayPanel.Parent = Me DisplayPanel.Dock = DockStyle.Fill End Sub Private pMouseLock As Boolean Private Sub DisplayPanel_MouseDown(ByVal sender As Object, ByVal e As MouseEventArgs) Handles DisplayPanel.MouseDown Dim Button As Integer = e.Button Select Case Button ' show which button was clicked Case MouseButtons.Right ButtonLabel.Text = "Right" pMouseLock = Not (pMouseLock) MonitorLockLabel.Visible = pMouseLock Case MouseButtons.Left : ButtonLabel.Text = "Left" Case Else : ButtonLabel.Text = "?????" End Select End Sub Private Sub DisplayPanel_MouseMove(ByVal sender As Object, ByVal e As MouseEventArgs) Handles DisplayPanel.MouseMove Dim X As Single = e.X : Dim Y As Single = e.Y MouseXLabel.Text = X.ToString : MouseYLabel.Text = Y.ToString If pMouseLock Then Exit Sub 'The "FreqLabel.Left = CType(X, Integer)" line below is the problem. 'When commented, MouseDown works. 'When uncommented, MouseDown does not work FreqLabel.Left = CType(X, Integer) ' moves line left & right to follow cursor End Sub End Class -
Friday, August 10, 2012 2:00 PM
Hello,
Thanks to you all, I got the answer to my questions, but I saw that there were some additional comments/questions that I thought that I should address.
In the VB6 version of the program, DisplayPanel was a Picture Box. The .net upgrade converted it to a Panel. DisplayPanel contains the image of a graph.
In the VB6 version of the program, FreqLabel was a Line that moved left and right on the graph. The .net upgrade converted it to a Label.
The purpose of the MouseMove routine is to move FreqLabel left and right (to follow the cursor) across the graph. Remember that it was a line
The purpose of the MouseDown routine was to toggle pMouseLock when the user right-clicked the mouse. The status of pMouseLock determined whether or not FreqLabel would move.
So, yes, this code works as it's supposed to, but pMouseLock is what determines whether FreqLabel moves or not. When MonitorLockLabel is visible, the user knows that the cursor (FreqLabel) is locked.
As an added note, I have found a solution. I am using the FreqLine_MouseDown routine which works great. I have retained the DisplayPanel_MouseDown code for unlocking purposes.
-
Friday, August 10, 2012 2:41 PMNice you found the solution! I admit I do not see what was the cause.
Armin

