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