简体中文
English 简体中文 繁體中文
Methodox 首页

脚本

脚本是一个 Command:在你运行时更改文档的 Lua、C# 或 Python 代码,其更改作为一个可撤消的步骤。脚本可在 Impulse、Formula、Expo 和 Nu 中从 Scripts 窗格或命令行运行。Divooka 图的 Routine 也是脚本,它会在同一窗格的图编辑器中打开。

Scripts 窗格

Tools ▸ Scripts(Alt+F11)会在底部托盘中打开 Scripts 选项卡:左侧是文档的脚本,中间是编辑器,右侧是 Output 和 Problems 选项卡。

Nu 的三角形圆环下方的 Scripts 选项卡,旁边是 Immediate 选项卡:列表中的 CircleOfTriangles.lua、带行号和语法着色的 Lua 编辑器,以及旁边的 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 中的一个值。关于退出代码,请参阅命令行与转换。