Link to home
Start Free TrialLog in
Avatar of Mike Eghtebas
Mike EghtebasFlag for United States of America

asked on

GetCursorPos(...) in Access

I have this code to move the mouse pointer to a desired location on a form (I think):

Private Declare Function SetCursorPos Lib "user32" (ByVal x As Long, ByVal y As Long) As Long
using:

Call SetCursorPos 100,45 ' for example.

Now, I need similar function to return X, and Y value of the mouse pointer where ever it might be on the form. I am looking for GetCursorPos(...)

Thanks.
ASKER CERTIFIED SOLUTION
Avatar of rockiroads
rockiroads
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Mike Eghtebas

ASKER

Now, I guess all I need to do is:

Debug.Print  "x= " & GetXCursorPos()  & ", y= " & GetYCursorPos

I am testing although your solution don't need to be tested.

Mike
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Idle_Mind,

What a pleasure to hear from you. Year 2004, I learned a lot from you with my VB questions.

Conversion issue was one of the points I was strugling with just now.  your post will be helpfull in that regard.

Another issue I am dealing with is to find left position of the form. In VB, I have used me.left but it seems not working in Access.

FYI: What I am tying to do to detect (in the form timer event) if the user has the cursor on a certain button:

    If (GetXCursorPos >= cmdStop.Left And GetXCursorPos <= (cmdStop.Left + cmdStop.Width)) Then And _
    (GetYCursorPos <= cmdStop.Top And GetYCursorPos >= (cmdStop.Top + cmdStop.Height)) Then
        bolStop = True
        cmdStop.SetFocus
    Else
        bolStop = False
    End If

Of course, I need yet to include form's .left and .top property in the code.

Thank you to both my favorite experts.

Mike
Background: variable bolStop is set to control the code used to print files. By holding/clicking cmdStop, user is able to stop print process.

At a later question I will post, I would try to send a commant to the printer to cancle all print jobs from a specific user (to cancle all print jobs qued to be printed). I am not sure whether such action is possible or not.

Regards,

Mike
? should you just trap the mousemove event?
Hi Mike, I went offline after I posted but I see what you are trying to do

idle mind, I didnt know about that api, now I do, thanks

If u just want to capture the position of a mouse to see if its over a certain control then I think the answer from EDDYKT would solve that for you

cmdstop_mousemove  is called whenever the mouse is moved over that button
u may want to handle users using the keyboard as well? so perhaps u also need to check for cmdstop_gotfocus as well
re:> ? should you just trap the mousemove event?

Maybe. I am not sure. The reason for my uncertainty is while cpu is engaged running the print routine, why all of sudden a mouse move would be recognized (fire) in middle the print routine. I suspect it will come to it when the print routine is finished which to late then.

I am not even sure the print routine would allow timer to fire either. Then again I could test it to see how each behaves.

brb,

Mike
your print job, surely its just a case of you issuing it. You dont wait for that proces to end surely. One would assume u issue the command and revert focus back to access.
U could disable any buttons prior to call to print and renable them after print if that is what u are worried about
no, its stop print u want eh
oh
Test results:


Timer event fires: 4/10/2007 8:57:18 AM
Timer event fires: 4/10/2007 8:57:19 AM
Timer event fires: 4/10/2007 8:57:19 AM
Timer event fires: 4/10/2007 8:57:20 AM

Print started at: 4/10/2007 8:57:20 AM

Timer event fires: 4/10/2007 8:57:20 AM
Timer event fires: 4/10/2007 8:57:21 AM
Timer event fires: 4/10/2007 8:57:21 AM
Timer event fires: 4/10/2007 8:57:22 AM

Print finished at: 4/10/2007 8:57:31 AM

Although I clicked on cmdStop quickly right after clicking on cmdStop, it kept these two events (cmdStop_MouseMove and cmdStop_GotFocus) to fire after it was done printing.

cmdStop_MouseMove fires at: 4/10/2007 8:57:31 AM
cmdStop_GotFocus fires at: 4/10/2007 8:57:31 AM
cmdStop_MouseMove fires at: 4/10/2007 8:57:31 AM
Timer event fires: 4/10/2007 8:57:31 AM
Timer event fires: 4/10/2007 8:57:32 AM

But timer event fired without DoEvents or something else.

This is the reason why I though I have to use timer to check if the pointer is within cmdStop's boundry.

Mike
correction...

Although I clicked on cmdStop quickly right after clicking on cmdPrint, it kept these two events (cmdStop_MouseMove and cmdStop_GotFocus) to fire after it was done printing.
re:> your print job, surely its just a case of you issuing it. You dont wait for that proces to end surely.

My code cycles through files selected and prints them one at a time. If I have 12 files selected and the timer sets bolStop = True and my print routine has:

If bolStop = True Then
   now print
Else
  MsgBox "Print job is cancled by user."
  Exit Sub
End If

Mike
I am not sure how to apply code from Idle_Mind:

Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

Private Declare Function ScreenToClient Lib "user32" Alias "ScreenToClient" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

to my code:

Private Sub Form_Timer()

    Dim intX As Long        ' x-position of the cursor
    Dim intY As Long        ' y-position of the cursor
   
    Dim intLeft As Long     ' left of smdStop
    Dim intRight As Long    ' right of smdStop
   
    Dim intTop As Long      ' top of smdStop
    Dim intBottom As Long   ' bottom of smdStop
   
    intX = GetXCursorPos
    intY = GetYCursorPos
   
    intLeft = cmdStop.Left
    intRight = cmdStop.Left + cmdStop.Width
   
    intTop = cmdStop.Top
    intBottom = cmdStop.Top + cmdStop.Height
   
    If (intX >= intLeft And intX <= intRight) And _
       (intY <= intTop And intY >= intBottom) Then
       
            bolStop = True
            cmdStop.SetFocus
            DoEvents
    Else
        bolStop = False
    End If

End Sub

to make it work. Also I am not quite sure about:

...  (intY <= intTop And intY >= intBottom) Then

portion.

Thank you,

Mike
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
jefftwilley,

I have a good solution here. What I need a bit help to make it work that is if you have a moment to make sense of my last post.

Mike
No time tonight...let me tackle it again in the morning.
J
Thanks.
Mike,
I've had time this morning to read through your posts...and here's what I think.

I also have a process...mine involves importing and exporting though...but I'm still simply looping through and starting processes. There can be up to 20 or 30 of them. I use a method similar to this one

If bolStop = True Then
   now print
Else
  MsgBox "Print job is cancled by user."
  Exit Sub
End If

However...because the button click itself isn't actually recognized until my process finishes and tries to start the next item in the loop...I too am forced to wait for that ONE import/export to finish.

While designing and testing this particular process, I too thought there had to be a way to stop it immediately...and issuing a BREAK did at times cancel the process....but often times, that had unpredictable results.

I understand that you're trying to create a predictive process...where by you are relying on a big assumption, that IF your user's mouse is hovering over the CANCEL button, then he must be about to press it. I don't think that's good practice.

In theory, you can issue your mouse to move...you can gain it's coordinates in a timer event, but you're still within a process, that when cancelled, could quite possibly error out and bypass your exit routine within your code.

This can...will leave recordsets open, file handles open, etc...and probably orphan a print job that you'll have to manually cancel.

Convince me that my points have all been taken into consideration, and that you have it under control, and I too would love to have this function that handles a situation I too have been in....and opted for a more Code friendly answer to.

I'll play with this..get it working...but I won't know how to apply it to cancel your print job. I'm assuming you have that handled?
J
Mike, instead of worrying about the cursor position, what if u used a global variable (well global to the form) and the mousemove events of detail and cmdStop

dim m_bOnStopBtn as boolean

private sub form_load()
    m_bOnStopBtn = False
end sub

Private Sub Detail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    m_bOnStopBtn = False
end sub

Private Sub cmdStop_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    m_bOnStopBtn = True
end sub


then perhaps use m_bOnStopBtn to determine whether to kick off other events or not

eg

private sub form_timer()
    if m_bOnStopBtn = True then
          'do what u need to if cursor on stopbtn
    else
          'etc
    end if
end sub
rockiroads,

I guess you haven't read one of my earlier post on "Test results:"


Timer event fires: 4/10/2007 8:57:18 AM
Timer event fires: 4/10/2007 8:57:19 AM
Timer event fires: 4/10/2007 8:57:19 AM
Timer event fires: 4/10/2007 8:57:20 AM

If you do, you would see mouse move cannot be activated (fired) during the print process.

Please help me with my last post which starts with:

"I am not sure how to apply code from Idle_Mind:

Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

Private Declare Function ScreenToClient Lib "user32" Alias "ScreenToClient" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
.
."

Thanks.

Now, I am reading the posts from Jeff.

Mike

jefftwilley,

In my case, the Timer is able to fire and change the value of bolStop from True to False and visa versa. And, my print routine involves reading some file names from a list box. Using the code below:

If bolStop = True Then
   now print
Else
  MsgBox "Print job is cancled by user."
  Exit Sub
End If

if bolStop = True it will print. And once the print code is executed there is no way to undo it (at least for now. I will discuss this further later on with you).

So, there will be no files left open or orphan. The only point is I am dealing with buton left, form left and cursor position using code from Idle_Mind.

Unfortunately, I am not how to bring all together. But, I will eventually will be able to accomplish this task.
=======
Future quest:
Scenario: 10 files are sent to the printer and at this moment the printer is printing file 3 of 10.

User moves the mouse to Panic or Stop Print button. Usere resets bolStop to True when the next file (the 11th file) is being processed.

If bolStop = True Then
   now print
Else
  MsgBox "Print job is cancled by user."
  CancelAllPrintJobsInThePrinter
  Exit Sub
End If

Routine like "CancelAllPrintJobsInThePrinter" might be possible may be not.

If we have only 10 files to print, means now after 10th file is available to be clicked on and it responds to mouse move also.

Now, the idea is to accomplish the first phase of it (post starting:

"I am not sure how to apply code from Idle_Mind:

Private Declare Function ClientToScreen Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

Private Declare Function ScreenToClient Lib "user32" Alias "ScreenToClient" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long
.
.")

Mike

Working...standby.
Thank you very much.

Mike
Mike, I tried to get this going but couldnt quite get the right coordinates
Its almost perfect for X (top) but I couldnt quite get left (Y) working

this is the module code

Private Type POINTAPI
    X As Long
    Y As Long
End Type

Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Declare Function ScreenToClient Lib "user32" (ByVal hwnd As Long, lpPoint As POINTAPI) As Long

Public Function GetXCursorPos(ByVal lHwnd As Long) As Long
   Dim pt As POINTAPI
   GetCursorPos pt
   ScreenToClient lHwnd, pt
   GetXCursorPos = pt.X
End Function

Public Function GetYCursorPos(ByVal lHwnd As Long) As Long
   Dim pt As POINTAPI
   GetCursorPos pt
   ScreenToClient lHwnd, pt
   GetYCursorPos = pt.Y
End Function


and in the form, I call GetXCursorPos/GetYCursorPos by passing in Me.hwnd
eg
GetXCursorPos(Me.hwnd)
GetYCursorPos(Me.hwnd)

I created a sample form, one button (cmdStop), two labels (lblCurrPos, lblCmdPos)
lblCmdPos shows values of cmdStop (left,top,height,width)
lblCurrPos shows current cursor position

i.e.

Private Sub Form_Load()
    Me.lblCmdPos.Caption = "T=" & cmdStop.Top & ", L=" & cmdStop.Left & ", W=" & cmdStop.width & ", H=" & cmdStop.height
End Sub

Private Sub cmdStop_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Me.lblCurrPos.Caption = "on mouse"
End Sub

Private Sub Detail_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Me.lblCurrPos.Caption = "X=" & GetXCursorPos(Me.hwnd) & ", Y=" & GetYCursorPos(Me.hwnd)
End Sub

Private Sub Form_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Me.lblCurrPos.Caption = "X=" & GetXCursorPos(Me.hwnd) & ", Y=" & GetYCursorPos(Me.hwnd)
End Sub



But Im thinking about this and still not sure if these events can also be captured during the print process. Is it because the print process has all the cpu time, not sure.
Im gonna have another play, try to match coordinates correctly. Will have to do this 2morrow now
Thank you rockiroads for the time.

Re:>Is it because the print process has all the cpu time, not sure.

By looking to my test resluts from the previous posts, despit the fact print process (or better to say print process of may small files) starts at:

Print started at: 4/10/2007 8:57:20 AM

the form timer fires after print has started:

Timer event fires: 4/10/2007 8:57:20 AM

and befor print finishes at:

Print finished at: 4/10/2007 8:57:31 AM
============
Now, when the user moves the mouse to Panic or Stop Print button while code is in the process of printing the value of bolStop will change to True according my test results.  If the code is in the process of printing say 100 files one at a time and before printing each file checks the value of bolStop:

If bolStop = True Then
   'continue printing current file
Else
  MsgBox "Print job is cancled by the user."
  CancelAllPrintJobsInThePrinter
  Exit Sub
End If

Routine like "CancelAllPrintJobsInThePrinter" might be possible may be not. It is considered possibly to chase the print jobs to the printer and cancled these qued files inside the printer waiting to be printed.

As I said, this is the overkill I am hoping to address later on. Plan A is to stop sending to the printer when user moves the cursor over the panic button (or cmdStop). Plan B is to develope routine like CancelAllPrintJobsInThePrinter to stop print jobs already in the printer.

Regards,

Mike
rockiroads,

I coppied your code and created what you have described in your last post. For clarity, I cahnged following code only:

Private Sub Form_Load()
    Me.lblCmdPos.Caption = "Y1=" & cmdStop.Top & ", Y2=" & cmdStop.Top + cmdStop.Height & " , X1=" & cmdStop.Left & ", X2=" & cmdStop.Left + cmdStop.Width
End Sub

It works now!  I need still study it a bit but it works.

Thank you.

Mike
rockiroads and Idle_Mind,

Rocky's code on the test form (when no printing taking places) work fine, but it doesn't let Time fire. I move the form's MouseMove event to:

Private Sub Form_Timer()
' this event never fires
    Me.lblCurrPos.Caption = "X=" & GetXCursorPos(Me.hwnd) & ", Y=" & GetYCursorPos(Me.hwnd)
    DoEvents
    Me.Repaint
   ' this never takes place----v
   If lblCurrPos.Caption = "on mouse" Then
        bolStop = True
   Else
        'bolStop = False
   End If

End Sub
=========
Is there a way we avoid to use such a indirect response:

If lblCurrPos.Caption = "on mouse" Then

In direct because lblCurrPos first need to be set to "on mouse" and then our code have some chance to works.

Or, instead of setting its caption to "on mouse", why we cannot set bolStop to True?

Mike
I gave up.

Thank you to all.  My last atempt was to create another Panic.mdb with a single button (cmdStop) to change the value of TestVal (yes/no field) in a table tTest in this database. And, include the following code in the print module mdb. It read the setting from Panic.mdb okay but it doesn't fire when it is printing (despit my earlier test results). Here is the code:

Private Sub Form_Timer()
   
    If bolStop = False Then
        DoEvents
        Dim dbsNorthwind As Database
        Dim conPubs As Connection
        Dim rstTemp As Recordset
       
        Set dbsNorthwind = Workspaces(0).OpenDatabase("Panic.mdb")
       
        Set rstTemp = dbsNorthwind.OpenRecordset( _
        "tTest", dbOpenForwardOnly)
        If rstTemp.RecordCount > 0 Then
        'rstTemp.MoveFirst
        bolStop = rstTemp!TestVal
        End If
       
        rstTemp.Close
        dbsNorthwind.Close
       
        lblTest.Caption = bolStop
        Me.Repaint
        DoEvents
    End If

End Sub


Mike
Please see "Stop/Cancel Print Job..." at

https://www.experts-exchange.com/questions/22509816/Stop-Cancel-Print-Job.html

to handle it in a different manner. Any help is appreciated.

Mike