通过 Delphi 在 OpenOffice Calc 中排序

Sorting in OpenOffice Calc via Delphi

我花了几个小时试图在 Delphi 中对 OpenOffice Calc 中的数据进行排序。我尝试按照基本示例(来自“OpenOffice.org Macros Explained”*)或 C# 进行操作,但仍然没有结果。数据根本不会改变。我究竟做错了什么? 也许问题出在数据类型上?

*https://www.pitonyak.org/OOME_3_0.pdf,第 488 页。

最小可重现示例:

program OpenOfficeCalcSortingIssue;

{$APPTYPE CONSOLE}

uses
  System.SysUtils, Variants, ComObj, ActiveX;

var
  StarOffice:     OleVariant;
  SODesktop:      OleVariant;
  SOCalc:         OleVariant;
  CalcSheets:     OleVariant;
  CalcSheet:      OleVariant;
  SortFields:     OleVariant;
  SortDescriptor: OleVariant;

begin
  CoInitialize(nil);
  try
    try
      StarOffice:=CreateOleObject('com.sun.star.ServiceManager');
      SODesktop:=StarOffice.CreateInstance('com.sun.star.frame.Desktop');
      SOCalc:=SODesktop.LoadComponentFromURL('private:factory/scalc', '_blank', 0, VarArrayCreate([0, -1], varVariant));
      CalcSheets:=SOCalc.GetSheets;
      CalcSheet:=CalcSheets.GetByIndex(0);

      CalcSheet.GetCellByPosition(0, 0).SetValue(2);
      CalcSheet.GetCellByPosition(0, 1).SetValue(1);
      CalcSheet.GetCellByPosition(0, 2).SetValue(4);
      CalcSheet.GetCellByPosition(0, 3).SetValue(3);

      SortFields:=VarArrayCreate([0, 0], varVariant);
      SortFields[0]:=StarOffice.Bridge_GetStruct('com.sun.star.util.SortField');
      SortFields[0].Field:=0;
      SortFields[0].SortAscending:=True;

      SortDescriptor:=VarArrayCreate([0, 0], varVariant);
      SortDescriptor[0]:=StarOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
      SortDescriptor[0].Name:='SortFields';
      SortDescriptor[0].Value:=SortFields;

      CalcSheet.GetCellRangeByName('A1:A4').Sort(SortDescriptor);
    except
      on E: Exception do
        Writeln(E.ClassName, ': ', E.Message);
    end;
  finally
    CoUninitialize;
  end;
end.

像往常一样,解决方案在向世界公开问题后不久就出现了:-)我从互联网深处找到了一个例子。希望这个关于 SO 的主题将被偶然发现这个问题的人更容易地用谷歌搜索。 答案是:SortFields 不仅仅是一个变量数组。它是一个“值对象”,必须这样设置:

ValueObject:=StarOffice.Bridge_GetValueObject;
ValueObject.Set('[]com.sun.star.table.TableSortField', SortFields);

在我发现的示例中,它被注释为“您必须指定将哪种类型的序列传输到 SortFields 属性”。

所以整个代码应该是:

      StarOffice:=CreateOleObject('com.sun.star.ServiceManager');
      SODesktop:=StarOffice.CreateInstance('com.sun.star.frame.Desktop');
      SOCalc:=SODesktop.LoadComponentFromURL('private:factory/scalc', '_blank', 0, VarArrayCreate([0, -1], varVariant));
      CalcSheets:=SOCalc.GetSheets;
      CalcSheet:=CalcSheets.GetByIndex(0);

      CalcSheet.GetCellByPosition(0, 0).SetValue(2);
      CalcSheet.GetCellByPosition(0, 1).SetValue(1);
      CalcSheet.GetCellByPosition(0, 2).SetValue(4);
      CalcSheet.GetCellByPosition(0, 3).SetValue(3);

      SortFields:=VarArrayCreate([0, 0], varVariant);
      SortFields[0]:=StarOffice.Bridge_GetStruct('com.sun.star.table.TableSortField');
      SortFields[0].Field:=0;
      SortFields[0].IsAscending:=True;

      ValueObject:=StarOffice.Bridge_GetValueObject;
      ValueObject.Set('[]com.sun.star.table.TableSortField', SortFields);

      SortDescriptor:=VarArrayCreate([0, 0], varVariant);
      SortDescriptor[0]:=StarOffice.Bridge_GetStruct('com.sun.star.beans.PropertyValue');
      SortDescriptor[0].Name:='SortFields';
      SortDescriptor[0].Value:=ValueObject;

      CalcSheet.GetCellRangeByName('A1:A4').Sort(SortDescriptor);