【问题标题】:How to correctly set NumberFormat property when automating different localized versions of Excel自动化不同本地化版本的 Excel 时如何正确设置 NumberFormat 属性
【发布时间】:2012-06-12 10:43:36
【问题描述】:

我遇到了以下问题:

在我的 Delphi 程序中通过 OLE 自动执行 Excel 并尝试设置单元格的 NumberFormat 属性时,Excel 需要本地化格式的格式字符串。

通常,当通过在 Excel 中记录宏来检查格式时,Excel 期望它是这样的: Cells(1, 2).NumberFormat = "#,##0.00"

也就是说千位分隔符是“,”,小数分隔符是“.”。

实际上,我使用的是本地化版本的 Excel。在我的语言环境中,千位分隔符是“”,小数点分隔符是“,”。

因此,每当从我的 Delphi 程序中设置 NumberFormat 时,我都需要将其指定为“# ##0,00”。

我的问题是:显然,如果我在我的程序中对这些值进行硬编码,那么当我的程序与英语或其他不同本地化版本的 Excel 一起使用时,就会出现异常。是否有设置 NumberFormat 属性的“通用”方法? (使用默认的英语语言环境?)

谢谢!

更新:我在此页面上找到了一种更优雅的方法: http://www.delphikingdom.com/asp/viewitem.asp?catalogid=920&mode=print 它是俄语的(我也不会说),但您可以轻松理解代码。

【问题讨论】:

  • 在 Delphi 中,您可以使用 ThousandSeparator、DecimalSeparator 和 GetLocaleFormatSettings() 函数。它们在 SysUtils.pas 中声明
  • 没关系,但我需要根据本地化版本的 Excel 调整这些设置,而不是 Windows 区域设置...
  • 您可以根据Globalization and Localization of Excel Solutions使用US LCID 1033
  • 您能否举一个使用 Delphi 的工作示例,用于在非美国版 Excel 上设置 LCID 1033 中的 NumberFormat?

标签: delphi excel automation ole number-formatting


【解决方案1】:

在 Excel 中有两个字段:

  • 数字格式

  • NumberFormatLocal

NumberFormat 采用美国标准中始终保持语言环境不变的格式,而 NumberFormatLocal 需要具有设置语言环境的格式。

例如

Sub test()
    Dim r As Range
    Set r = ActiveWorkbook.ActiveSheet.Range("$A$1")
    r.NumberFormat = "#,##0.00"
    Set r = ActiveWorkbook.ActiveSheet.Range("$A$2")
    r.NumberFormat = "#.##0,00"
    Set r = ActiveWorkbook.ActiveSheet.Range("$A$3")
    r.NumberFormatLocal = "#,##0.00"
    Set r = ActiveWorkbook.ActiveSheet.Range("$A$4")
    r.NumberFormatLocal = "#.##0,00"       
End Sub

使用德语设置(十进制 sep: 和千位 sep: .)为 $A$1 和 $A$4 提供正确格式的数字。如果您将 Windows 中的区域设置更改为您喜欢的任何内容,您可以对其进行测试,然后尝试,如果您的格式有效。

假设您使用 Delphi 5 并且有这样的代码来启动 Excel(并且可以访问 ComObj.pas):

var
  oXL, oWB, oSheet : Variant;
 LocaleId : Integer;
begin
 oXL := CreateOleObject('Excel.Application');
 oXL.Visible := True;
 oWB := oXL.Workbooks.Add;
 oSheet := oWB.ActiveSheet;
 oSheet.Range['$A$1'].NumberFormatLocal := '#.##0,00';
 oSheet.Range['$A$2'].NumberFormatLocal := '#,##0.00';
 LocaleID:= DispCallLocaleID($0409);
 try
    oSheet.Range['$A$3'].NumberFormat := '#.##0,00';
    oSheet.Range['$A$4'].NumberFormat := '#,##0.00';
 finally
    DispCallLocaleId( LocaleId);
 end;
end;

然后默认情况下,每个调用都通过调用 ComObj.DispatchInvoke 的 ComObj.VarDispInvoke。在那里,您可以找到对 Dispatch.Invoke 的调用,该调用将 lcid 作为第三个参数。这设置为 0。您可以使用注释中第一个链接中显示的技术来创建您自己的单元并将所有代码从 ComObj 复制到您自己的单元(或直接修改 ComObj)。只是不要忘记在单元的初始化中设置 VarDispProc 变量。最后一部分似乎并非在所有情况下都有效(可能取决于模块的顺序),但您可以在代码中设置变量:

 VarDispProc := @VarDispInvoke;

您必须将 VarDispInvoke 放入 ComObj 复制模块的接口部分的位置。 第一个链接的代码不能直接工作,因为它修改了上述 Delphi 示例中未调用的不同方法。
更改 numberformat 调用的语言环境就足够了(以避免副作用)。
上面的示例以及所描述的修改适用于我的德语 excel 正确。在没有修改或调用 DispCallLocaleId 的情况下,我看到了与您描述的相同的问题。

【讨论】:

  • 您好!显然,当通过 COM NumberFormat 自动化 Excel 时等于 NumberFormatLocal。如果您在 VBA 中尝试它,它当然可以工作。但是在 Delphi(或者可能来自 C#)中尝试同样的方法,你就会明白我在说什么。我希望有一个解决方法...
  • 好的,在我看来,你必须在调用中修改语言环境。我不知道,您使用的是哪个 Delphi,两个链接可能会对您有所帮助(我没有尝试过):link Old Delphi without .NET link with .NET(C#,但我想这会在 Delphi 中是一样的)
  • 感谢 Stefan 的解决方案。我不想使用它的原因是它需要将一些未知的汇编代码放入修改后的 ComObj。这些天来,当 64 位支持到达 Delphi 并且 ARM 可能即将到来时,我想避免这样的举动。我在俄罗斯网站上找到了另一个解决方案,你可以看到我的编辑。我唯一不知道的是,为什么 Excel 会在我的本地货币格式中添加“\”?即:它看起来像这样:“###0,00\ [$EUR]”而不是“###0,00 [$EUR]”有什么想法吗?
  • 在普通的 Excel 中不一样吗?如果我正确阅读 [office.microsoft.com/en-us/excel-help/…(办公室帮助),则使用空格或反斜杠空格都没关系。是一样的。
  • 另一点:至少在我的示例中,没有必要修改汇编代码(与俄罗斯解决方案不同)。而且我不需要直接修改 ComObj.pas,当然,我必须复制一些代码。虽然,我永远不会使用这样的解决方案(更多的是一些学术问题:可以做到吗?),因为如果你忘记在某个地方设置语言环境,它很容易导致(小)缺陷。由于这只影响数字在某些表格中的显示方式,我想,在测试中很难注意到这一点。
【解决方案2】:

您可以让excel管理这个选项以避免在其他系统中的差异:

.....NumberFormat :='#'+Excel.ThousandsSeparator+'##0'+Excel.DecimalSeparator+'00';

【讨论】:

    【解决方案3】:

    也可以直接设置属性值

     SetDispatchPropValue(oSheet, 
         'Range['$A$1'].NumberFormatLocal',$0409);
    

    【讨论】:

      猜你喜欢
      • 2012-03-26
      • 2022-01-13
      • 1970-01-01
      • 1970-01-01
      • 2020-12-27
      • 2015-05-05
      • 1970-01-01
      • 1970-01-01
      • 2021-09-29
      相关资源
      最近更新 更多