app.progress - 进度对话框 API

显示和控制进度对话框。

权限:L0 安全 — 无需声明,始终可用

整个模块只有一个入口:app.progress.create(config) 创建对话框并返回一个句柄, 之后所有操作都是句柄上的方法。

local p = app.progress.create({ title = "处理中" })
p:update(50, "已完成一半")
p:close()

句柄方法要用冒号调用(p:update(...)),不是点号。

app.progress.create(config)

创建并显示一个进度对话框。

参数:

  • config (table):
    • title (string, 必需) - 对话框标题
    • message (string) - 详细消息,默认空
    • indeterminate (boolean) - 是否为不确定进度(默认 true,显示来回滚动的条)
    • cancellable (boolean) - 是否显示取消按钮(默认 false
    • onCancel (function) - 用户点取消时的回调

返回值: progressHandle - 进度句柄;失败时返回 nil, error

local p, err = app.progress.create({
    title = "下载文件",
    message = "准备中...",
    indeterminate = false,
    cancellable = true,
    onCancel = function()
        app.log.info("下载已取消")
    end
})
if not p then
    app.log.error("创建进度对话框失败: " .. tostring(err))
    return
end

没传 title 会直接失败——它是唯一的必需字段。

句柄方法

handle:update(value, message?)

更新进度值和消息。

参数:

  • value (number) - 进度值,范围 0–100(不是 0–1)
  • message (string, 可选) - 同时更新消息文本
for i = 1, #files do
    p:update(i * 100 / #files, "处理: " .. app.path.basename(files[i]))
end

调用 update() 会把不确定进度切换成确定进度。 即使创建时 indeterminate = true,第一次 update() 之后滚动条就变成按 value 走的实心条。 想一直保持不确定状态,就只用 setMessage() 别用 update()

handle:setMessage(message)

只更新消息文本,不动进度值,也不会把不确定进度切成确定进度。

参数:

  • message (string) - 新消息
p:setMessage("正在执行步骤 2...")

handle:isCancelled()

查询用户有没有点过取消。需要创建时 cancellable = true

返回值: boolean

if p:isCancelled() then
    p:close()
    return
end

handle:close()

关闭对话框。

p:close()

两种处理取消的方式

cancellable = true 之后有两条路,按循环的形状挑:

轮询 isCancelled() —— 适合有明确循环的批处理,退出点看得见:

for i = 1, 100 do
    if p:isCancelled() then break end
    p:update(i, "步骤 " .. i)
end

onCancel 回调 —— 适合没有循环可插入检查的场合(等待某个异步结果时):

local cancelled = false
local p = app.progress.create({
    title = "长时间操作",
    cancellable = true,
    onCancel = function() cancelled = true end
})

两者可以混用,但没必要——挑一个就好。

完整示例

批量处理文件

function MyPlugin:handleBatchProcess(context)
    local files = context.selectedFiles
    local total = #files

    local p = app.progress.create({
        title = "批量处理",
        message = "准备中...",
        indeterminate = false,
        cancellable = true
    })
    if not p then return end

    local processed = 0
    for i, file in ipairs(files) do
        if p:isCancelled() then break end

        p:update(i * 100 / total, "处理: " .. app.path.basename(file))
        self:processFile(file)
        processed = processed + 1
    end

    p:close()
    app.notification.show("完成", "处理了 " .. processed .. " 个文件")
end

不确定进度(不知道要多久)

function MyPlugin:handleSearch(context)
    local p = app.progress.create({
        title = "搜索中",
        message = "正在搜索文件...",
        indeterminate = true
    })
    if not p then return end

    -- 全程只用 setMessage,不用 update——否则滚动条会变成实心条
    p:setMessage("正在扫描子目录...")
    local results = self:searchFiles()

    p:close()
    app.notification.show("完成", "找到 " .. #results .. " 个文件")
end

同时开多个

每次 create() 都是独立的一个对话框,互不干扰:

function MyPlugin:handleParallelDownload(context)
    local urls = {"url1", "url2", "url3"}
    local bars = {}

    for i, url in ipairs(urls) do
        bars[i] = app.progress.create({
            title = "下载 " .. i,
            message = "准备中...",
            indeterminate = false
        })
    end

    for pct = 1, 100 do
        for _, p in ipairs(bars) do
            if p then p:update(pct, "下载中... " .. pct .. "%") end
        end
    end

    for _, p in ipairs(bars) do
        if p then p:close() end
    end
end
开发者文档
使用帮助
使用说明 菜单编辑器指南 插件管理 设置说明 脚本菜单 常见问题
脚本开发
开发指南
插件开发
快速开始 开发指南 示例插件
API 参考
概览 API 查询 插件信息 日志 Finder 上下文 插件设置 国际化
UI 与交互
对话框 进度条 系统通知 选择器 WebView 状态栏 Dock
文件与路径
文件操作 路径工具 Finder 操作 废纸篓 扩展属性 元数据 文件监听
数据格式
JSON Plist CSV XML PDF 图片
文本与编码
字符串 正则表达式 日期时间 颜色 加密编码
系统
Shell 命令 进程管理 应用管理 系统信息 AppleScript 快捷指令
系统信息
网络信息 电源/电池 屏幕/外观 音频控制 蓝牙设备 位置服务
网络
HTTP 请求 WebSocket URL 工具
输入与剪贴板
键盘模拟 鼠标模拟 全局热键 剪贴板 窗口管理
存储
SQLite Keychain UserDefaults
媒体
文字识别 二维码
工具
归档 类型标识 分享 定时器 防休眠 并发/协程