I want to develop a GIS type drawing window where the user can draw circle, lines and Plines based on selection.
Additional issue is the user can only draw on top of a picture (used as background).
I have been searching for a code that i can use specifically to solve the problem of inserting a shape at the mouse cursor location on top of an image. Found the following solutions both using PointAPI:
Thanks
Additional issue is the user can only draw on top of a picture (used as background).
I have been searching for a code that i can use specifically to solve the problem of inserting a shape at the mouse cursor location on top of an image. Found the following solutions both using PointAPI:
- Range is selected under the pic and shape is inserted at the selected range - this works well but the image has to be made invisible very briefly to achieve it. I dont want the image to blink during the process
- Cursor X and Y locations in excel are found using a combination of screen resolution and relative position of cursor in Excel window - This is closer to what i want as i am not having to select a range but the issue is the shape is not inserted at the precise location. Its some distance away. This distance increases when i click further away from the top left of the image. I found some zoom corrections but none of them seems to work perfectly.
Thanks
VBA Code:
Option Explicit
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long
Private Declare Function GetDeviceCaps Lib "gdi32" (ByVal hdc As Long, ByVal nIndex As Long) As Long
Private Declare Function GetCursorPos Lib "user32" (lpPoint As POINTAPI) As Long
Private Type POINTAPI
x As Long
y As Long
End Type
'GetDeviceCaps function
'http://msdn.microsoft.com/en-us/library/windows/desktop/dd144877%28v=vs.85%29.aspx
Private Const LOGPIXELSX As Long = 88&
Private Const LOGPIXELSY As Long = 90&
'Size of shape's bounding box in points
Private Const SHAPE_WIDTH = 5
Private Const SHAPE_HEIGHT = 5
Public Sub Add_Shape_At_Cursor_Position()
Dim hdc As Long
Dim PointsPerPixelX As Double, PointsPerPixelY As Double
Dim CursorPos As POINTAPI
Dim ExcelPos As POINTAPI
Dim ShapePos As POINTAPI
Dim z As Double
Const LOGPIXELSX As Long = 88
Const LOGPIXELSY As Long = 90
'Get number of points per screen pixel, depending on screen device size
hdc = GetDC(0)
PointsPerPixelX = 72 / GetDeviceCaps(hdc, LOGPIXELSX)
PointsPerPixelY = 72 / GetDeviceCaps(hdc, LOGPIXELSY)
ReleaseDC 0, hdc
'Scale points per pixel according to current window zoom. The smaller the zoom, the higher the number of points per pixel
PointsPerPixelX = PointsPerPixelX '* 100 / ActiveWindow.Zoom
PointsPerPixelY = PointsPerPixelY '* 100 / ActiveWindow.Zoom
'Get position of Excel window in screen pixels
z = CorrectZoomFactor(ActiveWindow.Zoom / 100)
ExcelPos.x = ActiveWindow.PointsToScreenPixelsX(0)
ExcelPos.y = ActiveWindow.PointsToScreenPixelsY(0)
'Get mouse cursor position in screen pixels
GetCursorPos CursorPos
'Set shape position according to mouse position relative to Excel window position, scaled to the
'number of points per pixel. Since the AutoShape's position is defined by the top left corner
'of its bounding box, subtract half the shape's size to centre it over the mouse
ShapePos.x = (CursorPos.x - ExcelPos.x) * PointsPerPixelX / z - SHAPE_WIDTH / 2
ShapePos.y = (CursorPos.y - ExcelPos.y) * PointsPerPixelY / z - SHAPE_HEIGHT / 2
ActiveSheet.Shapes.AddShape msoShapeOval, ShapePos.x, ShapePos.y, SHAPE_WIDTH, SHAPE_HEIGHT
End Sub
Function CorrectZoomFactor(ByVal z As Single) As Single
Select Case z
Case 2
z = 2
Case 1.75
z = 1.765
Case 1.5
z = 1.529
Case 1.25
z = 1.235
Case 1
z = 1
Case 0.9
z = 0.882
Case 0.85
z = 0.825
Case 0.8
z = 0.82
Case 0.75
z = 0.74
Case 0.7
z = 0.705
Case 0.65
z = 0.645
Case 0.6
z = 0.588
Case 0.55
z = 0.53
Case 0.5
z = 0.5296
Case Else
z = 1.0069 * z + 0.0055
End Select
CorrectZoomFactor = z
End Function