Vb.net 在单元格下方显示WinForm

Vb.net 在单元格下方显示WinForm,vb.net,excel,winforms,Vb.net,Excel,Winforms,如何在活动单元格下方显示我在VB.NET中创建的winform 我不知道怎么解决这个问题。我发现了以下有希望的解决方案: -公认的解决方案似乎过于复杂,无法可靠地工作。第一行出现错误(私有声明函数GetDC Lib“user32”(ByVal hwnd As Long)As Long) -第二个解决方案看起来很有希望,但它没有为我的windows窗体提供正确的位置 第二个建议的解决方案的以下修改不会产生任何错误,但不会将windows窗体置于正确的位置: Public Sub GetS

如何在活动单元格下方显示我在VB.NET中创建的winform

我不知道怎么解决这个问题。我发现了以下有希望的解决方案:

-公认的解决方案似乎过于复杂,无法可靠地工作。第一行出现错误(私有声明函数GetDC Lib“user32”(ByVal hwnd As Long)As Long)

-第二个解决方案看起来很有希望,但它没有为我的windows窗体提供正确的位置

第二个建议的解决方案的以下修改不会产生任何错误,但不会将windows窗体置于正确的位置:

    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
编辑:@Loating,以下是我如何使用您的代码。这很好,我很高兴你能抽出时间来帮助我解决问题。x坐标似乎起作用,而x坐标有点偏离,并且根据缩放级别或多或少偏离

    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)
        ' e.g. window.x + row header width
        Dim y As Integer = excelWindow.PointsToScreenPixelsY(0)
        ' e.g. 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 (e.g. 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

ScrollColumn
ScrollRow
均为1时,则
PointsToScreenPixelsX/Y
似乎返回屏幕坐标中左上可见单元格的左上角点。使用此选项,将计算活动单元格的偏移宽度和高度,同时考虑缩放设置

        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); // e.g. window.x + row header width
        int y = ap.PointsToScreenPixelsY(0); // e.g. 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 (e.g. 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();
var excelApp=Globals.ThisAddIn.Application;
var excelWindow=excelApp.ActiveWindow;
var cell=excelApp.ActiveCell;
双zoomFactor=excelWindow.Zoom/100;
var-ws=cell.Worksheet;
var ap=excelWindow.ActivePane;//可能是拆分窗格
var origScrollCol=ap.scroll列;
var origScrollRow=ap.ScrollRow;
excelApp.ScreenUpdate=false;
//当冻结窗格==true时,ap.ScrollColumn/Row将仅重置
//和冻结分离器的位置一样多
ap.column=1;
ap.ScrollRow=1;
//如果滚动当前不是1,则PointsToScreenPixels返回不同的值
//暂时将滚动设置回1,以便PointsToScreenPixels返回
//我们知道如何处理价值。
//(x,y)是左上角单元格的屏幕坐标
int x=ap.pointstoscreenspixelsx(0);//e、 g.窗口.x+行标题宽度
int y=ap.pointstoscreenspixelsy(0);//e、 g.窗口.y+功能区高度+列标题高度
浮点数dpiX=0;
浮点dpiY=0;
使用(var g=Graphics.FromHwnd(IntPtr.Zero)){
dpiX=g.dpiX;
dpiY=g.dpiY;
}
int deltaRow=0;
int-deltaCol=0;
int fromCol=origScrollCol;
int fromRow=origScrollRow;
如果(Excel窗口。冻结窗格){
fromCol=1;
fromRow=1;
deltaCol=origScrollCol-ap.ScrollColumn;//注意:ap.ScrollColumn/Row 1
deltaRow=origScrollRow-ap.ScrollRow;//请参阅注释:当冻结窗格==true时。。。
}
//注:每个列宽/行高必须单独计算。
//在此之前,尝试使用此方法:
//var r2=(Microsoft.Office.Interop.Excel.Range)cell.Worksheet.Cells[origscrolrow,origScrollCol];
//双dw=单元格左-r2.左;
//双dh=cell.Top-r2.Top;
//但是,这仅在缩放因子为整数时有效。
//分数缩放(例如1.27)会使每一行或每一列四舍五入到最接近的整数,
//这意味着必须循环通过。
for(int i=fromCol;i=ap.ScrollColumn&&i=ap.ScrollRow&&i
我们看不到您的屏幕,位置有多远?很远。当cell.left大约为1000时,x变成-600。这个答案没用,它告诉你窗口在哪里,而不是单元格。啊哈,好的。有什么解决办法吗?谢谢!我试过放大和缩小一点,x坐标似乎总是正确的。但是,y坐标不正确,y坐标与活动单元格的差异似乎也会受到缩放的影响。我上传了一个屏幕截图,您可以看到它的不同之处:更改为我。位置=新图形。点(x,y+330+(zoomFactor-1)*365)在我的计算机上的所有缩放级别上给出了大致正确的位置。我不知道这是什么原因。您的工作表是否使用冻结顶行?我注意到当有一个拆分行时,
pointstoscreenspexels
不会返回预期的(x,y)。你说得对!这与冰冻的玻璃有关。无论用户是否冻结了窗格,是否可以修改工作以使其工作?@user1283776我已更新了代码。它应该使用
ActivePane
上的
pointstoscreenspexels