Reputation: 497
How can I find the absolute coordinates in pixels of a certain cell?
I am developing an Office 2010 addon (the Ribbon UI) and I add a new button to a new menu in the Ribbon and when the button is pressed, I want to get the screen position of that cell. The problem is that
Globals.ThisWorkbook.Application.ActiveCell . Top / Left
only give the position relative to the A1
corner of the spreadsheet, while I want the position relative to 0,0 of the screen.
I found this: How to get screen X and Y of an Excel 2003 cell in C# but it's for Office 2003 and I don't fully understand the answer.
I'm using C# for devel, but VB will also do.
Thanks!
Upvotes: 2
Views: 5003
Reputation: 41
I found this to work without any kind of hackery:
Point GetScreenPositionFromCell(Excel.Range cell, Excel.Application excel)
{
var wnd = excel.ActiveWindow;
if (wnd != null)
{
var result = new Point
{
X = wnd.PointsToScreenPixelsX((int)cell.Left),
Y = wnd.PointsToScreenPixelsY((int)cell.Top)
};
//cleanup
Marshal.ReleaseComObject(wnd);
wnd = null;
return result;
}
throw new Exception("Error retrieving active Excel-window.");
}
Upvotes: 4
Reputation: 27478
I found this post, which contains the API calls used below. I also was reminded that you can get the height of the ribbon with Application.Commandbars("Ribbon").Height. So, in VBA you'd do:
EDIT: In response the Formula Bar and Headings height issue I added a function that hides them, gets the ActiveWindow.Height, then shows them and gets the new ActiveWindow.Height and figures the difference. That function now gets called in the line below that adds together the heights before converting. I think it works but I didn't do a lot of testing.
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 Const LOGPIXELSX As Long = 88
Private Const LOGPIXELSY As Long = 90
Sub CellTopLeftPixels(rng As Excel.Range)
Dim RibbonHeight As Long
Dim TotalTop As Long
Dim TotalLeft As Long
RibbonHeight = Application.CommandBars("Ribbon").Height
TotalTop = (RibbonHeight + GetFormulaBarAndHeadingsHeight + rng.Top) * PixelsPerPointY
TotalLeft = rng.Left * PixelsPerPointX
Debug.Print "Top: "; TotalTop; " Left: "; TotalLeft
End Sub
Function GetFormulaBarAndHeadingsHeight()
Dim ActiveWindowHeightWhenHidden As Long
Dim ActiveWindowHeightWhenShown As Long
Application.DisplayFormulaBar = False
ActiveWindow.DisplayHeadings = False
ActiveWindowHeightWhenHidden = ActiveWindow.Height
Application.DisplayFormulaBar = True
ActiveWindow.DisplayHeadings = True
ActiveWindowHeightWhenShown = ActiveWindow.Height
GetFormulaBarAndHeadingsHeight = ActiveWindowHeightWhenHidden - ActiveWindowHeightWhenShown
End Function
Function PixelsPerPointX() As Double
Dim hdc As Long
Dim PixPerInchX As Long
hdc = GetDC(0)
PixPerInchX = GetDeviceCaps(hdc, LOGPIXELSX)
PixelsPerPointX = PixPerInchX / 72
ReleaseDC 0, hdc
End Function
Function PixelsPerPointY() As Double
Dim hdc As Long
Dim PixPerInchY As Long
hdc = GetDC(0)
PixPerInchY = GetDeviceCaps(hdc, LOGPIXELSY)
PixelsPerPointY = PixPerInchY / 72
ReleaseDC 0, hdc
End Function
The 72 above is the points per inch.
Call it like:
Sub test()
CellTopLeftPixels ActiveCell
End Sub
Upvotes: 4