Determine shape object position

hbudihardjo

New Member
Joined
Jul 3, 2007
Messages
1
Can I determine the position of a call out shape object, specifically the position of the starting node/the lowest node on the "triangle"? I need to figure out to what cell this call out is actually pointing to. This far, I have figured out how to get the width & height, and left & top position of the box. However, this is not accurate enough to predict that "starting node" position as the size of the shapes is different from one file to other files.

For example, as seen on the link below, is there any properties that can return the value of range (in this example, range "A6") or any pixel position somewhere close to there?
https://webmail1.uwindsor.ca/~budihar/autoshape.html

Thank you very much. Any answer will be very appreciated.
 

Excel Facts

Add Bullets to Range
Select range. Press Ctrl+1. On Number tab, choose Custom. Type Alt+7 then space then @ sign (using 7 on numeric keypad)
This function will work for Rectangular callouts, giving you the value of the cell where the callout ends.

Code:
Function GetCalloutValue(ByVal shapeName As String, _
                         Optional parentRange As Range, _
                         Optional volatile As Boolean = True) As Variant
   Dim shp As Excel.Shape
   Dim WS As Worksheet
   Dim top As Single
   Dim left As Single
   Dim testRange As Range
   Dim foundHorizontal As Boolean
   Dim foundVertical As Boolean
   
   Application.volatile volatile
   
   If Not parentRange Is Nothing Then
      Set WS = parentRange.Worksheet
   Else
      If TypeName(Application.Caller) = "Range" Then
         Set WS = Application.Caller.Worksheet
      Else
         GetCalloutValue = CVErr(xlErrNum)
         Exit Function
      End If
   End If
   
   On Error Resume Next
   Set shp = WS.Shapes(shapeName)
   On Error GoTo 0
   
   If shp Is Nothing Then
      GetCalloutValue = CVErr(xlErrValue)
      Exit Function
   End If
   
   'Only do for Rectangular Callout for now
   If shp.AutoShapeType <> msoShapeRectangularCallout Then
      GetCalloutValue = CVErr(xlErrValue)
      Exit Function
   End If
   
   'Get mid point of the rectangle
   top = shp.top + shp.Height / 2
   left = shp.left + shp.Width / 2
   
   'Adjustments(1) holds the number of "widths" where the callout ends
   left = left + shp.Width * shp.Adjustments(1)
   
   'Adjustments(2) holds the number of "heights" where the callout ends
   top = top + shp.Height * shp.Adjustments(2)
   
   'Now find the range that has those coordinates, starting from the TopLeftCell
   
   Set testRange = shp.TopLeftCell
   
   foundHorizontal = False
   foundVertical = False
   Do While Not (foundHorizontal And foundVertical)
      If Not foundHorizontal Then
         Select Case left
         Case Is < testRange.left
            Set testRange = testRange.Offset(, -1)
         Case Is > testRange.left + testRange.Width
            Set testRange = testRange.Offset(, 1)
         Case Else
            foundHorizontal = True
         End Select
      End If
      
      If Not foundVertical Then
         Select Case top
         Case Is < testRange.top
            Set testRange = testRange.Offset(-1)
         Case Is > testRange.top + testRange.Height
            Set testRange = testRange.Offset(1)
         Case Else
            foundVertical = True
         End Select
      End If
   Loop
   
   GetCalloutValue = testRange.Value
End Function

You can use it like

=GETCALLOUTVALUE("ShapeName")

or if the shape is in another worksheet, just pass any range that belongs to that worksheet

=GETCALLOUTVALUE("ShapeName", Sheet2!A1)
 
Upvote 0
Thanks a lot for quick responses.

Juan: I made a small modification on the code. I changed the parentRange constraint to match with the whole program, and for the left position, I changed to "left = left + shp.Width * shp.Adjustments(1) - 80", so that the code return a value of a cell at exactly the end of the callout.

The code works just fine now. Again, thank you for your help =)
 
Upvote 0
Hi Bro,
I am very impressive with your code here.. I have the situation like that question and I realize your code can help me to do my purpose... But.. I am too new in VBA so I could not know how to use your code function to my project.. Can you help me to revised it to be direct SUB for me to run.. or you can help me explaining some needed things I have to prepare before running your code.

I am very appriciated your help.

Thanks Bro,


This function will work for Rectangular callouts, giving you the value of the cell where the callout ends.

Code:
Function GetCalloutValue(ByVal shapeName As String, _
                         Optional parentRange As Range, _
                         Optional volatile As Boolean = True) As Variant
   Dim shp As Excel.Shape
   Dim WS As Worksheet
   Dim top As Single
   Dim left As Single
   Dim testRange As Range
   Dim foundHorizontal As Boolean
   Dim foundVertical As Boolean
   
   Application.volatile volatile
   
   If Not parentRange Is Nothing Then
      Set WS = parentRange.Worksheet
   Else
      If TypeName(Application.Caller) = "Range" Then
         Set WS = Application.Caller.Worksheet
      Else
         GetCalloutValue = CVErr(xlErrNum)
         Exit Function
      End If
   End If
   
   On Error Resume Next
   Set shp = WS.Shapes(shapeName)
   On Error GoTo 0
   
   If shp Is Nothing Then
      GetCalloutValue = CVErr(xlErrValue)
      Exit Function
   End If
   
   'Only do for Rectangular Callout for now
   If shp.AutoShapeType <> msoShapeRectangularCallout Then
      GetCalloutValue = CVErr(xlErrValue)
      Exit Function
   End If
   
   'Get mid point of the rectangle
   top = shp.top + shp.Height / 2
   left = shp.left + shp.Width / 2
   
   'Adjustments(1) holds the number of "widths" where the callout ends
   left = left + shp.Width * shp.Adjustments(1)
   
   'Adjustments(2) holds the number of "heights" where the callout ends
   top = top + shp.Height * shp.Adjustments(2)
   
   'Now find the range that has those coordinates, starting from the TopLeftCell
   
   Set testRange = shp.TopLeftCell
   
   foundHorizontal = False
   foundVertical = False
   Do While Not (foundHorizontal And foundVertical)
      If Not foundHorizontal Then
         Select Case left
         Case Is < testRange.left
            Set testRange = testRange.Offset(, -1)
         Case Is > testRange.left + testRange.Width
            Set testRange = testRange.Offset(, 1)
         Case Else
            foundHorizontal = True
         End Select
      End If
      
      If Not foundVertical Then
         Select Case top
         Case Is < testRange.top
            Set testRange = testRange.Offset(-1)
         Case Is > testRange.top + testRange.Height
            Set testRange = testRange.Offset(1)
         Case Else
            foundVertical = True
         End Select
      End If
   Loop
   
   GetCalloutValue = testRange.Value
End Function

You can use it like

=GETCALLOUTVALUE("ShapeName")

or if the shape is in another worksheet, just pass any range that belongs to that worksheet

=GETCALLOUTVALUE("ShapeName", Sheet2!A1)
 
Upvote 0

Forum statistics

Threads
1,214,787
Messages
6,121,565
Members
449,038
Latest member
Guest1337

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top