☰
QGIS插件开发:环境配置、调试与打包发布全流程
2026/10/1 4:47:48 网站建设 项目流程

1. 先说清楚:QGIS 插件开发为什么不能当成普通 Python 项目来做

1.1 插件不是独立程序,它是寄生在 QGIS 进程里的一段代码

这是所有新手最容易走偏的地方。你写一个普通的 Python 脚本,python main.py就能跑,进程是你自己启动的,依赖是你自己 pip 装的。QGIS 插件完全不是这个逻辑:插件是一段被 QGIS 主程序在运行时动态加载的 Python 代码,它运行在 QGIS 已经启动好的那个 Python 解释器进程里,用的也是 QGIS 自带的 PyQt5 版本、自带的 GDAL 和 PROJ 库、自带的那套 Python site-packages。

举个生活化的类比:普通 Python 项目像是你自己开一家店,租店面、进货、装修全由你决定;QGIS 插件像是你在别人的商场里租一个柜台,水电、消防、客流全是商场给的,你只能按商场的规矩来。所以你在编辑器里能不能import qgis.core成功,并不是看你 pip 装了多少东西,而是看编辑器有没有用上 QGIS 那套 Python 和那套环境变量。

理解了这一层,后面所有的配置动作就有了统一的判断标准:凡是能让编辑器"借用" QGIS 自带 Python 环境的做法都是对的,凡是试图用系统 Python 硬装 PyQGIS 的做法基本都是弯路。PyQGIS 在 pip 上没有官方可分发的独立包,强行安装会遇到 SIP 绑定、Qt 版本、GDAL 编译链一堆问题,投入产出比极低。

所以整套环境配置的核心目标只有三个:让编辑器能读到 QGIS 的 Python 解释器、让import qgis.core能成功、让改完的代码能快速在 QGIS 里看到效果。剩下的都是围绕这三件事的细节。

1.2 三种环境配置路线,各自适合什么样的人

实际工作中我见过并试过三条路线,各有取舍,先把结论摆出来,你对号入座。

路线做法优点缺点适合谁
路线 A:QGIS 自带控制台直接在 QGIS 里打开 Python 控制台写代码零配置,立刻能跑没有补全、没有断点、代码管理困难只做实验、验证 API
路线 B:OSGeo4W Shell 启动编辑器从 QGIS 附带的命令行环境里启动 VS Code / PyCharm环境变量完整继承,import qgis.core一次通过每次要从 Shell 里启动绝大多数开发场景
路线 C:手工配置解释器与 env在编辑器里手动指定解释器、PYTHONPATH、PATH启动方式自由,能做调试配置路径多、版本升级易失效想深度整合调试的人

路线 B 是我最推荐的起点。原因很直接:QGIS 附带的o4w_env.bat会把PATH、PYTHONPATH、GDAL_DATA、PROJ_LIB、QT_PLUGIN_PATH这些变量一次性设好,你在那个环境里启动的编辑器天然就继承了全部配置,省掉大量试错时间。等你对这套东西熟了,再去做路线 C 的精细配置。

路线 C 不是不必要,而是"进阶选项"。它的价值在于调试:只有环境变量在编辑器里被正确声明,断点调试才可能跑通。而环境变量的具体内容,你完全可以从路线 B 的环境里抄出来。

1.3 配错了会长什么样:三种典型报错先认清

提前认识报错,比事后瞎猜快得多。以下三种几乎每个新手都会遇到:

  • ModuleNotFoundError: No module named 'qgis'。这说明解释器根本不知道 PyQGIS 在哪。要么解释器指错了(用了系统 Python),要么PYTHONPATH里没加 QGIS 的 python 目录。
  • ImportError: DLL load failed while importing core: 找不到指定的模块。这个是 Windows 上最经典的坑,说明PYTHONPATH对了但PATH里缺 QGIS 的bin目录,导致 Qt 的 DLL 加载不到。加路径没用,得加对顺序。
  • 插件出现在列表里但打勾后无反应,或者勾完立刻掉回未勾选状态。这通常是插件本身的代码问题:__init__.py里的classFactory写错了、metadata.txt字段缺失、或者运行时报了异常被 QGIS 静默吞掉。

第三种最坑,因为 QGIS 默认不会把插件的加载异常直接弹出来。排查手段后面第 5 章会详细讲。现在你只需要记住:环境问题报错在 import,代码问题报错在加载。分清这两类,排查方向就不会跑偏。

2. 装 QGIS 与装编辑器:路径这一步决定了后面顺不顺

2.1 选 LTR 还是最新版,安装目录要不要改

QGIS 的 Windows 安装包分两类:LTR(长期支持版)和 Latest(最新版)。做插件开发请优先选LTR。理由不是保守,而是插件兼容性:LTR 版本的 API 更稳定,你写的一次代码能覆盖的人群更广;最新版可能引入了还没被广泛测试的 API 变化,早期的插件会在这些版本上直接报错。

安装目录这一项,很多人图省事直接点默认的C:\Program Files\QGIS 3.xx.x\,这本身没问题,但你要接受一个后果:这个路径带空格,还带版本号。带空格会导致后面在命令行、脚本、配置里引用时必须加引号,稍不留神就是一堆诡异错误。带版本号意味着你以后升级 QGIS 时所有配置里的路径都要跟着改。

我的做法是:不改默认路径,但把版本号单独记下来,并且所有配置里引用路径都老老实实加引号。改到C:\QGIS\这种短路径虽然看着干净,但和官方文档、社区教程里的路径对不上,反而增加沟通成本。

安装组件这一步也要留意。自定义安装界面里有一堆可选组件,做插件开发有两个别漏:Python 相关的组件(PyQt5、Python 解释器本体)以及 Qt 的工具链。如果你用的是网络安装器(OSGeo4W 那套),确保勾选qgis-ltr-full这类完整包,别只装了残缺的精简版,否则后面pyrcc5找不到。

装完之后,第一件事是打开 QGIS,从菜单里找到 Python 控制台(一般在"插件"菜单下,或者用工具栏那个 Python 图标)。能打开、能敲一行print("ok")并且窗口里出现ok,说明基础环境没问题。

2.2 编辑器选型:VS Code、PyCharm,还是先用自带控制台

编辑器这件事不用纠结太久,三个选项的实际差别在于"你要花多少时间在配置上"。

QGIS 自带的 Python 控制台是零配置的,打开就能跑,iface、QgsProject这些对象都是现成的。它的定位是"探路工具":你写插件时不确定某个 API 怎么调用,先在控制台里敲两行验证,验证通过再搬进代码。但别指望用它写正式项目——没有代码补全、没有版本管理、没有断点,写超过两百行的插件就是自虐。

VS Code 是大多数人的选择,免费、轻量、插件生态好。要注意的是 Python 扩展和 Pylance 这两块是必须装的(Python 扩展提供解释器管理和调试,Pylance 提供补全和类型提示)。装完这两个,PyQGIS 的补全才能通过extraPaths生效。

PyCharm 社区版也能用,它对大型项目的重构和跳转更顺手,但解释器和路径要在设置里手工配,配置条目比 VS Code 多。PyCharm 专业版有远程调试和更强的调试器,不过是付费的。

我的建议:先用 QGIS 自带控制台把 API 摸熟,然后直接上 VS Code。别在编辑器选型上反复横跳,时间和精力都应该花在写插件逻辑上。三大平台的插件目录差异也顺便记一下,后面生成插件时会反复用到:

  • Windows:C:\Users\<用户名>\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins
  • Linux:~/.local/share/QGIS/QGIS3/profiles/default/python/plugins
  • macOS:~/Library/Application Support/QGIS/QGIS3/profiles/default/python/plugins

最省事的确认方式是在 QGIS 的 Python 控制台里跑这两行:

from qgis.core import QgsApplication print(QgsApplication.qgisSettingsDirPath()) import qgis.utils print(qgis.utils.plugin_paths())

第一行输出你的活动 profile 目录,第二行输出插件搜索路径列表。不要凭记忆写路径,永远以这两行的输出为准。版本不同、用户目录带中文、装了多份 QGIS,这些情况都会让"我记得是那个路径"变成错误。

2.3 profile 目录、插件目录、缓存目录,别混为一谈

这三个目录很容易被当成一回事,实际职责完全不同。

profile 目录是整个用户配置的根,里面装着界面布局、最近打开的项目、坐标系设置、已启用插件的清单,以及python/plugins这个子目录。你在 QGIS 里点"设置 → 用户配置 → 打开活动配置文件夹",打开的就是它。

插件目录是 profile 目录下的python/plugins,所有第三方插件(包括你自己开发的)都放在这儿。QGIS 启动时会扫描这个目录,逐个读metadata.txt判断能不能加载。

缓存目录则是python/plugins同级的cache之类的位置,一些插件会把临时数据写在这里。清缓存不等于删插件,这一点要分清楚。

还有一个隐藏的坑:QGIS 会记住"哪些插件被启用过"。这个状态存在 profile 目录下的一个配置文件里。你手动删了插件文件夹但没重启 QGIS,插件列表里可能还残留着条目;反过来,你新拷进去一个插件但没重启,它可能不出现。改插件文件后要么用 Plugin Reloader(第 4 章讲),要么老老实实重启 QGIS。

顺带提一下:如果你不想污染默认 profile,可以在 QGIS 启动时用--profile参数指定一个新 profile,这样插件、设置都是独立的。做实验性开发时很有用。

3. 让编辑器真正"看见" PyQGIS:解释器与路径配置全流程

3.1 找到 QGIS 自带的 Python 与那几个 bat 脚本

这一步是整个配置的基石,先把你机器上的文件找齐。打开 QGIS 的安装目录,进入apps子目录,里面应该能看到一个类似Python39、Python312这样的文件夹(版本号取决于你装的 QGIS 版本,3.28 和 3.34 常见的是 Python 3.9,3.40 之后常见的是 3.12,以你机器上实际存在的为准,别照抄)。

里面那个python.exe就是 QGIS 自带的解释器。注意:它和系统的 Python 是两套东西,互不干扰,你也别尝试用它去装系统的包。

再看安装目录下的bin文件夹,里面有几个批处理脚本很关键:

  • python-qgis.bat和python-qgis-ltr.bat:启动一个已经加载好 QGIS 环境的 Python 交互式环境
  • o4w_env.bat:只设置环境变量,不启动 Python
  • qgis-ltr-bin.exe:QGIS 主程序本体

o4w_env.bat是重中之重。在普通命令提示符里执行它,当前会话就会获得 QGIS 的全部环境变量。你可以这样验证:

call "C:\Program Files\QGIS 3.34.0\bin\o4w_env.bat" python -c "import qgis.core; print(qgis.core.Qgis.QGIS_VERSION)"

如果这一行能打印出版本号,说明 QGIS 自带的环境是完整可用的,问题就只剩"怎么让编辑器也用上这个环境"。

注意:o4w_env.bat只在当前命令行会话生效,关掉窗口就没了。不要指望把它加到系统环境变量里一劳永逸,那样会污染系统 Python 的正常使用。

3.2 VS Code:settings.json、终端 profile 与解释器三件套

VS Code 的配置分三层,层与层之间容易互相打断,按顺序来。

第一层是终端 profile。在settings.json里加一段,让 VS Code 的集成终端可以选择性地以 QGIS 环境启动:

{ "terminal.integrated.profiles.windows": { "QGIS Env": { "path": "C:\\Windows\\System32\\cmd.exe", "args": ["/k", "\"C:\\Program Files\\QGIS 3.34.0\\bin\\o4w_env.bat\""] } }, "terminal.integrated.defaultProfile.windows": "QGIS Env" }

配完之后,VS Code 里新开的终端会自动带上 QGIS 的环境变量。这是最省心的做法,因为接下来不管你是敲python还是敲pip,用的都是 QGIS 那套。

第二层是解释器。按下Ctrl+Shift+P,输入Python: Select Interpreter,然后手动输入路径,指向:

C:\Program Files\QGIS 3.34.0\apps\Python39\python.exe

选完之后 VS Code 状态栏会显示这个解释器。注意别选成系统里的 Anaconda 或微软商店版 Python,这是新手最常见的失误。

第三层是补全路径。光选解释器还不够,因为 QGIS 的 Python 库不在标准 site-packages 里,Pylance 找不到它。需要手工加:

{ "python.analysis.extraPaths": [ "C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\python", "C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\python\\plugins" ], "python.autoComplete.extraPaths": [ "C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\python", "C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\python\\plugins" ] }

加完之后重启一下 VS Code(或者执行Python: Restart Language Server),再打开一个.py文件敲from qgis.core import QgsProject,如果QgsProject有补全提示、能跳转到定义,说明补全这块通了。

如果还要在 VS Code 里直接运行脚本,就得配launch.json了,这属于路线 C 的范畴:

{ "version": "0.2.0", "configurations": [ { "name": "QGIS 环境跑当前文件", "type": "debugpy", "request": "launch", "program": "${file}", "console": "integratedTerminal", "env": { "PYTHONPATH": "C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\python;C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\python\\plugins", "PATH": "C:\\Program Files\\QGIS 3.34.0\\bin;C:\\Program Files\\QGIS 3.34.0\\apps\\qgis\\bin;${env:PATH}" } } ] }

这套 env 写法是"够用版本"。完整版还要加GDAL_DATA、PROJ_LIB、QT_PLUGIN_PATH,具体值请从o4w_env.bat里抄,或者在一个已经执行过它的终端里敲set查看。不要凭印象写这些变量,路径错一个字母就是 DLL 加载失败。

3.3 PyCharm:解释器、路径变量与外部工具

PyCharm 的配置思路和 VS Code 一致,但入口分散在几个地方。

解释器在File → Settings → Project → Python Interpreter。点齿轮图标选Add,然后选System Interpreter,路径填C:\Program Files\QGIS 3.34.0\apps\Python39\python.exe。添加完之后 PyCharm 会去扫这个解释器的 site-packages,QGIS 自带的那些库会被识别到。

但 PyQGIS 不在 site-packages 里,所以要再手工加路径,位置在Settings → Project → Python Interpreter → 解释器右侧的路径按钮,把apps\qgis\python和apps\qgis\python\plugins加进去。加完之后 PyCharm 的索引会重建一次,耐心等。

PyCharm 还有一个更好用的东西是外部工具配置。在Settings → Tools → External Tools里加一个工具,命令指向o4w_env.bat,每次点一下就能在一个带 QGIS 环境的终端里干活。对不想改launch.json的人来说,这比手工配 env 靠谱。

PyCharm 运行/调试配置里的环境变量编辑框,直接粘贴从o4w_env.bat抄来的那几个变量即可。要注意 PyCharm 的环境变量编辑框里,多条路径之间用的是分号分隔,且不要用引号把整条PATH值包起来。

3.4 验证环节:怎样才算真的配好了

配置完别急着写插件,先做三层验证,一层通不了就别往下走。

第一层,解释器认对了。在编辑器的文件里写:

import sys print(sys.executable) print(sys.version)

运行并看输出,路径必须指向 QGIS 安装目录里的python.exe,而不是C:\Python3xx或者 Anaconda。

第二层,PyQGIS 能导入。同一个文件里加:

from qgis.core import QgsApplication, Qgis print(Qgis.QGIS_VERSION)

能打印出版本号说明导入链路和 DLL 加载都没问题。如果这里报DLL load failed,回去检查PATH里有没有bin目录,并且确认bin排在系统 Python 相关路径前面。

第三层,补全和跳转可用。随便敲一个QgsVectorLayer(,看有没有参数提示;按住Ctrl点类名,看能不能跳到qgis/core/__init__.pyi或者对应的源码。这两项都通过,才算是一个真正好用的开发环境。

提示:如果第二层过了、第三层没过,通常是 Pylance 的缓存问题,执行一次Python: Restart Language Server就好。如果第三层过了、第二层没过,那是运行时环境变量的问题,不是编辑器的问题,要往o4w_env.bat的方向查。

4. 生成第一个插件骨架:Plugin Builder 与它的产物解剖

4.1 安装 Plugin Builder 并生成骨架

有了环境,下一步就是造一个能加载进 QGIS 的插件骨架。手写骨架不是不行,但metadata.txt字段多、__init__.py的classFactory有固定写法、资源文件要编译,手写容易漏东西。所以推荐用Plugin Builder这个官方社区插件生成模板,再按需修改。

安装路径是 QGIS 里的插件 → 管理并安装插件,搜索框输入 "Plugin Builder",找到后点安装。装完后菜单里会多出一项。

使用流程大致是:点开 Plugin Builder,填一组表单,然后选择输出目录。表单里几项要特别注意:

  • Class name:插件主类的名字,建议用英文驼峰,别用中文,也别和 QGIS 内置类名撞车。
  • Plugin name:显示在菜单和插件管理器里的名字,可以是中文,但建议保留英文原名做目录名,方便社区发布。
  • Module name:这个决定了文件夹名和 Python 模块名,必须是纯小写英文加下划线。
  • Description / About:这两项会写进metadata.txt,是发布时给别人看的门面,先大致填,发布前再打磨。
  • Minimum QGIS version:这个值直接决定插件能在哪些版本上被加载,填太高会让老用户装不上,填太低可能在不支持的版本上出问题。保守做法是填你实际测试过的最低版本,比如3.22。
  • Template:选Tool button with dialog或者Tool button with dock widget,前者适合弹窗式工具,后者适合常驻面板。

输出目录建议直接填到插件目录(第 2.2 节那个路径)下。Plugin Builder 会自动建子目录,你确认一下生成的位置对不对。

4.2 逐个文件拆解:哪些要改、哪些别碰

生成出来的目录大概长这样:

my_first_plugin/ ├── __init__.py ├── metadata.txt ├── my_first_plugin.py ├── my_first_plugin_dialog.py ├── my_first_plugin_dialog_base.ui ├── resources.qrc ├── resources.py ├── icon.png ├── Makefile └── i18n/ └── af.ts

挨个说清楚每个文件干什么、能不能动。

metadata.txt是插件的身份证。QGIS 启动扫描时只读这个文件来判断插件是否可用。关键字段包括name、qgisMinimumVersion、description、version、author、email、about、tracker、repository、tags、experimental。version字段每次发布必须递增,否则插件仓库会拒绝。experimental=True表示标记为实验版,只有勾选了"显示实验性插件"的用户才能看到。这个字段在你自测阶段可以开着,正式发布时改成False。

__init__.py是插件入口,里面的classFactory函数负责把插件类交给 QGIS。这个文件很短,但千万别改结构,只改返回的类名:

def classFactory(iface): from .my_first_plugin import MyFirstPlugin return MyFirstPlugin(iface)

my_first_plugin.py是核心逻辑,主类里固定有这么几个方法:

  • __init__(self, iface):构造,iface是 QGIS 给你的接口对象,通过它能访问图层树、菜单、工具栏、状态栏。
  • initGui(self):QGIS 加载插件时调用,通常在这里把动作(QAction)加到菜单和工具栏。
  • unload(self):插件被卸载时调用,要在这里把你加进去的动作从界面移除,不然会出现重复菜单项。
  • run(self):动作被点击时触发,业务逻辑从这儿开始。

*_dialog.py和*_dialog_base.ui是界面部分。.ui文件是 Qt Designer 的格式,可以用Qt Designer打开拖控件,也可以用文本编辑器直接改 XML。生成的*_dialog.py会把.ui加载进来,同时给你一个run()方法,这是你写业务逻辑的地方。注意.ui改完不需要重新生成.py,因为它是在运行时加载的,这跟resources.qrc的情况不同。

resources.qrc和resources.py是资源打包。.qrc里记录图标等资源文件的路径,.py是编译后的结果,代码里通过:/plugins/...这种形式引用。改完.qrc必须重新编译。

Makefile和i18n/是给pb_tool和翻译用的,初始阶段可以不管。

4.3 资源文件与 pyrcc5,以及 pb_tool 能省多少事

资源编译是很多新手第一次改图标时踩的坑:把新图标拷进目录、在.qrc里改了路径,但界面上还是旧图标。原因就是没重新编译.qrc。

编译命令是:

call "C:\Program Files\QGIS 3.34.0\bin\o4w_env.bat" pyrcc5 -o resources.py resources.qrc

pyrcc5是 PyQt5 附带的资源编译器,在o4w_env.bat设好环境后直接在命令行可用。如果你的 QGIS 版本用的是 Qt6 路线,对应的命令可能换成pyrcc6或者已经不再需要这一步(Qt6 更推荐用文件系统直接加载图标),以你机器上有哪个命令为准,敲pyrcc5 --help试一下就知道。

手工敲pyrcc5当然可以,但插件项目通常还要做别的重复劳动:把插件"部署"到 profile 目录、打包成 zip、清理临时文件、更新翻译。这些琐事可以用pb_tool一次性解决。

它在 QGIS 的 Python 环境里安装:

call "C:\Program Files\QGIS 3.34.0\bin\o4w_env.bat" python -m pip install pb_tool

然后在插件目录下运行:

pb_tool compile REM 编译 .qrc 和 .ui pb_tool deploy REM 部署到 profile 目录 pb_tool zip REM 打包成可发布的 zip pb_tool clean REM 清理中间产物

pb_tool读取插件目录里的pb_tool.cfg判断各项参数。Plugin Builder 生成的目录一般已经带了这个配置文件,如果没带,运行pb_tool create生成一个。

提示:pb_tool deploy会覆盖 profile 目录里同名插件。如果你同时手工改过 profile 里的文件,部署前先备份,免得辛苦改的代码被覆盖。这个坑我踩过不止一次。

4.4 Plugin Reloader:把"改一行重启一次"这件事干掉

QGIS 启动一次要好几秒,改一行代码就重启一次,一天下来时间全耗在等待上。Plugin Reloader就是解决这个的。

安装方式同样是在插件管理器里搜 "Plugin Reloader"。装完后菜单里会出现Plugin Reloader → Choose plugin,选你的插件,然后点Reload plugin。它的工作原理是调用qgis.utils.reloadPlugin(),把插件的模块从内存里卸载再重新加载。

实测下来它的边界要清楚:

  • 能热重载的:插件的 Python 逻辑代码、.ui文件(因为运行时加载)、metadata.txt的部分字段。
  • 不能热重载的:__init__.py的结构性改动、新增的.py文件(有可能不被识别)、resources.py的改动(有时能,有时不能,稳妥起见还是重启)。

另外主类的unload()方法必须写对。如果卸载时没把动作从界面移除,重载后你会看到菜单里出现两份同样的项,点哪个都可能出问题。生成的模板里unload()一般是写好的,你自己加动作时记得同步在unload()里清理。

还有一个更原生的方式,在 QGIS 的 Python 控制台里直接执行:

import qgis.utils qgis.utils.reloadPlugin('my_first_plugin')

效果和 Plugin Reloader 一样,但胜在快,可以把它绑定到一段你自己的小脚本里。

5. 调试、排错与打包:从能跑到能发

5.1 断点调试的可行做法

插件调试比普通脚本麻烦,因为代码运行在 QGIS 进程里,你不能直接在编辑器里按 F5 启动调试。目前可行的做法有两条。

第一条是远程附加调试。原理是让 QGIS 进程里跑起一个调试服务端,编辑器作为客户端附加过去。以debugpy为例,先把它装到 QGIS 的 Python 环境:

call "C:\Program Files\QGIS 3.34.0\bin\o4w_env.bat" python -m pip install debugpy

然后在 QGIS 的 Python 控制台里执行:

import debugpy debugpy.listen(("127.0.0.1", 5678)) print("waiting for debugger...")

接着在 VS Code 里配一个 attach 配置:

{ "name": "Attach to QGIS", "type": "debugpy", "request": "attach", "connect": { "host": "127.0.0.1", "port": 5678 }, "pathMappings": [ { "localRoot": "${workspaceFolder}/my_first_plugin", "remoteRoot": "C:\\Users\\<用户名>\\AppData\\Roaming\\QGIS\\QGIS3\\profiles\\default\\python\\plugins\\my_first_plugin" } ] }

路径映射这一项是关键,两边的目录必须能对上,否则断点会显示为"未绑定"。启动 attach 之后,你在插件里加的断点就能命中了。

第二条是日志法,也就是最土但最有效的办法。在代码里插打印,或者把异常信息写进 QGIS 的日志面板:

from qgis.core import QgsMessageLog, Qgis def run(self): try: # 你的业务逻辑 pass except Exception as e: import traceback QgsMessageLog.logMessage(traceback.format_exc(), "MyPlugin", Qgis.Critical)

QgsMessageLog会把消息写进 QGIS 的日志消息面板(菜单里可以打开),出错时带上完整堆栈,比单行 print 有用得多。开发期把print和QgsMessageLog混着用,效率最高。

5.2 报错定位的顺序:先看这里再看那里

排查插件问题有一套固定顺序,照着走能省很多时间。

第一步,看插件到底有没有被加载。在 QGIS 的 Python 控制台里执行:

import qgis.utils print(qgis.utils.plugins.keys())

如果你的插件模块名不在里面,说明加载就失败了,问题在metadata.txt或__init__.py。如果在里面但功能不对,说明加载成功,问题在业务逻辑。

第二步,看 QGIS 启动时的日志。菜单里的日志消息面板会记录插件加载异常。很多时候你以为插件没加载,其实加载了但initGui里抛了异常,QGIS 捕获后没弹窗。

第三步,检查路径。qgis.utils.plugin_paths()的输出里必须包含你的插件所在目录。如果插件放在自定义目录,要去设置 → 选项 → 系统 → 插件路径里手工加进去。

第四步,检查版本门槛。metadata.txt里的qgisMinimumVersion高于当前 QGIS 版本时,插件会直接不显示,且几乎不给提示。这是最阴的一个坑。

第五步,看是否有命名冲突。插件模块名如果和已安装的其他 Python 包重名(比如叫test、utils),导入时可能被解析到别的模块上,表现为"代码明明改了却没变化"。

5.3 跨版本兼容与 Python 版本差异

QGIS 3.x 系列内部是 PyQt5,但 Python 版本在系列内部有过变化。早期 3.x 版本多用 Python 3.6/3.7,LTR 阶段常见 3.9,较新的版本开始用 3.12。这个差异会直接影响到你的代码能不能跑:

  • 语法层面:3.12 里一些被弃用的写法会警告甚至报错,比如某些datetime用法、imp模块。你如果在 3.12 上开发却想兼容 3.9,就避免使用 3.10+ 才有的语法特性(比如match语句)。
  • API 层面:QGIS 的 API 在不同小版本间会做弃用调整。以前能用的QgsGeometry.fromPolygon()这类方法,新版本会推荐换成QgsGeometry.fromPolygonXY(),旧方法可能还能用但会告警。
  • 打包层面:如果你想同时在多个 QGIS 版本上测试,最省事的方法是装多个版本的 QGIS 到不同的目录,用不同 profile 隔离配置。

实际做法上,我建议以 LTR 版本为开发基准,然后在metadata.txt里把qgisMinimumVersion设成你真正测过的最低版本。别为了兼容很老的版本去牺牲代码可读性,社区主流用户都在 LTR 及以上。

5.4 上架前的自检清单

插件写完了,要发布或交付之前,这套清单过一遍,能挡掉大部分低级问题。

检查项具体要求常见失误
metadata.txt完整性name、version、description、author、email、qgisMinimumVersion 必填缺 email 或 version 格式不规范
version递增每次发布必须比上一次大直接覆盖发布导致仓库拒绝
experimental状态正式发布设为 False忘了改,用户看不到插件
图标引用正确图标路径与.qrc编译结果一致改了图但没重新 pyrcc5
依赖声明如果用了额外 pip 包,要在about或文档里说明用户装上后 ImportError
卸载干净unload()里移除所有添加的动作和界面元素重载后出现重复菜单项
中英文资源有翻译需求时补齐.ts并 lrelease 编译翻译文件没编译,界面还是英文
异常兜底关键路径加 try/except 并写 QgsMessageLog出错时用户完全不知道为什么

打包成 zip 之后,自己先在一台干净的机器上(或者一个新建的 profile 里)装一遍。这一步能发现"在我机器上没问题"这类隐蔽问题,比如某个路径写死成了你的用户名。

6. 几个我反复踩的坑和顺手的小习惯

6.1 中文路径、空格与权限

这三个问题在 Windows 上出现频率最高。

中文路径的问题出在编码环节。有些工具链在读取.qrc、.ts、.ui这些 XML 文件时,对非 ASCII 路径的处理不一致,表现为编译报错或者资源加载不出来。最省事的规避办法是把整个开发链路放在纯英文路径下,包括 QGIS 安装目录、编辑器工作区、插件目录里的用户名的部分。

用户目录带中文这一点比较麻烦,因为%APPDATA%是 Windows 给定的。如果你的用户名是中文,C:\Users\张三\AppData\...就会带中文。规避方式是新建一个英文名的用户,或者把插件开发目录放在D:\qgis-dev\这种纯英文路径下,只把编译产物部署到 profile 目录。命令行引用带空格路径时,所有路径都要加双引号,包括o4w_env.bat的路径。

权限问题上,C:\Program Files\下的文件默认不可写。装插件不需要写安装目录,所以一般不冲突;但如果你想改 QGIS 自带的 Python 库文件(不建议),会碰到权限拒绝。pip install装到 QGIS Python 环境时,如果报权限错误,说明装到了系统级的Program Files目录下,这时候要么用管理员权限,要么加--user装到用户目录。

6.2 环境变量顺序与"两个 Python 打架"

PATH的顺序决定命令解析的结果。如果你系统里同时有 Anaconda、微软商店版 Python、QGIS 自带 Python,敲python和pip时到底用哪个,完全取决于PATH里谁在前面。

插件开发时这个问题的表现是:你在终端里敲python,启动的却是 Anaconda,然后import qgis.core报错,你以为是 QGIS 环境坏了,其实是走错解释器了。

判断方法很简单,敲:

where python where pip

输出的第一行就是实际生效的那个。确认是 QGIS 目录下的再往下做。

根治方法是不要把这个混乱留给环境变量,而是记住一条规矩:涉及 QGIS 的操作,永远先在终端里执行o4w_env.bat,这个脚本会把 QGIS 相关的路径插到PATH前面,压制掉其他 Python。养成这个习惯,能避免大量"明明配好了却报错"的困惑。

6.3 改了代码没生效的三层原因

这个现象我遇到过三种完全不同的成因,排查顺序是从外到内。

第一层,代码没到 QGIS 会读取的位置。你在编辑器工作区改的是源目录里的文件,但 QGIS 加载的是 profile 目录下的插件。这两个目录如果没做链接或同步,改了源目录等于没改。解决办法是用pb_tool deploy同步,或者在 profile 目录里做符号链接(Windows 下用mklink /D)。

第二层,代码到了但模块没重新加载。Python 的模块一旦被导入就缓存在sys.modules里,改文件不会自动重新执行。所以要么用 Plugin Reloader,要么在 Python 控制台里调qgis.utils.reloadPlugin()。注意新加的文件有时热重载识别不到,这种情况还是得重启。

第三层,代码加载了但走的是缓存。这种最少见但最迷惑:.pyc缓存文件、或者插件自己在某个地方存了配置/状态,导致看起来"行为没变"。清掉插件目录下的__pycache__文件夹,重启 QGIS,基本能解决。

一个顺手的小习惯:在插件主类的initGui里加一行版本日志:

QgsMessageLog.logMessage("MyPlugin v0.1.3 loaded", "MyPlugin")

每次重载后看一眼日志里的版本号,就知道到底加载的是不是最新代码。这一行花费几秒钟,省下的排查时间是以小时计的。

6.4 多版本 QGIS 共存时的切换办法

如果你的工作需要同时维护面向不同 QGIS 版本的插件,多版本共存是必须的。安装时把不同版本装到不同目录,比如C:\Program Files\QGIS 3.28.0\和C:\Program Files\QGIS 3.34.0\,互不干扰。

切换的关键在 profile。不同版本的 QGIS 使用的 profile 目录其实是可以共用的(都在%APPDATA%\QGIS\QGIS3\下),但共享 profile 会导致插件列表和设置混在一起。更干净的做法是给每个版本建独立 profile:

"C:\Program Files\QGIS 3.28.0\bin\qgis-ltr-bin.exe" --profile qgis328 "C:\Program Files\QGIS 3.34.0\bin\qgis-ltr-bin.exe" --profile qgis334

这样两个版本的配置完全隔离,插件各自装各自的。开发插件时,同一个源目录可以通过pb_tool分别部署到两个 profile 的插件目录下,测试一遍就能确认跨版本兼容性。

编辑器这边的处理是:为每个 QGIS 版本建一个独立的 VS Code 工作区,settings.json里的解释器路径、extraPaths分别指向对应版本的目录。切工作区就等于切环境,避免手工改路径。

最后再提一个容易被忽略的点:profile 名字一旦确定就别随便改。改了之后 QGIS 会当成一个全新的 profile,之前的插件启用状态、界面布局全丢,你会以为出问题了。

我个人在这个话题上的体会是,QGIS 插件开发的环境配置难点不在于步骤多,而在于"环境是外部给的"这件事。普通 Python 项目里你几乎不需要关心解释器怎么来的,而这里必须把解释器、环境变量、加载路径这三件事想明白。想明白之后,配置本身十分钟就能做完;想不明白的话,可能折腾一整天还在报同一个错。所以我通常建议新手先花半小时把o4w_env.bat里到底设了哪些变量打印出来看一遍,那几十行输出,比任何教程都直观。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询