在最近的实习课程中,我们老师要求我们使用pycharm+pyqt+qgis库生成独立应用,然后通过修改将其转换成QGIS插件。通过老师的介绍可知一般情况下一个插件必须包含一下四个文件:
1、初始化文件__init__.py
2、插件主体文件plugin.py
3、生成界面文件form.ui所转换的form.py
4、插件元数据文件meradata.txt
一般情况下,伴随ui文件会有一份资源文件生成,即resources.qrc,如果你的插件没有资源文件,那么将可以直接不要此文件
综合上面的介绍一个插件的结构如下所示:
__init__.py
plugin.py
metadata.txt
form.ui
form.py
plugin_dialog.py
resources.qrc
resources.py
其中:
(1)__init__.py,是插件调用的起点,一般例如版本号、插件名、插件主类等信息会在这里面定义;
(2)plugin.py,插件主体啦,所有的插件操作都必须在这里完成,也是写代码最多的部分;
(3)form.ui,QT-Designer创建的界面文件;
(4)form.py,利用pyucc4.bat转换form.ui所得;
(5)meradata.txt,是插件元数据,描述了插件的基本信息,如版本号,插件名和其他一些插件网址,框架信息等
下面我将一一个例子逐一介绍每一个文件的内容以及该如何更改,例子结构如下所示:
__init__.py
mymain.py
metadata.txt
mypyqgis.ui
mypyqgis.py
mytext_dialog
// metadata.txt
# This file contains metadata for your plugin.
# This file should be included when you package your plugin.# Mandatory items:
[general]
name=plugin name
qgisMinimumVersion=3.0
description=example
version=0.1
author=your name
email=your email
about=Provide a brief description of the plugin and its purpose.
tracker=http://bugs
repository=http://repo
# End of mandatory metadata
# Recommended items:
hasProcessingProvider=no
# Uncomment the following line and add your changelog:
# changelog=
# Tags are comma separated with spaces allowed
tags=python
homepage=http://homepage
category=Plugins
icon=icon.png
# experimental flag
experimental=False
# deprecated flag (applies to the whole plugin, not just a single version)
deprecated=False
# Since QGIS 3.8, a comma separated list of plugins to be installed
# (or upgraded) can be specified.
# Check the documentation for more information.
# plugin_dependencies=
Category of the plugin: Raster, Vector, Database or Web
# category=
# If the plugin can run on QGIS Server.
server=False
对于metadata.txt文件,你基本不需要更改,一般情况下根据个人情况更改一下以下内容即可:
name=plugin name
qgisMinimumVersion=3.0
description=example
version=0.1
author=your name
email=your email
// __init__.py
# -*- coding: utf-8 -*-
def classFactory(iface): # pylint: disable=invalid-name
from .mymain import mytext
return mytext(iface)
对于__init__.py部分,你只需将对应包与类名改好即可
// mymain.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
EClass
A QGIS plugin
example
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2020-05-27
git sha : $Format:%H$
copyright : (C) 2020 by sueyeah
email : [email protected]
***************************************************************************/
/***************************************************************************
* *
* 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, sys
from qgis.core import QgsProject, QgsApplication
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction
# Initialize Qt resources from file resources.py
# Import the code for the dialog
from .mytext_dialog import mytext_dialog
import os.path
class mytext:
"""QGIS Plugin Implementation."""
def __init__(self, iface):
self.iface = iface
# initialize plugin directory
self.plugin_dir = os.path.dirname(__file__)
# initialize locale
locale = QSettings().value('locale/userLocale')[0:2]
locale_path = os.path.join(
self.plugin_dir,
'i18n',
'EClass_{}.qm'.format(locale))
if os.path.exists(locale_path):
self.translator = QTranslator()
self.translator.load(locale_path)
QCoreApplication.installTranslator(self.translator)
# Declare instance attributes
self.actions = []
self.menu = self.tr(u'&dome2')
self.first_start = None
# noinspection PyMethodMayBeStatic
def tr(self, message):
return QCoreApplication.translate('mytext', message)
def add_action(
self,
icon_path,
text,
callback,
enabled_flag=True,
add_to_menu=True,
add_to_toolbar=True,
status_tip=None,
whats_this=None,
parent=None):
icon = QIcon(icon_path)
action = QAction(icon, text, parent)
action.triggered.connect(callback)
action.setEnabled(enabled_flag)
if status_tip is not None:
action.setStatusTip(status_tip)
if whats_this is not None:
action.setWhatsThis(whats_this)
if add_to_toolbar:
# Adds plugin icon to Plugins toolbar
self.iface.addToolBarIcon(action)
if add_to_menu:
self.iface.addPluginToMenu(
self.menu,
action)
self.actions.append(action)
return action
def initGui(self):
"""Create the menu entries and toolbar icons inside the QGIS GUI."""
icon_path = 'D:/myplugin/dome2/icon.png'
self.add_action(
icon_path,
text=self.tr(u''),
callback=self.run,
parent=self.iface.mainWindow())
# will be set False in run()
self.first_start = True
def unload(self):
"""Removes the plugin menu item and icon from QGIS GUI."""
for action in self.actions:
self.iface.removePluginMenu(
self.tr(u'&EPlugin'),
action)
self.iface.removeToolBarIcon(action)
def run(self):
"""Run method that performs all the real work"""
# Create the dialog with elements (after translation) and keep reference
# Only create GUI ONCE in callback, so that it will only load when the plugin is started
if self.first_start == True:
self.first_start = False
self.dlg = mytext_dialog()
# show the dialog
self.dlg.show()
# Run the dialog event loop
# result = self.dlg.exec_()
# # # See if OK was pressed
# # if result:
# # # Do something useful here - delete the line containing pass and
# # # substitute with your code.
# # pass
对于mymain.py部分也就是plugin.py部分,需要更改如下内容:
def tr(self, message):
return QCoreApplication.translate(‘mytext’, message)
中的mytext类名
def run(self)函数中的if self.first_start == True:
self.first_start = False
self.dlg = mytext_dialog()
mytext_dialog()修改为对应名称
self.tr(u’&dome2’)这里的dome2 为插件名
// mytext_dialog.py
# -*- coding: utf-8 -*-
"""
/***************************************************************************
EClassDialog
A QGIS plugin
example
Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
-------------------
begin : 2020-05-27
git sha : $Format:%H$
copyright : (C) 2020 by sueyeah
email : [email protected]
***************************************************************************/
/***************************************************************************
* *
* 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, sys
from qgis.core import QgsProject, QgsApplication, QgsVectorLayer
from qgis.gui import QgsMapCanvas, QgsMapToolPan, QgsMapToolZoom, QgsMapToolIdentify
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QMainWindow, QVBoxLayout, QFileDialog
# This loads your .ui file so that PyQt can populate your plugin with the elements from Qt Designer
# FORM_CLASS, _ = uic.loadUiType(os.path.join(
# os.path.dirname(__file__), 'Emodule_dialog_base.ui'))
from .mypyqgis import Ui_MainWindow
class mytext_dialog(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
"""Constructor."""
super(mytext_dialog, self).__init__(parent)
self.setupUi(self)
self.init_mapcanvas()
self.slot_connect()
#信号和槽的连接,建立界面控件与主类中各个函数的响应关系
def slot_connect(self):
self.actionopen_file.triggered.connect(self.action_open_triggered)
self.actionzoom_in.triggered.connect(self.action_zoomin_triggered)
self.actionzoom_out.triggered.connect(self.action_zoomout_triggered)
self.actionpan.triggered.connect(self.action_pan_triggered)
self.actionfull_extent.triggered.connect(self.action_fullextent_triggered)
self.actionsave.triggered.connect(self.action_save_triggered)
#控件+信号+连接函数+各种槽函数
def init_mapcanvas(self):
#实例化地图画布
self.mapCanvas = QgsMapCanvas()
self.mapCanvas.xyCoordinates.connect(self.show_lonlat)
self.mapCanvas.setCanvasColor(Qt.white)
# self.mapCanvas.show()
layout = QVBoxLayout(self.centralwidget)
layout.setContentsMargins(0, 0, 0, 0)
layout.addWidget(self.mapCanvas)
def loadMap(self, fullpath):
print(fullpath)
#打开矢量图层
self.layer = QgsVectorLayer(fullpath, "shp", "ogr")
#注册图层
QgsProject.instance().addMapLayer(self.layer)
self.mapCanvas.setLayers([self.layer])
#设置图层范围
self.mapCanvas.setExtent(self.layer.extent())
self.mapCanvas.refresh()
def action_open_triggered(self):
fullpath, format = QFileDialog.getOpenFileName(self, '打开数据', '', '*.shp')
if os.path.exists(fullpath):
self.loadMap(fullpath)
def action_save_triggered(self):
fullpath,format = QFileDialog.getSaveFileName(self,'保存数据','','*.tif')
if os.path.exists(fullpath):
self.mapCanvas.saveAsImage(fullpath)
def action_zoomin_triggered(self):
self.maptool = QgsMapToolZoom(self.mapCanvas, False)
self.mapCanvas.setMapTool(self.maptool)
def action_zoomout_triggered(self):
self.maptool = QgsMapToolZoom(self.mapCanvas, True)
self.mapCanvas.setMapTool(self.maptool)
def action_pan_triggered(self):
self.maptool = QgsMapToolPan(self.mapCanvas)
self.mapCanvas.setMapTool(self.maptool)
def action_fullextent_triggered(self):
self.mapCanvas.setExtent(self.layer.extent())
self.mapCanvas.refresh()
#显示鼠标点的经纬度信息
def show_lonlat(self, point):
x = point.x()
y = point.y()
self.statusbar.showMessage(f'经度:{x},纬度:{y}')
在mytext_dialog.py部分你可以编写连接槽以及你想实现的功能函数
需要注意的是一下两部分
1、from .mypyqgis import Ui_MainWindow
2、class mytext_dialog(QMainWindow, Ui_MainWindow):
def init(self, parent=None):
“”“Constructor.”""
super(mytext_dialog, self).init(parent)
// mypyqgis.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mypyqgis.ui'
#
# Created by: PyQt5 UI code generator 5.13.0
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 18))
self.menubar.setObjectName("menubar")
self.file = QtWidgets.QMenu(self.menubar)
self.file.setObjectName("file")
self.view = QtWidgets.QMenu(self.menubar)
self.view.setObjectName("view")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.actionopen_file = QtWidgets.QAction(MainWindow)
self.actionopen_file.setObjectName("actionopen_file")
self.actionsave = QtWidgets.QAction(MainWindow)
self.actionsave.setObjectName("actionsave")
self.actionsave_as = QtWidgets.QAction(MainWindow)
self.actionsave_as.setObjectName("actionsave_as")
self.actionzoom_in = QtWidgets.QAction(MainWindow)
self.actionzoom_in.setObjectName("actionzoom_in")
self.actionzoom_out = QtWidgets.QAction(MainWindow)
self.actionzoom_out.setObjectName("actionzoom_out")
self.actionfull_extent = QtWidgets.QAction(MainWindow)
self.actionfull_extent.setObjectName("actionfull_extent")
self.actionpan = QtWidgets.QAction(MainWindow)
self.actionpan.setObjectName("actionpan")
self.file.addAction(self.actionopen_file)
self.file.addAction(self.actionsave)
self.file.addAction(self.actionsave_as)
self.view.addAction(self.actionzoom_in)
self.view.addAction(self.actionzoom_out)
self.view.addAction(self.actionfull_extent)
self.view.addAction(self.actionpan)
self.menubar.addAction(self.file.menuAction())
self.menubar.addAction(self.view.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MyPYQGIS"))
self.file.setTitle(_translate("MainWindow", "文件"))
self.view.setTitle(_translate("MainWindow", "视图"))
self.actionopen_file.setText(_translate("MainWindow", "open file"))
self.actionsave.setText(_translate("MainWindow", "save"))
self.actionsave_as.setText(_translate("MainWindow", "save as"))
self.actionzoom_in.setText(_translate("MainWindow", "zoom in"))
self.actionzoom_out.setText(_translate("MainWindow", "zoom out"))
self.actionfull_extent.setText(_translate("MainWindow", "full extent"))
self.actionpan.setText(_translate("MainWindow", "pan"))
此部分为ui生成的py文件,无需更改