Solved

Simple MouseMove Question

Posted on 2000-02-18
16
278 Views
Last Modified: 2008-03-03
I have a form with a toolbar and a menubar.  The application displays different captions on a status bar when the mouse is over different toolbar buttons.  When the mouse goes below the toolbar I added code to the Form MouseMove event to return the status bar to default.  When the mouse goes above the toolbar I don't know where to add code for the menubar to return the status bar to default.  Any ideas?
0
Comment
Question by:jasonboetcher
  • 5
  • 4
  • 3
  • +3
16 Comments
 
LVL 1

Expert Comment

by:Catouch
ID: 2534914
Maybe you could calculate the position of your mouse.

if mousemove (x,y) = form.top - 20 then
 write your code here
endif

Something like that
0
 
LVL 6

Expert Comment

by:Marine
ID: 2534920
OK, In your tool bar MouseMove event Place the code that will show the changes in status bar. As soon as mouse leaves the toolbar , status will be default.
0
 
LVL 12

Expert Comment

by:roverm
ID: 2534970
Or use an API to detect the mouse leaving your form:

see http://www.vb-world.net/demos/mouse/ for much information on this subject !

D'Mzzl!
RoverM
0
 

Author Comment

by:jasonboetcher
ID: 2534976
Catouch, I don't really want to do it that way because of different screen resolutions.  Is there any other way?

Marine, that's the way I have it now but when I leave the toolbar the status bar stays the same.  (The status bar is actually a SSPanel.)
0
 
LVL 6

Expert Comment

by:Marine
ID: 2535020
I'll give you a better solution in a little later. For now you can do this. See if the focus left the toolbar if it did then change the status bar. Try using LostFocus , i am in a hurry i'll tlak to you later.
0
 

Author Comment

by:jasonboetcher
ID: 2535038
Marine, I can't find a LostFocus event for the toolbar.  Do you have a code sample?
0
 
LVL 32

Expert Comment

by:Erick37
ID: 2535392
Use the SetCapture() API in the toolbar MouseMove event.  Then you can test when the mouse moves outside the toolbar window.  At that point call ReleaseCapTure()
0
 

Author Comment

by:jasonboetcher
ID: 2535428
Erick37, can you give me a simple overview of how to use an API?  I have never used one before.  Also any sample code would be helpful.
0
How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

 
LVL 1

Expert Comment

by:jjsc
ID: 2535690
The following code demonstrates the use of the Get/Set/ReleaseCapture API calls. Note, the height of the menu bar is made negative because the Form coordinates are (0,0) one pixel below the bottom left corner of menu bar. Note also one problem with this method -- if the user moves *above* the form and re-enters, the form does not receive focus, so the status bar cannot be updated. The user must move onto the form and then over the menu bar.

A solution for this is to *not* call "ReleaseCapture" in the MouseMove event, however this has the unwanted side effect that it is necessary to click twice on the menu item (and then the problem described above comes into play again.)

Hope this helps,

John

'--------------------------------------------


Option Explicit

' API call to get various metrics (e.g. size of visible window, menu bar height etc.)
Private Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Integer) As Integer

' API calls to control which window receives mouse movement
Private Declare Function ReleaseCapture Lib "user32" () As Long
Private Declare Function GetCapture Lib "user32" () As Long
Private Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long

' menu bar height constant
Private Const SM_CYMENUSIZE = 55

Private ml_MenuHeight As Long, ml_Width As Long, ml_Height As Long

Private Sub Form_Load()
    ' get the height of the menu bar in twips
    ml_MenuHeight = -ScaleY(GetSystemMetrics(SM_CYMENUSIZE), vbPixels, vbTwips)
   
    ' make sure we have width and height in Twips
    ml_Width = ScaleX(ScaleWidth, ScaleMode, vbTwips)
    ml_Height = ScaleY(ScaleHeight, ScaleMode, vbTwips)
    StatusBar1.Panels.Add
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
   
    ' if we don't have the mouse captured, capture it
    If GetCapture() <> hWnd Then
        SetCapture hWnd
    End If
   
    ' check if we're within the bounds of the form
    If X < 0 Or X > ml_Width Or Y < ml_MenuHeight Or Y > 0 Then
        ' outside the permitted bounds, release the capture
        ReleaseCapture
       
        ' clear the status bar here
    Else
        ' update the status bar here
    End If
   
End Sub
0
 

Author Comment

by:jasonboetcher
ID: 2535845
jjsc, You say "if the user moves *above* the form and re-enters, the form does not receive focus, so the status bar cannot be updated".  So if my form is always maximized I will not need to worry about this problem?
0
 
LVL 32

Expert Comment

by:Erick37
ID: 2535851
John's code is essentially correct, however, I would put the code inside the ToolBar MouseMove event.
If you do not, then moving the mouse into the toolbar from the top, then moving it out again will not have the desired effect.
0
 
LVL 1

Accepted Solution

by:
jjsc earned 10 total points
ID: 2535904
Aha, Erick37 is right - I didn't read the question fully :-) The code I gave was for the menu bar, rather than the toolbar! That should make things easier since you should have a Height property for the toolbar. Just drop the code from the form_mousemove event into the toolbar mousemove and change the condition for the Y coordinate to be something like:

.... Y < 0 Or Y > ToolBar.Height

And yes, in principal a maximised form wouldn't have the problem of the user leaving from the top. Also, putting SetCapture in the toolbar mousemove ensures that you always capture the mouse even after clicking a button (which automagically calls ReleaseCapture and would be a problem for VB menu buttons)

John
0
 

Author Comment

by:jasonboetcher
ID: 2535990
Thanks everybody.  Sorry I can't accept more than one answer.  They should invent a way to divide up points.  Oh well, Erick37, I'll give you the points next time.  You are on my "people I have screwed over giving points to because I can only give points to one person" list; so I will be sure to keep that in mind if you answer any of my future questions.
0
 
LVL 1

Expert Comment

by:jjsc
ID: 2536038
Now I feel guilty :-) But in my (poor and limited) defense, when I originally read the question, Erick37 hadn't posted a comment, and I was already building a sample based on code I use...

John
0
 
LVL 32

Expert Comment

by:Erick37
ID: 2536134
You can make it up by figuring out a way to press ToolBar buttons while the mouse is captured.
:-)
0
 
LVL 1

Expert Comment

by:jjsc
ID: 2541928
OK, after much thought and a little digging, I came up with the following solution (which incidentally has solved exactly the same problem I already had with GetCapture :-)

Drop the following code into a BAS module, e.g. MCapture.bas

'-------------------------------

Option Explicit

' functions to capture all output for a particular window
Public Declare Function GetCapture Lib "user32" () As Long
Public Declare Function SetCapture Lib "user32" (ByVal hWnd As Long) As Long
Public Declare Function ReleaseCapture Lib "user32" () As Long

' send events as if they came from the mouse
Public Declare Sub mouse_event Lib "user32" (ByVal dwFlags As Long, ByVal dx As Long, ByVal dy As Long, ByVal cButtons As Long, ByVal dwExtraInfo As Long)

' get device information
Public Declare Function GetSystemMetrics Lib "user32" (ByVal nIndex As Long) As Long

' find the cursor
Public Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long

' for obtaining current screen dimensions
Public Const SM_CXSCREEN = 0
Public Const SM_CYSCREEN = 1

' constants for sending correct mouse event
Public Const MOUSEEVENTF_LEFTDOWN = &H2     '  left button down
Public Const MOUSEEVENTF_LEFTUP = &H4       '  left button up
Public Const MOUSEEVENTF_RIGHTDOWN = &H8    '  right button down
Public Const MOUSEEVENTF_RIGHTUP = &H10     '  right button up
Public Const MOUSEEVENTF_MIDDLEDOWN = &H20  '  middle button down
Public Const MOUSEEVENTF_MIDDLEUP = &H40    '  middle button up
Public Const MOUSEEVENTF_ABSOLUTE = &H8000  '  absolute move

Public Type POINTAPI
    X As Long
    Y As Long
End Type

Public Sub MouseClick(hWnd As Long, ByVal Button As MouseButtonConstants)
    ' store current coordinates
    Dim pt As POINTAPI
   
    ' dummy result, screen width and height
    Dim res As Long, scrX As Long, scrY As Long
   
    ' current mouse coordinates
    Dim curX As Long, curY As Long
   
    ' selected operation (left, middle, right button)
    Dim mouseDown As Long, mouseUp As Long
   
    ' get the dimensions of the current display
    scrX = GetSystemMetrics(SM_CXSCREEN)
    scrY = GetSystemMetrics(SM_CYSCREEN)
   
    ' get the current cursor position
    res = GetCursorPos(pt)
   
    ' convert to Mouse coordinates (0-65535, 0-65535)
    curX = pt.X * &HFFFF& / scrX
    curY = pt.Y * &HFFFF& / scrY
   
    ' select the event we want to send
    Select Case Button
        Case vbLeftButton
            mouseDown = MOUSEEVENTF_LEFTDOWN
            mouseUp = MOUSEEVENTF_LEFTUP
        Case vbMiddleButton
            mouseDown = MOUSEEVENTF_MIDDLEDOWN
            mouseUp = MOUSEEVENTF_MIDDLEUP
        Case vbRightButton
            mouseDown = MOUSEEVENTF_RIGHTDOWN
            mouseUp = MOUSEEVENTF_RIGHTUP
    End Select
   
    ' send it. Note, need to send mouseDown AND mouseUp
    mouse_event MOUSEEVENTF_ABSOLUTE Or mouseDown, curX, curY, 0, 0
    mouse_event MOUSEEVENTF_ABSOLUTE Or mouseUp, curX, curY, 0, 0
End Sub

'-------------------------------

Now, to test the code, drop a toolbar onto a new form, add a few buttons and add the following code:

'-------------------------------

Option Explicit

Private Sub Toolbar1_ButtonClick(ByVal Button As MSComctlLib.Button)
    Debug.Print "Clicked button " & Button.Index
End Sub

Private Sub Toolbar1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' if we don't have the mouse captured, capture it
    If GetCapture() <> Toolbar1.hWnd Then
        SetCapture Toolbar1.hWnd
    End If
   
    ' check if we're within the bounds of the form
    If X < 0 Or X > Toolbar1.Width Or Y < 0 Or Y > Toolbar1.Height Then
        ' no, release the capture
        ReleaseCapture
    End If
End Sub

Private Sub Toolbar1_MouseUp(Button As Integer, Shift As Integer, X As Single, Y As Single)
    ' click releases capture, so we only need to call the click function while capture is set.
    If GetCapture() = Toolbar1.hWnd Then
        MouseClick Toolbar1.hWnd, Button
    End If
End Sub

'-------------------------------

Notice that the MouseClick event should be in the MouseUp event of the toolbar (or whichever control has the focus captured) and you need to check if focus is still captured to prevent sending 2 events after the first click.

I hope that covers my penance :-)

Enjoy,

John
0

Featured Post

Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

Join & Write a Comment

When trying to find the cause of a problem in VBA or VB6 it's often valuable to know what procedures were executed prior to the error. You can use the Call Stack for that but it is often inadequate because it may show procedures you aren't intereste…
When designing a form there are several BorderStyles to choose from, all of which can be classified as either 'Fixed' or 'Sizable' and I'd guess that 'Fixed Single' or one of the other fixed types is the most popular choice. I assume it's the most p…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Show developers how to use a criteria form to limit the data that appears on an Access report. It is a common requirement that users can specify the criteria for a report at runtime. The easiest way to accomplish this is using a criteria form that a…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now