Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 294
  • Last Modified:

Simple MouseMove Question

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
jasonboetcher
Asked:
jasonboetcher
  • 5
  • 4
  • 3
  • +3
1 Solution
 
CatouchCommented:
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
 
MarineCommented:
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
 
rovermCommented:
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
jasonboetcherAuthor Commented:
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
 
MarineCommented:
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
 
jasonboetcherAuthor Commented:
Marine, I can't find a LostFocus event for the toolbar.  Do you have a code sample?
0
 
Erick37Commented:
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
 
jasonboetcherAuthor Commented:
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
 
jjscCommented:
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
 
jasonboetcherAuthor Commented:
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
 
Erick37Commented:
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
 
jjscCommented:
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
 
jasonboetcherAuthor Commented:
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
 
jjscCommented:
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
 
Erick37Commented:
You can make it up by figuring out a way to press ToolBar buttons while the mouse is captured.
:-)
0
 
jjscCommented:
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

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

  • 5
  • 4
  • 3
  • +3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now