Want to win a PS4? Go Premium and enter to win our High-Tech Treats giveaway. Enter to Win

x
?
Solved

Simple MouseMove Question

Posted on 2000-02-18
16
Medium Priority
?
292 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 

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
 
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 40 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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you ever wanted to restrict the users input in a textbox to numbers, and while doing that make sure that they can't 'cheat' by pasting in non-numeric text? Of course you can do that with code you write yourself but it's tedious and error-prone …
Article by: Martin
Here are a few simple, working, games that you can use as-is or as the basis for your own games. Tic-Tac-Toe This is one of the simplest of all games.   The game allows for a choice of who goes first and keeps track of the number of wins for…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…
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…
Suggested Courses

618 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