在单元格下面显示WinForm

我怎样才能展示我在VB.NET创build的活动单元格下面的winform?

我不知道如何解决这个问题。 我发现以下有前途的解决scheme: Excel插件:单元格的绝对位置

– 接受的解决scheme似乎太复杂,无法可靠地工作。 我得到了一个错误的第一行(私人声明函数GetDC Lib“user32”(ByVal hwnd只要)只要)

第二种解决scheme看起来很有前途,但是它并没有为我的窗体提供正确的位置。

第二个提出的解决scheme的下列修改不会产生任何错误,但不会将窗体放在正确的位置:

Public Sub GetScreenPositionFromCell(cell As Excel.Range, excel As Excel.Application) Dim x As Double Dim y As Double If Not excel.ActiveWindow Is Nothing Then x = excel.ActiveWindow.PointsToScreenPixelsX(cell.Left) y = excel.ActiveWindow.PointsToScreenPixelsY(cell.Top) End If Me.Left = x Me.Top = y Me.Show() Me.TopMost = True End Sub 

编辑 :@放大,这里是我如何使用你的代码。 这很好,我很高兴你花时间帮助我解决问题。 x坐标似乎工作,而x坐标是有点closures,取决于缩放级别或多或lessclosures。

  Public Sub ShowMeBelowActiveCell() Dim ExcelApp As Excel.Application = CType(AddinExpress.MSO.ADXAddinModule.CurrentInstance, AddinModule).ExcelApp Dim excelWindow = ExcelApp.ActiveWindow Dim cell = ExcelApp.ActiveCell Dim zoomFactor As Double = excelWindow.Zoom / 100 Dim ws = cell.Worksheet ' PointsToScreenPixels returns different values if the scroll is not currently 1 ' Temporarily set the scroll back to 1 so that PointsToScreenPixels returns a ' value we know how to handle. Dim origScrollCol = excelWindow.ScrollColumn Dim origScrollRow = excelWindow.ScrollRow excelWindow.ScrollColumn = 1 excelWindow.ScrollRow = 1 ' (x,y) are screen coordinates for the top left corner of the top left cell Dim x As Integer = excelWindow.PointsToScreenPixelsX(0) ' eg window.x + row header width Dim y As Integer = excelWindow.PointsToScreenPixelsY(0) ' eg window.y + ribbon height + column headers height Dim dpiX As Single = 0 Dim dpiY As Single = 0 Using g = Drawing.Graphics.FromHwnd(IntPtr.Zero) dpiX = g.DpiX dpiY = g.DpiY End Using ' Note: Each column width / row height has to be calculated individually. ' Before, tried to use this approach: ' var r2 = (Microsoft.Office.Interop.Excel.Range) cell.Worksheet.Cells[origScrollRow, origScrollCol]; ' double dw = cell.Left - r2.Left; ' double dh = cell.Top - r2.Top; ' However, that only works when the zoom factor is a whole number. ' A fractional zoom (eg 1.27) causes each individual row or column to round to the closest whole number, ' which means having to loop through. For i As Integer = origScrollCol To cell.Column - 1 Dim col = DirectCast(ws.Cells(cell.Row, i), Microsoft.Office.Interop.Excel.Range) Dim ww As Double = col.Width * dpiX / 72 Dim newW As Double = zoomFactor * ww x += CInt(Math.Round(newW)) Next For i As Integer = origScrollRow To cell.Row - 1 Dim row = DirectCast(ws.Cells(i, cell.Column), Microsoft.Office.Interop.Excel.Range) Dim hh As Double = row.Height * dpiY / 72 Dim newH As Double = zoomFactor * hh y += CInt(Math.Round(newH)) Next excelWindow.ScrollColumn = origScrollCol excelWindow.ScrollRow = origScrollRow Me.StartPosition = Windows.Forms.FormStartPosition.Manual Me.Location = New Drawing.Point(x, y) Me.Show() End Sub End Class 

ScrollColumnScrollRow都为1时,则PointsToScreenPixelsX/Y似乎返回屏幕坐标中左上angular可见单元格的左上angular点。 使用这个,计算活动单元的偏移宽度和高度,并考虑缩放设置。

  var excelApp = Globals.ThisAddIn.Application; var excelWindow = excelApp.ActiveWindow; var cell = excelApp.ActiveCell; double zoomFactor = excelWindow.Zoom / 100; var ws = cell.Worksheet; var ap = excelWindow.ActivePane; // might be split panes var origScrollCol = ap.ScrollColumn; var origScrollRow = ap.ScrollRow; excelApp.ScreenUpdating = false; // when FreezePanes == true, ap.ScrollColumn/Row will only reset // as much as the location of the frozen splitter ap.ScrollColumn = 1; ap.ScrollRow = 1; // PointsToScreenPixels returns different values if the scroll is not currently 1 // Temporarily set the scroll back to 1 so that PointsToScreenPixels returns a // value we know how to handle. // (x,y) are screen coordinates for the top left corner of the top left cell int x = ap.PointsToScreenPixelsX(0); // eg window.x + row header width int y = ap.PointsToScreenPixelsY(0); // eg window.y + ribbon height + column headers height float dpiX = 0; float dpiY = 0; using (var g = Graphics.FromHwnd(IntPtr.Zero)) { dpiX = g.DpiX; dpiY = g.DpiY; } int deltaRow = 0; int deltaCol = 0; int fromCol = origScrollCol; int fromRow = origScrollRow; if (excelWindow.FreezePanes) { fromCol = 1; fromRow = 1; deltaCol = origScrollCol - ap.ScrollColumn; // Note: ap.ScrollColumn/Row <> 1 deltaRow = origScrollRow - ap.ScrollRow; // see comment: when FreezePanes == true ... } // Note: Each column width / row height has to be calculated individually. // Before, tried to use this approach: // var r2 = (Microsoft.Office.Interop.Excel.Range) cell.Worksheet.Cells[origScrollRow, origScrollCol]; // double dw = cell.Left - r2.Left; // double dh = cell.Top - r2.Top; // However, that only works when the zoom factor is a whole number. // A fractional zoom (eg 1.27) causes each individual row or column to round to the closest whole number, // which means having to loop through. for (int i = fromCol; i < cell.Column; i++) { // skip the columns between the frozen split and the first visible column if (i >= ap.ScrollColumn && i < ap.ScrollColumn + deltaCol) continue; var col = ((Microsoft.Office.Interop.Excel.Range) ws.Cells[cell.Row, i]); double ww = col.Width * dpiX / 72; double newW = zoomFactor * ww; x += (int) Math.Round(newW); } for (int i = fromRow; i < cell.Row; i++) { // skip the columns between the frozen split and the first visible column if (i >= ap.ScrollRow && i < ap.ScrollRow + deltaRow) continue; var row = ((Microsoft.Office.Interop.Excel.Range) ws.Cells[i, cell.Column]); double hh = row.Height * dpiY / 72; double newH = zoomFactor * hh; y += (int) Math.Round(newH); } ap.ScrollColumn = origScrollCol; ap.ScrollRow = origScrollRow; excelApp.ScreenUpdating = true; Form f = new Form(); f.StartPosition = FormStartPosition.Manual; f.Location = new Point(x, y); f.Show();