脚本
脚本是一个 Command:在你运行时更改文档的 Lua、C# 或 Python 代码,其更改作为一个可撤消的步骤。脚本可在 Impulse、Formula、Expo 和 Nu 中从 Scripts 窗格或命令行运行。Divooka 图的 Routine 也是脚本,它会在同一窗格的图编辑器中打开。
Scripts 窗格
Tools ▸ Scripts(Alt+F11)会在底部托盘中打开 Scripts 选项卡:左侧是文档的脚本,中间是编辑器,右侧是 Output 和 Problems 选项卡。

列表
列表首先显示文档的函数脚本,然后是其 Command,再然后是其图文档,每项都带有表示其类型的图标和表示其语言的颜色。右键单击脚本,或使用以下按键,可以:
- 新建脚本:工具条上的 New script、
Insert或Ctrl+N,使用工具条列表中所选的语言(Lua、C# 或 Python),开头带有一行指明应用程序的代码; - 重命名:
F2; - 复制:
Ctrl+D; - 删除:
Delete,会先询问。
脚本保存到文档后,以上每项操作都是窗口 Edit ▸ Undo 中的一个步骤。
编辑器
编辑器为 Lua、C# 和 Python 提供语法着色和行号,突出显示插入点所在的行以及与其旁边括号相匹配的括号,并按照语言的代码块需要缩进新行。
Ctrl+Space提供根据对象模型生成的补全建议;输入.(在 Lua 中为:)也会提供补全建议。- 只要编辑器拥有键盘焦点,
Ctrl+F和Ctrl+H就会在脚本中(而不是在文档中)查找和替换;F3查找下一个匹配项。Ctrl+G转到某一行,Ctrl+/注释或取消注释所选的行,Tab和Shift+Tab增加和减少其缩进。 - 当你暂停输入时,脚本会被检查:错误会带下划线,悬停时显示其消息,并列在 Problems 选项卡中,单击即可转到该行。
运行
- Run(
Ctrl+Enter)针对打开的文档运行脚本;Ctrl+Shift+Enter只运行所选的行。按钮旁边的状态会说明运行耗时,或者说明运行失败并已回滚。 - 对于图文档,Run 旁边的列表用于选择要运行哪个 Routine。
- Save 把脚本作为可撤消的更改保存在文档中,由 File ▸ Save 写入磁盘;Export 把一份普通副本写入你选择的文件,即使文档从未保存过也可以。早期版本中的脚本文件夹(
<document name>.scripts\)会在文档打开时被纳入文档。 - Python environments and packages 按钮用于管理 Python 可以使用的包;参见 Python。
当脚本失败时,输出会指出文件、行和错误,编辑器会选中该行。一次运行是 Edit ▸ Undo 中的一个步骤,以脚本的名称标注,因此 Ctrl+Z 会撤回它所做的一切。
Smart Objects 选项卡也会列出文档的脚本,其中的 Show Definition 会打开计算某个单元格或智能对象的脚本。
即时模式
Tools ▸ Immediate 会打开 Immediate 选项卡。它是底部托盘中位于 Scripts 旁边的一个独立选项卡,因为它作用于文档,而不是正在编辑的脚本。它会立即针对窗口的文档运行你输入或粘贴的内容,可使用 Lua、C# 或 Python(在其列表中选择):用于查询文档、尝试某个调用,或在不编写脚本的情况下进行一次性编辑。
Enter运行该行,表达式的值会打印在其下方。Shift+Enter(或在 Python 中,以冒号结尾的行)会开始新的一行,Ctrl+Enter运行整个代码块。↑和↓逐条浏览你之前运行过的内容。- 某条输入定义的内容会保留给下一条输入使用,直到你更改语言或文档。
每条输入都是一个事务,因此按一次 Ctrl+Z 即可撤回。即时模式是你自己输入的内容,而不是文档的代码,因此在两个版本中都拥有完全访问权限:完整的语言、无需询问即可使用宿主的调用,在 Python 中还包括 .NET 桥接和你的环境中的包。
第一个脚本
-- Format all tables: thin grey borders, a shaded bold header row, and the header repeated at the top of every page the table runs onto.
local count = 0
for t in doc.tables do
t:setBorders({ style = "single", width = 0.5, color = "#7F7F7F" })
t:shadeRow(1, "#D9E2F3")
t:boldRow(1)
t.headerRows = 1
count = count + 1
end
print(string.format("Formatted %d table(s).", count))
用 C# 编写的相同脚本:
int count = 0;
foreach (Table table in Doc.Tables)
{
table.SetBorders(new Dictionary<string, object?> { ["style"] = "single", ["width"] = 0.5, ["color"] = "#7F7F7F" });
table.ShadeRow(1, "#D9E2F3");
table.BoldRow(1);
table.HeaderRows = 1;
count++;
}
Print($"Formatted {count} table(s).");
两者都是套件 Examples\Automation 文件夹中的示例:Impulse\FormatAllTables.lua 和 .csx、Formula\SummarySheet.lua(一个汇总工作表,其中包含来自第一个表格的实时合计)、Expo\DeckFromWorkbook.lua(为工作簿的每个工作表生成一张幻灯片),以及 Nu\CircleOfTriangles.lua 和 .py(一个三角形圆环,每个三角形都沿其半径方向旋转)。
对象模型
始终可用的名称有三个:app(应用程序)、doc(脚本所针对的文档)和 session(运行本身)。在 C# 中,它们是 App、Doc 和 Session,Doc 具有文档自身的类型,Print(...) 写入输出。在 Lua 中,成员采用 lowerCamel 形式(doc.sheets),方法使用 : 调用(t:boldRow(1)),集合使用 for x in collection do 遍历。在 Python 中,成员采用 snake_case 形式(sheet.used_range),print 写入输出。在每种语言中,计数都从 1 开始。
app 和 session
| 成员 | 说明 |
|---|---|
app.version |
Methodox Office 版本 |
app.arguments |
在命令行中给出的 --arg 值 |
app:open(path) |
打开另一个 .xlsx、.docx 或 .pptx;除非脚本保存它,否则在运行结束时会不保存而关闭 |
app:new(kind) |
一个新文档:"formula"、"impulse" 或 "expo" |
doc:save(), doc:saveAs(path), doc:close() |
保存或关闭脚本打开的文档 |
session.commands |
应用程序自身的命令;见下文 |
param.Name(C#:Param["Name"]) |
一个 Document Parameter |
host.get(url), host.getJson(url), host.getImage(url), host.readText(path)(C#:Host.Get 等) |
授予的网络和文件访问权限 |
Formula
| 对象 | 主要成员 |
|---|---|
doc(工作簿) |
sheets, names, tables, range("Sheet1!A1:C3"), calculate() |
| sheets | count, [1] 或 ["Sales"], find(name), add(name, before) |
| sheet | name(重命名会更新公式), range("A1:C3"), cells(row, column), usedRange, tables |
| range | value(填充区域), values(由值组成的行), formula(以相对引用填充), formulas, text(按显示内容), format, address, read(), write(values, { header = true }), offset(r, c), resize(r, c), currentRegion, clear() |
| range format | bold, italic, fontSize, numberFormat, fontColor, fill, horizontalAlignment |
| names | add(name, refersTo), remove(name), [name](带 refersTo 和 range) |
| tables | add(range, name, { style = "TableStyleMedium2" });表格具有 name, range, headerRange, dataRange, columns, rows()(按列名组织的记录), column(name) |
写入单元格的值就是值:作为值写入的 "=1+1" 是文本。公式通过 formula 和 formulas 写入,它们会在更改任何内容之前检查每个公式。
Impulse
| 对象 | 主要成员 |
|---|---|
doc(文档) |
paragraphs, tables, styles, text, find(text, { matchCase, wholeWord, regex }), replace(text, replacement, options), addTable(rows, columns, values), smartObjects |
| paragraphs | count, [i], last, add(text, style) |
| paragraph | text, style, alignment, spaceBefore 和 spaceAfter, lineSpacing, runs, characters(start, length), insertAfter, insertBefore, delete() |
| text range(一个文本段) | text, bold, italic, underline, fontName, fontSize, color, highlight |
| table | rowCount, columnCount, cell(r, c), read(), write(values), headerRows, style, setBorders(...), shadeRow(row, color), boldRow(row), delete() |
smartObjects |
参见智能对象 |
doc:replace 是一个撤消步骤,并返回替换的数量;使用 regex 时,替换文本中的 $1 表示第一个分组。
Expo
| 对象 | 主要成员 |
|---|---|
doc(演示文稿) |
slides, layouts, slideWidth, slideHeight(以磅为单位) |
| slides | count, [i], add(layout, at),使用布局名称,例如 "Title and Content" |
| slide | title, titleShape, bodyShape, shapes, placeholder(kind), notes, layout, background, duplicate(), moveTo(position), delete() |
| shapes | addTextBox(text, left, top, width, height), addShape(preset, left, top, width, height, text), addChart(kind, data, left, top, width, height, options), find(name) |
| shape | name, text, left, top, width, height, fill, bold, italic, fontSize, color, alignment, delete() |
| chart | setData(rows),它会保留每个系列的绘制方式,以及值范围、系列颜色和类别标签的位置 |
Nu
| 对象 | 主要成员 |
|---|---|
doc(绘图) |
pages, activePage, selection, layers, pageWidth, pageHeight, mm(millimetres)(将毫米换算为磅), describe(), count() |
| pages | count, [i] 或 ["Name"], find(name), add(name, at) |
| page | index, name, width, height, centerX, centerY, background, shapes, shapesAt(x, y), shapesIn(left, top, width, height), duplicate(), moveTo(position), delete() |
| shapes | count, [i] 或 ["Name"], find(name), all(), ofKind(kind), named(prefix), addShape(preset, left, top, width, height, text), addTextBox(text, left, top, width, height), addLine(x1, y1, x2, y2), addConnector(from, to, kind), group(shapes) |
| shape | name, kind, text, left, top, width, height, centerX, centerY, rotation, flipHorizontal, flipVertical, moveTo, moveBy, centerOn(x, y), resize, rotateBy(degrees), rotateAround(x, y, degrees), fill, fillOpacity, line, lineWidth, startArrow, endArrow, bold, italic, fontSize, fontName, color, alignment, hidden, layer, isGroup, children, ungroup(), isConnector, startShape, endShape, connectors, duplicate(dx, dy), bringToFront(), sendToBack(), bringForward(), sendBackward(), delete() |
位置和大小以磅为单位,从页面左上角开始计算;在两个形状之间添加的连接线会在它们移动时保持粘附。每次更改都是本次运行的那一个撤消步骤的一部分。
Impulse 文档还支持图片(doc:addPicture(at, bytes, width))、页边距,以及表格的列宽、内边距、边框、填充和对齐方式。对象模型中尚未提供:删除 Formula 工作表;Formula 和 Impulse 中的图表;域;Expo 演示文稿中尚不存在的布局;Nu 中的图片、表格和渐变。
调用应用程序的命令
菜单上的一切都是带有名称的命令,脚本可以调用它们:
session.commands:execute("format.bold")
print(session.commands:isAvailable("edit.undo"))
for id in session.commands:list() do print(id) end
describe(id) 列出命令的参数,execute 以表的形式接受这些参数。需要对话框或窗口选择内容的命令可以从 Scripts 窗格运行,但不能从在命令行上运行的脚本中运行,并会说明这一点。
事务
一次运行是一个事务。如果脚本失败,或它调用的命令被拒绝,本次运行所做的一切更改都会回滚,文档恢复原状;失败的运行所做的任何事情都无法被保存。读取能看到本次运行自己的写入:脚本写入某个单元格后,读取该单元格的公式会得到新值。在 Lua 中,pcall 可以捕获拒绝,运行会继续进行,因为被拒绝的操作不会更改任何内容。
从命令行运行
MethodoxFormula --script SummarySheet.lua --open Sales.xlsx --save-as Summary.xlsx
MethodoxExpo --script DeckFromWorkbook.lua --arg Sales.xlsx --save-as Sales.pptx
MethodoxNu --script CircleOfTriangles.py --save-as ring.pptx
mos --script FormatAllTables.lua --save-as Report-formatted.docx Report.docx
图 Routine 以相同方式运行,在其图文档名称之后指定:--script "Report.dvj#StampRegion"。--open(使用 mos 时则为最后指定的文档)是脚本所针对的文档;如果没有指定,脚本会得到一个新文档。--save-as 仅在脚本成功时保存结果;除非脚本本身调用 doc:save(),否则打开的文件永远不会被覆盖。每个 --arg 是 app.arguments 中的一个值。关于退出代码,请参阅命令行与转换。