Hexen 09-09-2003, 07:58 AM Hi. :)
How would I go about capturing the MouseMove event for specified controls, and redirecting it to a function, without actually having to add MouseMove events for every one of these controls?
I want to make a StatusBar that has a label, which displays various specific status messages, as well as the ToolTipText or Tag of each control as the mouse is moved over them.
You mean like this:
Private Sub Command1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Call MoveOverObject(Command1, Button, Shift, X, Y)
End Sub
Private Sub Command2_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Call MoveOverObject(Command2, Button, Shift, X, Y)
End Sub
Private Sub Command3_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Call MoveOverObject(Command3, Button, Shift, X, Y)
End Sub
Public Function MoveOverObject(oObject As Object, Button As Integer, Shift As Integer, X As Single, Y As Single) As Boolean
' Do all the universal 'move over' stuff here
oObject.Caption = X
MoveOverObject = True
End Function
Every mousemove will go to the MoveOverObject, and there you can do with oObject the things you want it to. :)
00100b 09-09-2003, 08:13 AM You will need to use Sub-Classing to capture the WM_MOUSEMOVE message for each control and then handle the updating of the StatusBar.Panel in the WinProc for the hooked controls. It will be simpler to create a procedure that accepts a control instance as a parameter and call the procedure from each MouseMove event.
As far as ToolTipText, just set the value of the ToolTipText property for each control. When the mouse is hovered over the control, the ToolTipText will be displayed.
Hexen 09-09-2003, 08:32 AM It'd be all well and good to do it that way, but it sounds like this complex subclassing approach may be the way to go. I want to do this for every single control in my application, including all the controls in many MDIChild forms I have.
This is why I thought there must have been an alternative to typing one line in the MouseMove event of every control. It seems like alot of work to do something not that significant.
Thinker 09-09-2003, 08:42 AM Take a look at the SetCapture and ReleaseCapture API Functions.
00100b 09-09-2003, 08:45 AM I'm not following how setting all mouse input to a specific window is going to handle detecting when a mouse is being moved over a control?
Thinker 09-09-2003, 08:49 AM As long as the control has a hwnd, it can be set to capture all movement,
even outside the control. So it is just a matter of comparing the X and Y
to see where the mouse is.
00100b 09-09-2003, 09:29 AM As long as the control has a hwnd, it can be set to capture all movement,
even outside the control. So it is just a matter of comparing the X and Y
to see where the mouse is.
But that seems like alot more work to handle what is being sought.
Let's say that Form1 has 6 controls, for sake of simplicity, three text boxes, two buttons, and a status bar.
The requirement is, that when the mouse is moved over a specific control, a textual description for that control is displayed in Panel(1) of the status bar.
Normally, one would do something like:
Private Sub Text1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Me.StatusBar1.Panels(1).Text = "Control's Description Here"
End Sub
' Repeated for each TextBox and CommandButton
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
Me.StatusBar1.Panels(1).Text = vbNullString
End Sub
With that, when the mouse is moved over Text1, StatusBar1 displays Text1's Tag. When the mouse is moved over Text2, StatusBar1 displays Text2's Tab. And so on, and so on.
Now, with using the SetCapture/ReleaseCapture.
Private Declare Function SetCapture Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Sub Form_Load()
SetCapture Me.hwnd
End Sub
Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
If (X > Me.Text1.Left And X < Me.Text1.Left + Me.Text1.Width) AND
(Y > Me.Text1.Top And Y < Me.Text1.Top + Me.Text1.Height) Then
Me.StatusBar1.Panels(1).Text = "Control's Description Here"
' ElseIf ... Repeated for each control
End If
End Sub
Private Sub Form_Unload()
ReleaseCapture
End Sub
Also, included in this handling, you would need to evaluate the MouseDown to determine when a control is clicked on so that it can receive the focus because while capturing is active, clicking on everything else won't trigger those mouse events.
So now, on the Form_MouseDown event, we are evaluating where the mouse is and if it is over a control, then release the capture and set the capture to the control so that it can now receive the mouse events, and on the control's MouseUp, setting the capture back to the form.
Add to this the handling to release the capture so that the Form's control menu can be invoked (like clicking on the little "x" to close the form).
At least with Sub-Classing and trapping for the WM_MOUSEMOVE message, you can intercept the message, do something, and then continue with the normal processing of that message.
Or am I missing something here all-together?
Hexen 09-09-2003, 09:31 AM Ok, I've integrated SetCapture into my application a little.
The link you gave above says that SetCapture returns the handle of the window that previously captured the mouse. I figured that I could use this to capture the control that would have otherwise captured the mouse movement. So I just declared a long and gave it SetCapture's returned value, so now I have the handle of the control I want to put into a variable.
How can I use the handle to get the specific control, without looping through every control's hWnd property?
Thinker 09-09-2003, 09:33 AM Doesn't sound like you are missing anything. But it really depends on
what is needed. If you need to continue processing mouse clicks, the
SetCapture method is going to get messy. Subclassing has its own set
of problems. It just depends.
00100b 09-09-2003, 09:42 AM Agreed, both add their inherit complexities. But, if Hexen doesn't want to take the route of adding a line of code to each control's MouseMove event, and still be able to interact with the form in the usual manner, then I believe that Sub-Classing is the least complex of the two presented alternatives.
Hexen, in response to your question about looping through the controls' handles, you will need to do this with whichever of the two methods that you implement.
Hexen 09-09-2003, 09:54 AM Hmm, bugger. :P
Well if I'm going to have to do that, then maybe I should try another method. I've noticed that in using this SetCapture function, controls don't seem to pick up their click events unless the mouse is still while over the control.
I guess subclassing isn't really viable either, considering that the entire point of my wanting to know how to do this is to avoid adding one line in every control's MouseMove event.
If you guys know of a way to cause SetCapture to not cause click events to work as mentioned above, then that'd be heaps good. It looks like I might have to end up testing the bounds of each control to figure out which control is under the mouse though at this rate. It sure seems like alot of work to be done every time the mouse moves though. :P
Edit: Ugh, so only form windows have handles? Bugger. It seems I wouldn't be able to get the control under the mouse pointer with SetCapture after all. I was under the assumption it was returning a handle referring to the control that the mouse was passing over.
00100b 09-09-2003, 10:03 AM You're better off doing it the old-fashioned way. Sorry. I know it's not the answer that you want to hear.
Hexen 09-09-2003, 10:08 AM Argh!
Ah well...
Ehhm, just in the off-chance that the old fashioned way isn't what I think it is. Do ya mean typing in the MouseMove event for every control? :P
manavo 09-09-2003, 06:49 PM Well with a timer you could try something else... With just a timer you can check if the mouse is over a control. So that in combination with a For Each control loop should work ;)
manavo 09-09-2003, 06:56 PM At this page : http://www.vbforums.com/showthread.php?s=&threadid=231469
you can find the code I am refering to . Just change the timer checking to check all the controls ;)
|