关于delphi:自动化不同的本地化版本的Excel时如何正确设置NumberFormat属性

How to correctly set NumberFormat property when automating different localized versions of Excel

我遇到了以下问题:

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

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

这意味着千位分隔符为",",十进制分隔符为"。"。

实际上,我使用的是Excel的本地化版本。在我的语言环境中,千位分隔符为"",十进制分隔符为","。

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

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

谢谢!

更新:我在此页面上找到了一种更优雅的方法:
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=920


在Excel中,您有两个字段:

  • NumberFormat

  • NumberFormatLocal

NumberFormat采用美国标准中的区域设置始终为不变的格式,而NumberFormatLocal期望使用具有设置区域设置的格式。

例如

1
2
3
4
5
6
7
8
9
10
11
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):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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.VarDispInvoke进行调用,该ComObj.DispatchInvoke。在那里您找到对Dispatch.Invoke的调用,该调用将第三个参数作为lcid。设置为0。您可以使用注释的第一个链接中显示的技术来创建您自己的单元,并将所有代码从ComObj复制到您自己的单元(或直接修改ComObj)。只是不要忘记在单元初始化中设置VarDispProc变量。最后一部分似乎在所有情况下都不起作用(可能取决于模块的顺序),但是您可以在代码中设置变量:

1
 VarDispProc := @VarDispInvoke;

必须将VarDispInvoke放置在ComObj复制模块的接口部分中。
第一个链接的代码无法直接工作,因为它修改了上面的Delphi示例中未调用的其他方法。
并足以更改numberformat调用的语言环境(以避免产生副作用)。
上面的示例以及描述的修改适用于我的德语excel正确。如果不进行修改或不调用DispCallLocaleId,我将看到与您描述的问题相同的问题。


您也可以直接设置属性值

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

您可以让excel管理此选项,以避免其他系统出现差异:

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