QGIS的插件开发(C++&Python)
基于C++
C++插件一般以Dll文件的形式,存放在工程下。当我们使用对应的插件时,会动态加载它。
和Python良好的可移植性不同,Dll文件及其附属一系列的链接库不可以直接加入现有工程。所以,我们采用重新编译的方法来生成对应的Dll文件。
研究思路
QGIS是基于QT开发的开源项目。其中自带有Plugin Builder的插件,利用Plugin Builder,可以直接建立一个插件模板。
然而,Plugin Builder生成的插件模板是Python格式,为了让它能够成为我们希望的Dll格式。
我们将利用Plugin Builder的功能,先生成插件模板源码。再将其加入qgis源码中,重新用C++编译整个qgis工程来生成它。
(本文中将用大小写来区分QGIS Desktop桌面应用和qgis源码)
下载与安装
【本机配置】 Win10 64位
【VS】 2015(2017)
【CMake】 3.10.2
cmake-3.10.2-win64
【QT】 5.11.2
QT的版本应该配合你的qgis源码的版本要求。
同时将QT配置到VS上,QT的下载链接和配置步骤,你可以参考QT5.11.2+VS 2015环境搭建
在上述链接中提供的WinDBG调试器下载需要收费。
这是因为微软将WinDBG调试器在Windows里隐藏起来,所以官方不提供下载服务。这里附上外网链接。
WinDBG Downloads
请根据你的机器配置一样选择合适的版本下载。
【qgis源码】(我的版本是3.2.2)
本例中对版本无强制要求,你可以在这里下载较新的版本
qgis-latest
同时辅助下载Cygwins,OSGeo4W等,具体各版本的要求和下载链接,你可以参考
QGIS+QT5+VS2015(2017)的编译
【Plugin Builder源码】
Plugin Builder是一个同QGIS版本变化同步更新的一个插件。
如果你有下载安装过QGIS Desktop,你会发现他的Plugin Builder插件有所更改,名为Plugin Builder 3
同时在3版本以上的qgis源码中,我们找不到Plugin Builder的源码。
(本文中将用Plugin Builder和Plugin Builder 3分别表示不同版本的PluginBuilder插件)
而目前提供的Plugin Builder(包含CMakeList)源码,还使用早期QT4和Python2的编译规则。
所以,如果你下载的源码版本是较新的(3版本以上),你还需要下载qgis-ltr(稳定维护版本2.18.25)的源码。
qgis-latest-ltr
在这个版本里,你可以在src/plugins下找到我们需要的Plugin Builder源码
生成插件模板
如果,你对版本情况没有具体要求,你可以直接对qgis-ltr编译。
当然,如果你希望用更新的版本,你可以在把qgis-ltr/src/plugins下的plugin_builder.py和plugin_template文件夹复制到你的源码src/plugins目录下。
我这里用qgis-3.2.2做例。
接下来,准备用cmd运行plugin_builder.py
首先再次强调环境变量path——明确你的环境变量中,是否加入了你qgis源码所对应版本的Python路径。
如果你的电脑没有安装Python,也没有关系。你只需要把OSGeo4W\apps下的Python路径加入即可。
具体步骤和过程同样参考 QGIS+QT5+VS2015(2017)的编译
这里不做赘述。
不同版本的QT处理
现在我们使用的编译环境大多是QT5,所以我们需要对QT版本不同的地方进行修改。
将plugin_template文件夹的 static const QgisPlugin::PLUGINTYPE sPluginType = QgisPlugin::UI
// // Qt4 Related Includes
// #include <QAction>
#include <QToolBar>
static const QString sName = QObject::tr( "[menuitemname]" );
static const QString sDescription = QObject::tr( "[plugindescription]" );
static const QString sCategory = QObject::tr( "[plugincategory]" );
static const QString sPluginVersion = QObject::tr( "Version 0.1" );
static const QgisPlugin::PLUGINTYPE sPluginType = QgisPlugin::UI;
static const QString sPluginIcon = ":/[pluginlcasename]/[pluginlcasename].png";
改为static const QgisPlugin::PluginType sPluginType = QgisPlugin::UI
不然,编译时将会出现报错
C2039 “PLUGINTYPE”: 不是“QgisPlugin”的成员
不同版本的Python处理
Python3
如果你的源码是3以上版本,我建议你和源码的配置保持一致,用Python37的环境来运行plugin_builder.py
然而plugin_builder.py使用的是Python2的编译规则。
在Python3中运行会有一些报错。
1)你可以选择自己修改,这里列出几种错误及其修改方式
① Python 2的 print “xxx” 语法错误,在Python 3中需要加上括号:print (“xxx”)
报错为——
SyntaxError: Missing parentheses in call to ‘print’. Did you mean print(“Enter the directory name under qgis/src/plugins/ where your new plugin will be created.”)?
SyntaxError: Missing parentheses in call to ‘print’. Did you mean print(myDir)?
② Python 2的raw_input( )函数,Python3版本后用input( )替换了raw_input( )
报错为——
NameError: name ‘raw_input’ is not defined
③ Python3在readlines里,缺省会使用操作系统当前的编码来解析文件,比如windows下就用GBK。所以会出现读取txt文件错误的情况。解决的办法是在对应的文件open( )里补上参数 encoding=‘utf-8’
//例如,Python2
fi= open('somefile.txt', 'r')
//Python3中修改为
fi= open('somefile.txt', 'rt',encoding='utf-8')
2)你也可以直接复制以下代码,用记事本打开plugin_builder.py全部替换即可。
# plugin_builder.py build in Python3
#!/usr/bin/python
"""
***************************************************************************
plugin_builder.py
A script to automate creation of a new QGIS plugin using the plugin_template
--------------------------------------
Date : Sun Sep 16 12:11:04 AKDT 2007
Copyright : (C) Copyright 2007 Martin Dobias
Email : Original authors of Perl version: Gary Sherman and Tim Sutton
**************************************************************************** *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* ****************************************************************************/
"""
import os
import sys
import shutil
import re
def template_file(file):
return os.path.join('plugin_template', file)
def plugin_file(pluginDir, fi