第 7+1 篇 📝 宏脚本编辑器与模板库管理实现细节
✨ 引言
在上篇《7. 宏脚本编辑器设计与解释器实现》中,我们构建了宏系统的核心执行引擎,从词法分析、语法解析到 AST 解释执行,实现了自动巡航、批量预置位、报警联动等高级功能。本篇将视角从"引擎内部"转向"用户界面",深入讲解宏编辑器(macro_editor.py)与模板库(template_library.py)的设计与实现。
这两部分共同构成了宏系统的"前端入口",让用户能够:
- 可视化编写脚本
- 一键加载模板
- 参数化生成脚本
- 保存/管理宏文件
- 直接运行并查看执行进度
相比早期单文件版(KBD300A_main.py)完全没有宏功能,最终版通过 QsciScintilla 编辑器 + JSON 模板库 + 完整 AST 引擎,实现了一个可扩展、可维护、可复用的企业级脚本系统。
🛠️ 宏编辑器设计(MacroEditorPanel)
宏编辑器是用户与宏系统交互的核心界面。设计目标非常明确:
- 专业编辑体验(语法高亮、行号、缩进)
- 文件管理(新建、保存、删除)
- 运行/停止控制
- 进度反馈
最终选择 QsciScintilla 作为编辑器组件,它比 QTextEdit 更适合做代码编辑器。

🔧 UI 结构
编辑器采用典型的三段式布局:
- 顶部工具栏:宏列表 + 新建/保存/删除
- 中间编辑区:QsciScintilla
- 底部控制区:运行/停止 + 进度条
代码片段(来自最终实现):
python
self.editor = QsciScintilla()
lexer = QsciLexerLua(self.editor)
self.editor.setLexer(lexer)
self.editor.setUtf8(True)
self.editor.setIndentationsUseTabs(False)
self.editor.setIndentationWidth(4)
self.editor.setMarginLineNumbers(1, True)
self.editor.setMarginWidth(1, "0000")
QsciLexerLua 虽然不是专为宏语言设计,但其结构与我们 DSL 的语法足够接近,能提供良好的高亮体验。
▶️ 运行与停止
运行宏的逻辑非常简洁:
python
def _run(self):
script = self.editor.text()
self.run_macro.emit(script)
self.progress.setValue(0)
这里不直接执行脚本,而是通过信号交给 AppWindow → MacroEngine,保持 UI 与逻辑完全解耦。
停止宏:
python
def _stop(self):
if hasattr(self.parent(), "_stop"):
self.parent()._stop()
最终由 MacroEngine.stop() 触发安全停止(包括 PTZ 强制停止)。
📁 文件管理
宏文件存储在:
resources/macros/*.macro
加载:
python
for f in os.listdir(MACRO_DIR):
if f.endswith(".macro"):
self.macro_list.addItem(f[:-6])
保存:
python
with open(path, "w", encoding="utf-8") as f:
f.write(self.editor.text())
删除:
python
os.remove(path)
self.load_macros()
整个编辑器保持轻量、直观、可扩展。
📚 模板库管理(TemplateLibraryPanel)
模板库是宏系统的"生产力工具"。它允许用户:
- 一键加载常用脚本
- 使用参数化模板生成脚本
- 快速构建巡航、批量预置位、报警联动等场景


模板存储在 JSON 文件中:
resources/templates.json
结构示例:
json
{
"templates": [
{
"name": "停车场巡航",
"description": "循环巡航 1-5 号预置位",
"script": "loop(5){ send_preset(1, {{preset}}); delay(1000); }",
"params": ["preset"]
}
]
}
🔄 模板加载
python
def load_templates(self):
with open(TEMPLATE_FILE, "r", encoding="utf-8") as f:
data = json.load(f)
self.templates = data.get("templates", [])
UI 列表自动刷新:
python
for tpl in self.templates:
self.template_list.addItem(tpl["name"])
🧩 参数化模板渲染
模板支持 {``{param}} 占位符,渲染逻辑:
python
def _render_template(self, tpl):
script = tpl["script"]
for param in tpl["params"]:
value = input(f"Enter {param}: ") # 实际实现为 QDialog
script = script.replace(f"{{{{{param}}}}}", value)
return script
最终脚本通过信号发送给编辑器:
python
self.load_template.emit(script)
🔗 编辑器与模板库的集成
RightPanel 将两者组合到同一个 TabWidget 中:
python
self.tabs.addTab(self.macro_editor, "宏编辑")
self.tabs.addTab(self.template_panel, "模板库")
AppWindow 负责信号路由:
python
self.right.run_macro.connect(self._run_macro)
键盘切换到宏模式时自动跳转:
python
if mode == "MACRO":
self.right.tabs.setCurrentWidget(self.right.macro_editor)
模板库 → 编辑器 → 引擎 的链路完全打通。
🧠 宏引擎与 AST 的协作(关键补充)
你的最终版 MacroEngine 使用 访问者模式(Visitor Pattern) 执行 AST:
python
def visit(self, node):
method_name = f'visit_{type(node).__name__}'
visitor = getattr(self, method_name, self.generic_visit)
return visitor(node)
支持:
- Compound
- Loop
- For
- Command
- Var / Num / String
执行命令:
python
if name == 'send_preset':
pelco.call_preset(self.serial_mgr, current_cam, preset)
delay 使用可中断版本:
python
self._delay_interruptible(ms)
整个执行器是同步的、可测试的、可扩展的。
🛡️ 调试与优化
- AST 可视化:在 visit_* 中加入 debug 输出
- 模板校验:使用 JSON schema
- 自动补全:QsciScintilla 支持 API 文件,可加入 send_preset/loop/delay 等关键字
- 错误提示:解析错误通过 error.emit 弹窗
- Win7 兼容性:QsciScintilla 性能优于 QTextEdit,长脚本不卡顿
🏁 结语
本篇文章从 UI 到模板库,从脚本编辑到 AST 执行,完整展示了宏系统的"前端生态"。宏编辑器让脚本编写更直观,模板库让脚本复用更高效,而 MacroEngine 则提供了强大的执行能力。
三者结合,使得 KBD300A 工具从"控制台工具"升级为"自动化平台",为安防维护、巡航调试、批量配置提供了真正的生产力。
下一篇《7.2 Python 专题:线程安全与信号槽机制》将深入探讨宏执行的并发模型与 UI 响应优化。