QGIS插件开发(Python+Qgis+pyqt+pycharm)

在最近的实习课程中,我们老师要求我们使用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                : sueyeah@whu.edu.cn
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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                : sueyeah@whu.edu.cn
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   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文件,无需更改

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值