Results 1 to 16 of 16

Thread: [RESOLVED] Get object by mouse position on click

  1. #1

    Thread Starter
    New Member
    Join Date
    Feb 2019
    Posts
    5

    Resolved [RESOLVED] Get object by mouse position on click

    Hi guys!!

    There's another VB6 special challenge! lol!

    My application has many objects in many parents and z-orders... Someones showing disabled for editing (not clickable)... All the objects interact with the screen size and resizing, so the position is always kind of relative...
    I'm trying to implement an tool to edit some properties of these objects out of the source code.

    Question:
    Is there anyway to get the object (at least its name) by mouse positioning on the screen? Thinking about the moment that the user clicks on the object and work around its name to show on my tool the properties that he could edit.

    I found some ways to get the mouse position or implement some event on the object to get its position, but nothing so general... I don't wanna implement an event for all the objects... that's a lot!

    Thanks!!
    Last edited by fernandozap; Feb 21st, 2019 at 01:17 PM.

  2. #2
    Sinecure devotee
    Join Date
    Aug 2013
    Location
    Southern Tier NY
    Posts
    6,582

    Re: Get object by mouse position on click

    Well, I don't know a lot of windows api options that might make it simpler, so my approach, based on the little I know, would be to keep the bounds for all the controls in some structure so that they would be easy to look up, and then use the GetAsyncKeyState function to monitor for a button press in my window, then look up the control, or controls whose bounds include that point.

    In the cases where I've used "objects" that I created and placed, so I know their bounds and z-order, I can just search the list I maintain in z-order and the first hit I get I know is the visible object that was clicked on, rather than some object that was under it in the z-order.

  3. #3

    Thread Starter
    New Member
    Join Date
    Feb 2019
    Posts
    5

    Re: Get object by mouse position on click

    Thanks Passel...

    I could do this if my objects doesn't change their position with an resize, but it does! So I need something more accurate, if is it possible...

  4. #4
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Get object by mouse position on click

    This is just an idea for you to think.

    You may implement a low-level mouse hook with your tool for this.
    Based on that, you can get low-level mouse data for x, y coordinates when the mouse moves/clicks on controls in your targeting application.
    Then, use WindowFromPoint API to get the hWnd of the controls based on the x, y coordinates (but excluding disabled or windowless controls)

  5. #5

    Thread Starter
    New Member
    Join Date
    Feb 2019
    Posts
    5

    Re: Get object by mouse position on click

    ....
    Last edited by fernandozap; Feb 21st, 2019 at 01:14 PM.

  6. #6

    Thread Starter
    New Member
    Join Date
    Feb 2019
    Posts
    5

    Re: Get object by mouse position on click

    Quote Originally Posted by PGBSoft View Post
    This is just an idea for you to think.

    You may implement a low-level mouse hook with your tool for this.
    Based on that, you can get low-level mouse data for x, y coordinates when the mouse moves/clicks on controls in your targeting application.
    Then, use WindowFromPoint API to get the hWnd of the controls based on the x, y coordinates (but excluding disabled or windowless controls)
    Hey PGB... thanks for the tip!! I wrote a code with this:

    Code:
    (...)
    lngHwnd = ChildWindowFromPoint(Me.hwnd, 10, 10)
    GetClassName(lngHwnd, classname, 50)
    (...)
    the GetClassName API returns some name, but not the exactly object name. I'm searching for an API that returns that. Do you know anyone?

    Thanks!

  7. #7
    PowerPoster
    Join Date
    Jun 2015
    Posts
    2,224

    Re: Get object by mouse position on click

    Once you've got the hWnd, couldn't you just iterate all your child controls, looking for you hWnd?

  8. #8
    Addicted Member
    Join Date
    Jun 2018
    Posts
    189

    Re: Get object by mouse position on click

    Perhaps, this may help you...

  9. #9
    Hyperactive Member
    Join Date
    Mar 2018
    Posts
    460

    Re: Get object by mouse position on click

    this code listens for mouseclick events and then uses a basic axis-aligned bounding box formula to see if the mouse position has collided with any control. The built in "me.controls" collection seems to return controls in topmost zorder so there is no need to look at the zorder

    put a timer on a form, paste this code, and add overlapping controls to see it in action:

    Code:
    Option Explicit
    Private Type POINTAPI
        X As Long
        Y As Long
    End Type
    
    Private Type RECT
       Left As Long
       Top As Long
       Right As Long
       Bottom As Long
    End Type
    
    Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
    Private Declare Function GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare Function GetActiveWindow Lib "user32" () As Long
    Private Declare Function GetWindowRect Lib "user32.dll" (ByVal hwnd As Long, ByRef lpRect As RECT) As Long
    
    Private Sub Form_Load()
        Timer1.Interval = 250
        Timer1.Enabled = True
    End Sub
     
    Private Sub Timer1_Timer()
        Dim pt As POINTAPI
        Dim c As Control
        
        If GetAsyncKeyState(1) <> 0 Then
            GetCursorPos pt
            If GetActiveWindow = Me.hwnd Then
                For Each c In Me.Controls
                    If controlAtPoint(c, pt.X, pt.Y) Then
                        Debug.Print c.Name & " was clicked"
                        Exit For
                    End If
                Next
            End If
        End If
     
    End Sub
    
    Private Function controlAtPoint(c As Control, mx As Long, my As Long) As Boolean
        Dim a As RECT
        Dim b As RECT
        On Error Resume Next
        GetWindowRect c.hwnd, a
        b.Top = my
        b.Left = mx
        b.Bottom = my - 1
        b.Right = mx + 1
        controlAtPoint = ((a.Left < b.Left + (b.Right - b.Left)) And (a.Left + (a.Right - a.Left) > b.Left) And (a.Top < b.Top + (b.Top - b.Bottom)) And (a.Top + (a.Bottom - a.Top) > b.Top))
        On Error GoTo 0
    End Function

  10. #10
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Get object by mouse position on click

    Do note that API solutions that rely on a hWnd will not find windowless controls (images, shapes, labels, etc) if that applies to you.

    DllHell's solution might be modified to address the problem. Instead of using GetWindowRect to retrieve the dimensions, use the control's Width/Height properties. There are some gotchas there. For example, not all controls have a Width/Height property: Lines, menus, and probably a couple others that would be returned from the form's Controls() collection.

    Another gotcha is that you may need to scale a control's dimensions to pixels (for comparison) as those dimensions are in the control's container scalemode, be it twips or whatever. More effort obviously, but may be reasonable to trap for windowless controls. But a solution like this would require additional checks: you don't want to return a hidden image control (.Visible = False)
    Last edited by LaVolpe; Feb 21st, 2019 at 04:40 PM.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  11. #11
    PowerPoster
    Join Date
    Feb 2017
    Posts
    5,064

    Re: Get object by mouse position on click

    Hello, this code is similar to the one proposed above but it will work with all the forms and all the controls that have dimensions:

    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 GetAsyncKeyState Lib "user32" (ByVal vKey As Long) As Integer
    Private Declare Function ScreenToClient Lib "user32" (ByVal hWnd As Long, lpPoint As POINTAPI) As Long
    
    Private Const VK_LBUTTON As Long = &H1
    
    Private Sub Form_Load()
        Timer1.Interval = 10
    End Sub
    
    Private Sub Timer1_Timer()
        Dim iPt As POINTAPI
        Dim iPt_Scaled As POINTAPI
        Static sMousePressed As Boolean
        Dim iFrm As Form
        Dim iTheForm As Form
        Dim iCtl As Control
        Dim iTheControl  As Control
        Dim iVisible As Boolean
        Dim iLeft As Single
        Dim iTop As Single
        Dim iWidth As Single
        Dim iHeight As Single
        
        If GetAsyncKeyState(VK_LBUTTON) <> 0 Then
            GetCursorPos iPt
            If Not sMousePressed Then
                sMousePressed = True
                iPt_Scaled.X = iPt.X * Screen.TwipsPerPixelX
                iPt_Scaled.Y = iPt.Y * Screen.TwipsPerPixelX
                For Each iFrm In Forms
                    If iFrm.Visible Then
                        If iFrm.WindowState <> vbMinimized Then
                            If iPt_Scaled.X >= iFrm.Left Then
                                If iPt_Scaled.X <= (iFrm.Left + iFrm.Width) Then
                                    If iPt_Scaled.Y >= iFrm.Top Then
                                        If iPt_Scaled.Y <= (iFrm.Top + iFrm.Height) Then
                                            Set iTheForm = iFrm
                                            Exit For
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    End If
                Next
                If Not iTheForm Is Nothing Then
                    ScreenToClient iTheForm.hWnd, iPt
                    iPt_Scaled.X = iTheForm.ScaleX(iPt.X, vbPixels, iTheForm.ScaleMode)
                    iPt_Scaled.Y = iTheForm.ScaleY(iPt.Y, vbPixels, iTheForm.ScaleMode)
                    For Each iCtl In iTheForm.Controls
                        On Error Resume Next
                        iVisible = False
                        iVisible = iCtl.Visible
                        iLeft = 0
                        iLeft = iCtl.Left
                        iTop = 0
                        iTop = iCtl.Top
                        iWidth = 0
                        iWidth = iCtl.Width
                        iHeight = 0
                        iHeight = iCtl.Height
                        If iVisible then
                            If (iWidth = 0) Or (iHeight = 0) Then iVisible = False
                        End If
                        On Error GoTo 0
                        If iVisible Then
                            If iPt_Scaled.X >= iLeft Then
                                If iPt_Scaled.X <= (iLeft + iWidth) Then
                                    If iPt_Scaled.Y >= iTop Then
                                        If iPt_Scaled.Y <= (iTop + iHeight) Then
                                            Set iTheControl = iCtl
                                            Exit For
                                        End If
                                    End If
                                End If
                            End If
                        End If
                    Next
                    If Not iTheControl Is Nothing Then
                        Debug.Print "Clicked " & iTheControl.Name & " in " & iTheForm.Name
                    End If
                End If
            End If
        Else
            sMousePressed = False
        End If
    End Sub
    Last edited by Eduardo-; Feb 22nd, 2019 at 08:15 AM.

  12. #12
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Get object by mouse position on click

    @Eduardo. Should the mouse be clicked exactly at 0,0 in the client area, your logic could return a false positive on a control that doesn't have a left,top,width or height property when no control is at 0,0 on the form. For example, a visible Line elsewhere on the form would return a false positive in that case. Since lines don't have those properties, your routine defaults to 0x0 @ 0,0. Well, iPt_Scaled.X >= 0 and iPt_Scaled.X <= 0 and iPt_Scaled.Y >= 0 and iPt_Scaled.Y <= 0 when mouse down at 0,0. Hopefully, I'm reading your code correctly, did not run it. If so, suggest maybe changing your check to following or toggle iVisible to False when width or height are zero.
    If iVisible = True And iWidth > 0 And iHeight > 0
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  13. #13
    PowerPoster
    Join Date
    Feb 2017
    Posts
    5,064

    Re: Get object by mouse position on click

    Quote Originally Posted by LaVolpe View Post
    @Eduardo. Should the mouse be clicked exactly at 0,0 in the client area, your logic could return a false positive on a control that doesn't have a left,top,width or height property when no control is at 0,0 on the form. For example, a visible Line elsewhere on the form would return a false positive in that case. Since lines don't have those properties, your routine defaults to 0x0 @ 0,0. Well, iPt_Scaled.X >= 0 and iPt_Scaled.X <= 0 and iPt_Scaled.Y >= 0 and iPt_Scaled.Y <= 0 when mouse down at 0,0. Hopefully, I'm reading your code correctly, did not run it. If so, suggest maybe changing your check to following or toggle iVisible to False when width or height are zero.
    If iVisible = True And iWidth > 0 And iHeight > 0
    Hi LaVolpe. Good idea, changed!

  14. #14
    Fanatic Member
    Join Date
    Feb 2019
    Posts
    706

    Re: Get object by mouse position on click

    Try Debug.Print Screen.ActiveControl.Name. See also ActiveForm.

  15. #15
    VB-aholic & Lovin' It LaVolpe's Avatar
    Join Date
    Oct 2007
    Location
    Beside Waldo
    Posts
    19,541

    Re: Get object by mouse position on click

    Quote Originally Posted by qvb6 View Post
    Try Debug.Print Screen.ActiveControl.Name. See also ActiveForm.
    Won't work for all types of controls, i.e., shape controls or controls that can't get focus. Also won't work for disabled controls which the OP seems to want included.
    Insomnia is just a byproduct of, "It can't be done"

    Classics Enthusiast? Here's my 1969 Mustang Mach I Fastback. Her sister '67 Coupe has been adopted

    Newbie? Novice? Bored? Spend a few minutes browsing the FAQ section of the forum.
    Read the HitchHiker's Guide to Getting Help on the Forums.
    Here is the list of TAGs you can use to format your posts
    Here are VB6 Help Files online


    {Alpha Image Control} {Memory Leak FAQ} {Unicode Open/Save Dialog} {Resource Image Viewer/Extractor}
    {VB and DPI Tutorial} {Manifest Creator} {UserControl Button Template} {stdPicture Render Usage}

  16. #16

    Thread Starter
    New Member
    Join Date
    Feb 2019
    Posts
    5

    Re: Get object by mouse position on click

    Really thanks for ALL!!

    I think doing something that DllHell and Eduardo suggested will resolve! Because I wasn't figuring out how to do with accessibility API....
    The priorities on my project has been changed, and I'll do this in the future (not just now), but I'll tell you when finished!

    You're awesome guys!! thanks a lot!!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width