将 Applescript 移植到 Scripting Bridge:无法获取 Excel 2008 中的范围值

发布于 2024-10-06 04:11:27 字数 2412 浏览 10 评论 0原文

我需要将一些 Applescript 代码移动到 Scripting Bridge 以利用一些 Cocoa 挂钩,而不需要 Applescript-ObjC。

将 Excel 2008 与 Applescript 结合使用,获取范围的值很容易:

set myList to GetValuesFromColumnRange("A", 1, 100)

 on GetValuesFromColumnRange(ColumnLetter, FirstRow, LastRow) -- (string, integer, integer) as list
     set theList to {}
     tell application "Microsoft Excel"
         set theRange to ColumnLetter & FirstRow & ":" & ColumnLetter & LastRow
         set AppleScript's text item delimiters to {return}
         set theList to (get value of range theRange as list)
         set AppleScript's text item delimiters to {""}
     end tell
     set theList to ConvertItemizedListToValueList(theList) of me -- Note this dependency due to how MSE2008 returns the data
     return theList
 end GetValuesFromColumnRange

但在 Scripting Bridge 中,我在根据范围获取工作表的单元格时遇到问题。以下是我到目前为止所拥有的。

    Excel2008Application *excelApp = [SBApplication applicationWithBundleIdentifier:@"com.microsoft.Excel"];

    Excel2008Workbook *workbook = excelApp.activeWorkbook;

    SBElementArray *sheets = [workbook sheets];

    Excel2008Sheet *targetSheet;
    int thisSheet = 0;
    int lastSheet = [sheets count]; 

    for (thisSheet = 0; thisSheet < lastSheet; thisSheet++) {
        Excel2008Sheet *currentSheet = [sheets objectAtIndex:thisSheet];
        NSString *currentSheetName = currentSheet.name;
        if ([currentSheetName isEqualToString:@"Metadata"]) {
            targetSheet = currentSheet;
            [targetSheet retain];
        }
    }

    Excel2008Range *range = [[[excelApp classForScriptingClass:@"range"] alloc] initWithProperties:[NSDictionary dictionaryWithObjectsAndKeys:@"A1:A10", @"formulaR1c1", nil]];

    [[targetSheet ranges] addObject:range];
    range = [[targetSheet ranges] lastObject]; // not null; stated class in log: MicrosoftExcelRange

    Excel2008Sheet *valueSheet = range.worksheetObject; // supposed to be new worksheet based upon values within the range; not null; stated class in log: MicrosoftExcelSheet
    [valueSheet retain];

    SBElementArray *valueCells = [valueSheet cells]; // not null, but count is 0
    [valueCells retain];

问题出现在最后一行,当我实际从 valueSheet 获取单元格时,返回的 SBElementArray 不为 null,但它也不包含任何对象。获取 targetSheet 中的单元格也是如此。

从我所有的搜索中可以看出,执行此操作的文档并不存在,我已尽我所能。

I have a need to move some Applescript code to Scripting Bridge to take advantage of some Cocoa hooks without the need for Applescript-ObjC.

Using Excel 2008 with Applescript, getting the value of a range is easy:

set myList to GetValuesFromColumnRange("A", 1, 100)

 on GetValuesFromColumnRange(ColumnLetter, FirstRow, LastRow) -- (string, integer, integer) as list
     set theList to {}
     tell application "Microsoft Excel"
         set theRange to ColumnLetter & FirstRow & ":" & ColumnLetter & LastRow
         set AppleScript's text item delimiters to {return}
         set theList to (get value of range theRange as list)
         set AppleScript's text item delimiters to {""}
     end tell
     set theList to ConvertItemizedListToValueList(theList) of me -- Note this dependency due to how MSE2008 returns the data
     return theList
 end GetValuesFromColumnRange

But in Scripting Bridge, I'm having a problem getting the cells of a worksheet based on a range. The following is what I have so far.

    Excel2008Application *excelApp = [SBApplication applicationWithBundleIdentifier:@"com.microsoft.Excel"];

    Excel2008Workbook *workbook = excelApp.activeWorkbook;

    SBElementArray *sheets = [workbook sheets];

    Excel2008Sheet *targetSheet;
    int thisSheet = 0;
    int lastSheet = [sheets count]; 

    for (thisSheet = 0; thisSheet < lastSheet; thisSheet++) {
        Excel2008Sheet *currentSheet = [sheets objectAtIndex:thisSheet];
        NSString *currentSheetName = currentSheet.name;
        if ([currentSheetName isEqualToString:@"Metadata"]) {
            targetSheet = currentSheet;
            [targetSheet retain];
        }
    }

    Excel2008Range *range = [[[excelApp classForScriptingClass:@"range"] alloc] initWithProperties:[NSDictionary dictionaryWithObjectsAndKeys:@"A1:A10", @"formulaR1c1", nil]];

    [[targetSheet ranges] addObject:range];
    range = [[targetSheet ranges] lastObject]; // not null; stated class in log: MicrosoftExcelRange

    Excel2008Sheet *valueSheet = range.worksheetObject; // supposed to be new worksheet based upon values within the range; not null; stated class in log: MicrosoftExcelSheet
    [valueSheet retain];

    SBElementArray *valueCells = [valueSheet cells]; // not null, but count is 0
    [valueCells retain];

The problem comes with the last line, when I actually get the cells from valueSheet, in that the returned SBElementArray isn't null, but it also doesn't contain any objects. The same goes for getting the cells in targetSheet as well.

Documentation to do this, near as I can tell from all my searching, does not exist and I've taken this about as far as I can.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

笑看君怀她人 2024-10-13 04:11:27

解决了。

NSString *rangeName = @"A1:A10";

Excel2008Range *range = [[[excelApp classForScriptingClass:@"range"] alloc] initWithProperties:[NSDictionary dictionaryWithObjectsAndKeys:rangeName, @"name", nil]];
[[targetSheet ranges] addObject:range];

Excel2008Range *currentRange;
if ([[[targetSheet ranges] objectWithName:rangeName] exists]) {
    currentRange = [[targetSheet ranges] objectWithName:rangeName];
}

NSLog(@"[currentRange.value get] = %@", [currentRange.value get]);
// result: ((key),(1),(2),(3),(4),(5),(6),(7),(8),(9)) = NSArray

看来诀窍是将范围字符串设置到 Excel2008Rangename 属性中。我在处理此问题时发现的一个陷阱是永远不要填充范围的 formulaR1c1 — 如 [NSDictionary DictionaryWithObjectsAndKeys:rangeName, @"formulaR1c1", nil] —因为这将使用范围字符串的值填充范围。

中完全相同的命令的语法时,这实际上是有意义的

tell application "Microsoft Excel"
    set theValues to get value of range "A1:A10"
end tell

事后看来,当阅读 Applescript ... 和 objc-appscript

NSString *rangeString = @"A1:A10"
MEApplication *microsoftExcel = [MEApplication applicationWithName: @"Microsoft Excel"];
MEReference *cells = [[[microsoftExcel ranges] byName:rangeString] value];
NSArray *cellValues = [cells getItem];

...在这两种情况下,范围的值都是通过获取带有其名称的值范围来获得的。但对于 Scripting Bridge,据我所知,名称​​必须在创建范围对象时显式应用。

我确信有更好的方法来实现这一点(通常有),但至少这是有效的。

Solved.

NSString *rangeName = @"A1:A10";

Excel2008Range *range = [[[excelApp classForScriptingClass:@"range"] alloc] initWithProperties:[NSDictionary dictionaryWithObjectsAndKeys:rangeName, @"name", nil]];
[[targetSheet ranges] addObject:range];

Excel2008Range *currentRange;
if ([[[targetSheet ranges] objectWithName:rangeName] exists]) {
    currentRange = [[targetSheet ranges] objectWithName:rangeName];
}

NSLog(@"[currentRange.value get] = %@", [currentRange.value get]);
// result: ((key),(1),(2),(3),(4),(5),(6),(7),(8),(9)) = NSArray

It seems the trick is to set the range string into the name property of the Excel2008Range. The one pitfall I had found while working on this is to never populate the formulaR1c1 of the range—as in [NSDictionary dictionaryWithObjectsAndKeys:rangeName, @"formulaR1c1", nil]—because that will populate the range with the value of the range string.

In hindsight this actually makes sense when reading the syntax of the exact same command in both Applescript...

tell application "Microsoft Excel"
    set theValues to get value of range "A1:A10"
end tell

...and objc-appscript...

NSString *rangeString = @"A1:A10"
MEApplication *microsoftExcel = [MEApplication applicationWithName: @"Microsoft Excel"];
MEReference *cells = [[[microsoftExcel ranges] byName:rangeString] value];
NSArray *cellValues = [cells getItem];

In both cases the value of the range is gained by getting a range of values with its name. But with Scripting Bridge, near as I can tell, the name has to be applied explicitly upon creation of the range object.

I'm sure there is a better way of accomplishing this (there usually is), but at least this works.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文