16.1. 构建Python插件

创建插件的主要步骤是:

  1. Idea :对您想要用新的QGIS插件做什么有一个想法。

  2. SetupCreate the files for your plugin 。根据插件类型的不同,有些是必选的,有些是可选的

  3. DevelopWrite the code 在适当的文件中

  4. DocumentWrite the plugin documentation

  5. 可选的: TranslateTranslate your plugin 翻译成不同的语言

  6. TestReload your plugin 检查是否一切正常

  7. Publish :在QGIS库中发布您的插件,或者将您自己的库作为个人“GIS武器”的“武器库”。

16.1.1. 快速入门

在开始编写新插件之前,先看一下 官方的Python插件存储库 。现有插件的源代码可以帮助您了解更多编程知识。您可能还会发现已经存在一个类似的插件,您可以扩展它,或者至少在它的基础上开发您自己的插件。

16.1.1.1. 设置插件文件结构

要开始使用新插件,我们需要设置必要的插件文件。

有两个插件模板资源可以帮助您入门:

  • 出于教育目的或需要极简主义方法时, minimal plugin template 提供创建有效的QGIS Python插件所需的基本文件(框架)。

  • 要获得功能更全的插件模板,请参阅 Plugin Builder 可以为多种不同的插件类型创建模板,包括本地化(翻译)和测试等功能。

典型的插件目录包括以下文件:

  • metadata.txt - required -包含插件网站和插件基础设施使用的一般信息、版本、名称和其他一些元数据。

  • __init__.py - required -插件的起点。它必须有 classFactory() 方法,并且可以具有任何其他初始化代码。

  • mainPlugin.py - core code -插件的主要工作代码。包含有关插件操作和主代码的所有信息。

  • form.ui - for plugins with custom GUI -Qt Designer创建的图形用户界面。

  • form.py - compiled GUI -将上面描述的form.ui翻译成Python。

  • resources.qrc - optional -由Qt Designer创建的.xml文档。包含指向在图形用户界面窗体中使用的资源的相对路径。

  • resources.py - compiled resources, optional -将上述.qrc文件转换为Python。

警告

如果您计划将该插件上载到 官方的Python插件存储库 您必须检查您的插件是否遵循插件所需的一些附加规则 验证

16.1.2. 编写插件代码

以下部分显示了应该在上面介绍的每个文件中添加哪些内容。

16.1.2.1. metadata.txt

首先,插件管理器需要检索一些关于插件的基本信息,比如它的名称、描述等。 metadata.txt

备注

所有元数据必须采用UTF-8编码。

元数据名称

必填项

备注

名字

千真万确

包含插件名称的短字符串

QgisMinimumVersion

千真万确

QGIS最低版本的虚线记法

QgisMaximumVersion

错误

最高QGIS版本的虚线记法

描述

千真万确

描述插件的短文本,不允许使用HTML语言

关于

千真万确

详细描述插件的较长文本,不允许使用HTML

版本

千真万确

带有版本点符号的短字符串

作者

千真万确

作者姓名

电子邮件

千真万确

作者的电子邮件,仅在网站上显示给登录的用户,但在插件安装后在插件管理器中可见

更改日志

错误

字符串,可以是多行,不允许使用HTML

试验性

错误

布尔标志, TrueFalse - True 如果这个版本是实验性的

弃用

错误

布尔标志, TrueFalse ,适用于整个插件,而不仅仅是上传的版本

标签

错误

逗号分隔的列表,单个标记内允许有空格

首页

错误

指向插件主页的有效URL

存储库

千真万确

源代码存储库的有效URL

跟踪器

错误

票证和错误报告的有效URL

图标

错误

Web友好图像(PNG、JPEG)的文件名或相对路径(相对于插件压缩包的基本文件夹)

范畴

错误

其中之一 RasterVectorDatabaseMeshWeb

plugin_dependencies

错误

要安装的其他插件的列表以逗号分隔,使用来自其元数据的名称字段的插件名称

伺服器

错误

布尔标志, TrueFalse ,确定插件是否具有服务器接口

HasProcessingProvider

错误

布尔标志, TrueFalse ,确定插件是否提供处理算法

默认情况下,插件放置在 Plugins 菜单(我们将在下一节中看到如何为您的插件添加菜单项),但它们也可以放置在 RasterVectorDatabaseMeshWeb 菜单。

存在相应的“类别”元数据条目来指定这一点,因此可以相应地对插件进行分类。这个元数据条目被用作对用户的提示,并告诉他们在哪里(在哪个菜单中)可以找到插件。“类别”的允许值为:矢量、栅格、数据库或Web。例如,如果您的插件将从 Raster 菜单中,将此内容添加到 metadata.txt

category=Raster

备注

如果 qgisMaximumVersion 为空,则它将自动设置为主要版本+ .99 上载到 官方的Python插件存储库

此metadata.txt的示例

; the next section is mandatory

[general]
name=HelloWorld
email=me@example.com
author=Just Me
qgisMinimumVersion=3.0
description=This is an example plugin for greeting the world.
    Multiline is allowed:
    lines starting with spaces belong to the same
    field, in this case to the "description" field.
    HTML formatting is not allowed.
about=This paragraph can contain a detailed description
    of the plugin. Multiline is allowed, HTML is not.
version=version 1.2
tracker=http://bugs.itopen.it
repository=http://www.itopen.it/repo
; end of mandatory metadata

; start of optional metadata
category=Raster
changelog=The changelog lists the plugin versions
    and their changes as in the example below:
    1.0 - First stable release
    0.9 - All features implemented
    0.8 - First testing release

; Tags are in comma separated value format, spaces are allowed within the
; tag name.
; Tags should be in English language. Please also check for existing tags and
; synonyms before creating a new one.
tags=wkt,raster,hello world

; these metadata can be empty, they will eventually become mandatory.
homepage=https://www.itopen.it
icon=icon.png

; experimental flag (applies to the single version)
experimental=True

; deprecated flag (applies to the whole plugin and not only to the uploaded version)
deprecated=False

; if empty, it will be automatically set to major version + .99
qgisMaximumVersion=3.99

; Since QGIS 3.8, a comma separated list of plugins to be installed
; (or upgraded) can be specified.
; The example below will try to install (or upgrade) "MyOtherPlugin" version 1.12
; and any version of "YetAnotherPlugin".
; Both "MyOtherPlugin" and "YetAnotherPlugin" names come from their own metadata's
; name field
plugin_dependencies=MyOtherPlugin==1.12,YetAnotherPlugin

16.1.2.2. __init__.py

该文件是Python的导入系统所必需的。此外,QGIS要求该文件包含一个 classFactory() 函数,当插件加载到QGIS中时调用。它接收对 QgisInterface 方法返回插件类的对象。 mainplugin.py -在我们的案例中,它叫做 TestPlugin (见下文)。这就是为什么 __init__.py 应该看起来像

def classFactory(iface):
  from .mainPlugin import TestPlugin
  return TestPlugin(iface)

# any other initialisation needed

16.1.2.3. mainPlugin.py

这就是魔术发生的地方,这就是魔术的样子: mainPlugin.py )

from qgis.PyQt.QtGui import *
from qgis.PyQt.QtWidgets import *

# initialize Qt resources from file resources.py
from . import resources

class TestPlugin:

  def __init__(self, iface):
    # save reference to the QGIS interface
    self.iface = iface

  def initGui(self):
    # create action that will start plugin configuration
    self.action = QAction(QIcon("testplug:icon.png"),
                          "Test plugin",
                          self.iface.mainWindow())
    self.action.setObjectName("testAction")
    self.action.setWhatsThis("Configuration for test plugin")
    self.action.setStatusTip("This is status tip")
    self.action.triggered.connect(self.run)

    # add toolbar button and menu item
    self.iface.addToolBarIcon(self.action)
    self.iface.addPluginToMenu("&Test plugins", self.action)

    # connect to signal renderComplete which is emitted when canvas
    # rendering is done
    self.iface.mapCanvas().renderComplete.connect(self.renderTest)

  def unload(self):
    # remove the plugin menu item and icon
    self.iface.removePluginMenu("&Test plugins", self.action)
    self.iface.removeToolBarIcon(self.action)

    # disconnect form signal of the canvas
    self.iface.mapCanvas().renderComplete.disconnect(self.renderTest)

  def run(self):
    # create and show a configuration dialog or something similar
    print("TestPlugin: run called!")

  def renderTest(self, painter):
    # use painter for drawing to map canvas
    print("TestPlugin: renderTest called!")

唯一必须存在于主插件源文件中的插件函数(例如 mainPlugin.py )包括:

  • __init__ 这使您可以访问QGIS界面

  • initGui() 在加载插件时调用

  • unload() 在卸载插件时调用

在上面的示例中, addPluginToMenu() 使用的是。这会将相应的菜单操作添加到 Plugins 菜单。存在将该动作添加到不同菜单的替代方法。以下是这些方法的列表:

它们的语法都与 addPluginToMenu() 方法。

建议将插件菜单添加到其中一个预定义的方法中,以保持插件条目组织方式的一致性。但是,您可以将自定义菜单组直接添加到菜单栏中,如下例所示:

def initGui(self):
    self.menu = QMenu(self.iface.mainWindow())
    self.menu.setObjectName("testMenu")
    self.menu.setTitle("MyMenu")

    self.action = QAction(QIcon("testplug:icon.png"),
                          "Test plugin",
                          self.iface.mainWindow())
    self.action.setObjectName("testAction")
    self.action.setWhatsThis("Configuration for test plugin")
    self.action.setStatusTip("This is status tip")
    self.action.triggered.connect(self.run)
    self.menu.addAction(self.action)

    menuBar = self.iface.mainWindow().menuBar()
    menuBar.insertMenu(self.iface.firstRightStandardMenu().menuAction(),
                       self.menu)

def unload(self):
    self.menu.deleteLater()

别忘了设置 QActionQMenu objectName 设置为特定于您的插件的名称,以便可以对其进行定制。

虽然也可以将帮助和关于操作添加到您的自定义菜单中,但使它们可用的一个方便位置是在QGIS Main中 Help ► Plugins 菜单。这是通过使用 pluginHelpMenu() 方法。

def initGui(self):

    self.help_action = QAction(
        QIcon("testplug:icon.png"),
        self.tr("Test Plugin..."),
        self.iface.mainWindow()
    )
    # Add the action to the Help menu
    self.iface.pluginHelpMenu().addAction(self.help_action)

    self.help_action.triggered.connect(self.show_help)

@staticmethod
def show_help():
    """ Open the online help. """
    QDesktopServices.openUrl(QUrl('https://docs.qgis.org'))

def unload(self):

    self.iface.pluginHelpMenu().removeAction(self.help_action)
    del self.help_action

在处理真正的插件时,明智的做法是在另一个(工作)目录中编写该插件,并创建一个Makefile,该文件将生成UI+资源文件并将该插件安装到您的QGIS安装中。

16.1.3. 记录插件

该插件的文档可以编写为HTML帮助文件。这个 qgis.utils 模块提供了一个功能, showPluginHelp() 这将以与其他QGIS帮助相同的方式打开帮助文件浏览器。

这个 showPluginHelp() 函数在与调用模块相同的目录中查找帮助文件。它将依次寻找, index-ll_cc.htmlindex-ll.htmlindex-en.htmlindex-en_us.htmlindex.html ,显示它最先找到的任何一个。这里 ll_cc 是QGIS区域设置。这允许在插件中包含文档的多个翻译版本。

这个 showPluginHelp() 函数还可以接受参数PackageName,它标识将显示帮助的特定插件,FileName,它可以替换正在搜索的文件名称中的“index”,以及SECTION,它是浏览器将定位到的文档中的html锚标记的名称。

16.1.4. 翻译插件

只需几个步骤,您就可以设置插件本地化的环境,以便根据您计算机的区域设置,插件将以不同的语言加载。

16.1.4.1. 软件要求

创建和管理所有翻译文件的最简单方法是安装 Qt Linguist 。在基于Debian的GNU/Linux环境中,您可以键入以下命令进行安装:

sudo apt install qttools5-dev-tools

16.1.4.2. 文件和目录

当您创建插件时,您会发现 i18n 主插件目录中的文件夹。

All the translation files have to be within this directory.

16.1.4.2.1. .Pro文件

首先,您应该创建一个 .pro 文件,这是一个 project 可由管理的文件 Qt Linguist

在这 .pro 文件,您必须指定要翻译的所有文件和表单。该文件用于设置本地化文件和变量。一个可能的项目文件,与我们的 example plugin

FORMS = ../form.ui
SOURCES = ../your_plugin.py
TRANSLATIONS = your_plugin_it.ts

您的插件可能遵循更复杂的结构,并且可能分布在多个文件中。如果是这样的话,请记住 pylupdate5 ,我们用来读取 .pro 文件并更新可翻译字符串,不会扩展通配符,因此需要将每个文件显式放置在 .pro 文件。然后,您的项目文件可能如下所示:

FORMS = ../ui/about.ui ../ui/feedback.ui \
        ../ui/main_dialog.ui
SOURCES = ../your_plugin.py ../computation.py \
          ../utils.py

此外, your_plugin.py 文件是指 calls QGIS工具栏中插件的所有菜单和子菜单,并且您想要将它们全部翻译。

最后,使用 TRANSLATIONS 变量,您可以指定所需的翻译语言。

警告

请务必命名 ts 文件类似 your_plugin_ + language + .ts 否则语言加载将失败!使用2个字母的语言快捷方式( it 对于意大利语来说, de 对于德语等...)

16.1.4.2.2. .ts文件

一旦您创建了 .pro 您已经准备好生成 .ts 您的插件的语言(S)的文件(S)。

打开终端,转到 your_plugin/i18n 目录和类型::

pylupdate5 your_plugin.pro

您应该看到 your_plugin_language.ts 档案(S)。

打开 .ts 文件包含 Qt Linguist 然后开始翻译。

16.1.4.2.3. .qm文件

当您完成翻译插件时(如果某些字符串没有完成,将使用这些字符串的源语言),您必须创建 .qm 文件(已编译的 .ts QGIS将使用的文件)。

只需在中打开终端CD your_plugin/i18n 目录和类型::

lrelease your_plugin.ts

现在,在 i18n 目录,您将看到 your_plugin.qm 档案(S)。

16.1.4.3. 使用生成文件进行翻译

或者,如果您使用plugin Builder创建了插件,您也可以使用Makefile从Python代码和Qt对话框中提取消息。在Makefile的开头有一个语言环境变量::

LOCALES = en

将语言的缩写添加到此变量中,例如,匈牙利语::

LOCALES = en hu

现在,您可以生成或更新 hu.ts 文件(和 en.ts 也),来源::

make transup

在此之后,您已更新 .ts 在Locales变量中设置的所有语言的文件。使用 Qt Linguist 翻译程序信息。完成翻译后, .qm 可以通过转换编译创建文件::

make transcompile

你必须分发 .ts 文件与您的插件。

16.1.4.4. 加载插件

要查看插件的翻译,请打开QGIS,更改语言 (Settings ► Options ► General ),并重启QGIS。

您应该看到您的插件使用正确的语言。

警告

如果您更改了插件中的某些内容(新的用户界面、新的菜单等)你不得不 generate again 两者的更新版本 .ts.qm 文件,所以再次运行上面的命令。

16.1.5. 共享您的插件

QGIS在插件存储库中托管了数百个插件。考虑分享你的吧!它将扩展QGIS的可能性,人们将能够从您的代码中学习。所有托管的插件都可以通过插件管理器在QGIS中找到并安装。

信息和要求如下: plugins.qgis.org

16.1.6. 小贴士和小窍门

16.1.6.1. 插件重载器

在您的插件开发过程中,您将经常需要在QGIS中重新加载它以进行测试。这非常容易使用 Plugin Reloader 插件。您可以使用 Plugin Manager

16.1.6.2. 使用qgis-plugin-ci自动打包、发布和翻译

qgis-plugin-ci 提供命令行界面,以在您的计算机上执行QGIS插件的自动打包和部署,或使用诸如 GitHub workflowsGitlab-CI 以及 Transifex 以供翻译。

它允许通过CLI或配置项操作发布、翻译、发布或生成XML插件存储库文件。

16.1.6.3. 访问插件

您可以使用python从QGIS中访问所有已安装插件的类,这对于调试非常方便。

my_plugin = qgis.utils.plugins['My Plugin']

16.1.6.4. 日志消息

插件在 日志消息面板

16.1.6.5. 资源文件

一些插件使用资源文件,例如 resources.qrc 它们定义了图形用户界面的资源,如图标:

<RCC>
  <qresource prefix="/plugins/testplug" >
     <file>icon.png</file>
  </qresource>
</RCC>

最好使用不会与其他插件或QGIS的任何部分冲突的前缀,否则可能会得到不想要的资源。现在,您只需要生成一个将包含资源的Python文件。一切都结束了 pyrcc5 命令:

pyrcc5 -o resources.py resources.qrc

备注

In Windows environments, attempting to run the pyrcc5 from Command Prompt or Powershell will probably result in the error "Windows cannot access the specified device, path, or file [...]". The easiest solution is probably to use the OSGeo4W Shell but if you are comfortable modifying the PATH environment variable or specifiying the path to the executable explicitly you should be able to find it at <Your QGIS Install Directory>\bin\pyrcc5.exe.