来自Spreadsheetgear和Excel的RowHeight异常

本文关键字:RowHeight 异常 Excel Spreadsheetgear 来自 | 更新日期: 2023-09-27 18:07:55

我正在使用电子表格设备以编程方式制作excel,我有一个与行高度相关的问题。

我在c#中有这个代码片段

cells[0, 0].ColumnWidth = totalColumnWidth; // recalculated column width after some formatting logic
var x = cells[0, 0].RowHeight; // gives me 14.95
cells[0, 0].Formula = "A long long text goes here spanning multiple lines..."; // spanning say 10 rows in excel
x = cells[0, 0].RowHeight; // gives me 190.5

当我保存这个excel,并在MS excel中打开它时,我可以看到行高是210。

对于一个空的excel表,我从电子表格齿轮得到行高度为14.95,从excel得到15。列宽度也分别得到8.09和8.43。

我的问题是——为什么这两个数字的来源有区别?在处理这些问题时,我是否应该考虑某种蒙混因素?谢谢!

来自Spreadsheetgear和Excel的RowHeight异常

除非您显式地为某些行指定高度值(以点为单位),否则行高度将根据工作簿的默认字体的高度自动确定(参见IWorkbook.Styles["Normal"]. font)。

相对地,列宽以"字符单位"测量。字符单位不是绝对的度量单位;它们还依赖于工作簿的默认字体。这就是为什么要为列宽度指定8这样的值。使用工作簿的默认字体时,"字符单位"大致等于"0"字符的宽度。请注意,在此基础上添加了一些填充,因此您的实际列宽仍将略大于8个字符。

对于自动行高和列宽,SpreadsheetGear并不完全匹配Excel的单位,因为SpreadsheetGear依赖于GDI+/WPF/Silverlight图形库来测量字体的高度和"字符单位"值,而Excel使用原生GDI来测量这些东西。不幸的是,对于相同的给定文本,每个库计算的结果略有不同,因此您将在列宽和自动行高方面遇到细微的差异。除非SpreadsheetGear运行在与Excel完全相同的环境中(即使用GDI),否则这些差异是不可避免的。

当在SpreadsheetGear中自动拟合列时,这个问题经常出现。虽然带有自动适配文本的工作簿在我们自己的WorkbookView控件中可以很好地呈现,但将工作簿保存到磁盘,然后在Excel中打开生成的工作簿,通常会导致列略短。列的宽度越宽,这种情况就越明显。因此,当在Excel中查看工作簿时,客户通常不得不添加一个轻微的"蒙混因子"来获得预期的结果。

行高可以手动设置,以点为单位。所以,如果你不介意手动设置行高度不会改变,尽管单元格的内容,你可能会考虑显式地设置你的行高度,以适应Excel和SpreadsheetGear。

实际上,当使用我们的WorkbookView控件时,你会发现SpreadsheetGear在许多情况下比Excel更一致,因为我们使用了更可靠的字体指标。即使在Excel内部自动拟合时,不使用SpreadsheetGear,通过保存然后加载到具有不同屏幕DPI(96/120/等…)的机器上,也可能发生列宽度差异。另一个例子是,尝试在Excel 2007/2010/2013中输入一个很长的文本字符串到单元格中,自动适配文本,然后使用右下角的滑块工具放大或缩小,注意文本可能在某些设置下不适合(它会适合某些文本,但这种情况很少见)。这种不一致的行为不会在SpreadsheetGear中发生。

我对Tim的回答没有任何批评,我为他的回答点了赞,试图让他成为第一个答案。我同意他关于Excel不一致的评论,他关于SpreadsheetGear的评论显然是权威的。这个答案是额外的信息,如果你决定需要一个蒙混系数,它可能会很有用。

在Excel中,如果您将鼠标悬停在行边界上,您将看到行高度为12.75 (17 pixels)19.5 (26 pixels)或类似的东西。我已经尝试手动调整行高,并通过更改默认字体和/或大小。我找不到points * 4/3 = pixels不为真的任何行高

悬停在列边界上给出不同的值,如8.43 (64 points)11.52 (86 pixels)。点和像素值之间的关系是不同的,但仍然是固定的。下面的例程给出了从像素到点的转换,对于我尝试过的每个值都是正确的。程序是用VB编写的。如果你感兴趣的话,可以很容易地转换成c#。

Private Shared Function pixelsToPoints(ByVal pixels As Integer) As Double
  ' Converts a column width in pixels to points.
  '  Pixels   Points
  '       0      0.0
  ' 0<=N<12      points1(N)
  '      12      1.0
  '      19      2.0
  '      26      3.0
  '   N>=12      (N - 12) Mod 7 + 1 + points2((N - 12) ' 7)  
  ' Point increments between pixel = 2 and pixels = 11 
  Dim points1() As Double = {0.0, 0.08, 0.17, 0.25, 0.33, 0.42, 0.5, 0.58, 0.67, 0.75, 0.83, 0.92}
  ' Point increments above pixels = 12 
  Dim points2() As Double = {0.0, 0.14, 0.29, 0.43, 0.57, 0.71, 0.86}
  Select Case pixels
    Case Is < 12
      Return points1(pixels)
      Exit Function
    Case Is >= 12
      Dim pixelsTemp As Integer = pixels - 12
      Dim pointsTemp As Double = 1.0
      pointsTemp += (pixelsTemp) ' 7 + points2(pixelsTemp Mod 7)
      Return pointsTemp
      Exit Function
  End Select
  Return 0.0      ' Required to avoid warning
End Function