Anki插件开发必知必会:钩子函数与右键菜单定制

发布时间:2026/7/11 20:05:30
Anki插件开发必知必会:钩子函数与右键菜单定制 为啥要自定义右键菜单——场景共鸣 钩子函数到底是个啥——生活化比喻 菜单定义的核心代码骨架 实战给浏览器卡片右键加上“查词典” 必知必看的注意事项与奇技淫巧 第一部分那个让人抓狂的下午起因的话开头已经说过了还有个需求就是在复习英语卡片时遇到个生僻词想查在线词典。正常操作是选中文本 → 右键复制 → 切到浏览器 → 粘贴搜索 → 再切回来。重复几次耐心直接清零了关键是费时呀当时我就想如果能在Anki里右键直接调接口查词还能顺手把释义填进字段该多爽。前几天咱们写的 FastAPI 自定义本地词典是不是也可以发光发热其实Anki插件体系还是很灵活的关键是把“什么时候触发”和“触发后干什么”串起来。前者靠钩子后者靠你写的函数而右键菜单或顶部菜单只是触发方式之一。 第二部分核心原理——钩子就是厨房里的传菜铃别被“钩子”这词吓到。把它想象成餐厅后厨的传菜铃厨师Anki做完一道工序就“叮”地按一下铃触发钩子服务员你的插件听到后去上菜执行自定义代码。其实就是这么简单Anki内置了一堆钩子点比如 卡片浏览器加载完菜单时browser.setupMenus 复习界面显示问题前reviewer.didShowQuestion 卡片添加、删除、修改时……我们定义右键菜单其实就是告诉Anki“嗨在浏览器右键菜单那个钩子触发时帮我塞进去一个‘查词典’选项。”这背后对应的钩子叫 browser.setupMenus官方文档虽然列出了但新手容易忽略的是你必须在这个钩子回调里去调用菜单对象的 addAction否则菜单项死活不会出现。还有一个大坑提醒老版本Anki的钩子命名不太一样比如 setupEditorButtons 和 browser.setupMenus 容易搞混。如果你用的 Anki 版本 2.1.55认准 browser.setupMenus 就行。版本太低的话赶紧升吧好多好用的钩子都没有。再说一点就是Anki就算升级到了新版本还是要注意下它里面的有些属性和函数因为版本差异就是死活找不到这时候你只能去源码里“移至定义”慢慢找了结合出错信息提示会快一些⚙️ 第三部分实战演示——三步给菜单加“查词典”功能好咱们直接上代码骨架。假设你已经在插件文件夹里新建了init.py。第一步导入必要的模块from aqt import mwfrom aqt.browser import Browserfrom aqt.qt import QActionfrom anki.hooks import addHookimport webbrowser这里 mw 是主窗口对象各种全局资源都通过它访问。第二步定义菜单添加函数并绑定钩子def setup_context_menu(browser: Browser):# 创建一个QAction这就是菜单项 action QAction( 一键查词典, browser) # 当用户点击时执行查询函数 action.triggered.connect(lambda: lookup_word(browser)) # 把action塞进浏览器菜单项里 browser.form.menuEdit.addAction(action)addHook(“browser.setupMenus”, setup_context_menu)注意啊browser.form.menuEdit 是浏览器顶栏“编辑”菜单的对象。如果你想加到其他菜单项下要看下源码里的命名不然会报错找不到对象。如果要添加到右键菜单项中我在卡片浏览器源码里没找到相应钩子不过我需要的是在笔记编辑界面中添加右键菜单项这个钩子函数我找到了就最下面代码里的editor_will_show_context_menu使用方式上和上面有点不同但意思大差不差gui_hooks.editor_will_show_context_menu.append(setup_editor_context_menu)第三步实现查词函数def lookup_word(browser: Browser):# 获取浏览器当前选中的文本 selected browser.current_card if not selected: return # 这里只是示例实际可从卡片字段取词 word selected.note()[Front] webbrowser.open(fhttps://dict.youdao.com/search?q{word})这个例子是直接用电脑默认浏览器来查词典。你完全可以结合 FastAPI 接口把查询结果写回卡片字段比如调个API后修改 note()[“Back”] 再 note().flush()。你可能会问“那我怎么知道有啥钩子能用”最好的办法不是死记硬背因为它可能因为版本不同就变了而是去Anki源码里搜 runHook 或 addHook 等关键词看它本身是怎么调用的或者在插件开发文档里找 Hooks Reference。另外用 aqt.utils.showInfo 打日志是最朴素的调试法插件控制台不弹错误时全靠它保命。 第四部分注意事项与进阶思考 千万别在主线程里干重活像调API、大量IO操作记得用 mw.taskman.run_in_background 包起来否则Anki直接卡死给你看。 菜单对象生命周期不要在钩子外面预先创建 QAction 然后反复添加每次 setupMenus 触发时都可能重建菜单你只管每次新建并加入系统会管理销毁否则容易出重复菜单项。 多版本兼容如果你想让插件同时兼容新旧Anki可以加个 if hasattr(Browser, ‘form’) 之类的判断但不如直接声明最低版本要求省心。再说个容易翻车的点修改了代码后记得重启Anki网上说的什么“开发者模式”下的“重载插件”功能我找了半天我这个版本里也没有找到还是重启来的干脆还省了缓存干扰。 来个小结其实自定义Anki插件就是个搭积木的过程——钩子告诉你“哪里能插”菜单定义告诉它“长什么样”你的函数决定“插进去干什么”。