File pickers & long tasks
System file dialogs (main-thread safe) and cancellable progress bars.
File / folder pickers
python
host.pick_file(title="选择文件", name_filter="所有文件 (*.*)", default_dir="") -> str
host.pick_files(title="选择文件", name_filter="所有文件 (*.*)", default_dir="") -> list[str]
host.pick_folder(title="选择文件夹", default_dir="") -> str
host.pick_save_file(title="保存文件", name_filter="所有文件 (*.*)", default_path="") -> str- Internally hops to the Qt GUI thread and opens the system dialog; callable from any thread, blocks until the user closes it.
- Cancel returns
""/[]and never raises. name_filterlooks like"文本 (*.txt *.json);;所有文件 (*.*)".- Need a file path in the plugin's private config? Write the returned path back into the plugin config / KV.
To let users pick a file by clicking a button on the settings page, see Custom settings view (
config_schema'stype: "file"currently has no file-picker widget).
Long-task progress (cancellable)
python
tid = host.begin_progress(plugin_id, title="批量汉化", total=120.0) -> str
host.update_progress(tid, current=12, message="item.lua") -> bool
host.is_progress_cancelled(tid) -> bool # check it inside the loop; exit as soon as it returns True
host.end_progress(tid, success=True, message="完成") -> bool
host.cancel_progress(tid) -> bool # usually triggered by the UI / a hotkey
host.get_progress(tid) -> dict- Front-end signal:
pluginProgress(task_id, plugin_id, ratio, message, done, cancelled). total <= 0means indeterminate progress;ratioranges over 0~1.- After a task ends it is kept for about 60 seconds so it can be queried, then cleaned up automatically.
begin_progressreturns atask_id; not getting one means the host refused (e.g. the same plugin already has a task running).
Standard pattern
python
def action_batch(self, **kwargs):
tid = self.host.begin_progress(self.id, title="批量处理", total=float(len(items)))
if not tid:
return {"ok": False, "error": "已有任务在跑"}
ok = True
try:
for i, it in enumerate(items, 1):
if self.host.is_progress_cancelled(tid):
ok = False
break
self._process(it)
self.host.update_progress(tid, current=i, message=it.name)
finally:
self.host.end_progress(tid, success=ok,
message="完成" if ok else "已取消")
return {"ok": ok}Key points:
is_progress_cancelled()returnsTrueonly on a genuine cancellation, and you must check it inside the loop — this is the only interruption point.- Keep the loop body fast; if a single item is very slow, make the cancellation granularity coarser instead of chopping the task up just to stay responsive.
- When the action itself is triggered by a hotkey / QML, wrap the whole thing in
self.run_in_background(...)— don't block the UI.
