QGIS二次开发(插件开发)

实习二 QGIS插件开发

2.1 任务要求

a)用C++语言编写qgis插件,实现带有x/y坐标的文本文件的地图显示。

  1. 用文件流fstream操作文本文件,读取其中的坐标数据。
  2. 基于QgsPlugin相关类派生出一个插件,并加到插件工厂中。
  3. 基于QgsVectorLayer创建一个点矢量图层vecLayer,将坐标数据形成要素添加vecLayer中,并将vecLayer添加到mapCavas中进行显示。

b)用python语言编写qgis插件,实现中文地名的解析与地图显示。

  1. 用文件流fstream操作文本文件,读取其中的地名文本数据。
  2. 基于python新建一个qgis功能插件。
  3. 利用腾讯地图服务api,解析地名形成坐标,并将坐标形成要素添加到点图层中进行显示。

2.2 完成过程

2.2.1 C++插件

QGIS的C++插件开发主要是在QGIS软件中新增一个插件,实现将txt文本中带有x/y坐标的文本文件转化为shp文件,加载到QGIS窗口中。具体操作步骤如下:

在确定需要进行 C++插件式开发的时候,结合 QGIS 的插件的特点,这是一种利用dll库进行开发的方式。具体来说,需要在 QGIS 进行以下的设置,也即修改工程的属性,将输出的文件的方式更改为以.dll 作为后缀名的文件。如图2.2.1-1所示

图2.2.1-1 修改配置类型

这里的设计插件采用的空的QT Widget 窗口,设计的窗口的显示内容如图中所示, 这里的窗口设置不同通过Qt Creator创建的,而是通过在代码中重新生成一个Qt Widget 来生成的,同时将其可视化出来,具体的插件的界面显示内容如图2.2.1-2所示。

图2.2.1-2 插件样式

在设计完成插件的界面显示内容之后,可以对原来的代码进行重新编译的操作。首先需要引入一些需要引用到的头文件,如图2.2.1-3所示。

图2.2.1-3 引用头文件

读取输入的文件中的坐标信息,并将读取到的点坐标存储起来。采用的容器是QVector这种动态数组,其中点的坐标对类型为QPointF。读取文件时候,打开的方式采用的是以只读的方式以及文本形式打开文件。在可以成功打开文件之后,采用文件流的方式读取文件中的数据。

文件中存储的坐标每一行都是以类似于“12,23”这种方式进行存储的,因此每一行选用“,”作为分割符,从而可以成功获取每一个点的坐标信息。代码如图2.2.1-4所示。

图2.2.1-4 坐标读取文件

在C++中创建点图层的方式与Python中是十分类似的,不同之处在于在Python中使用GDAL库创建shp文件的时候,需要显式地进行驱动的注册。但是在C++中可以直接通过调用QGIS的接口来隐去部分操作。

具体来说,在C++中首先是注册了一个点矢量图层,之后在点矢量图层中创建了一系列的字段并提交了更改。之后根据上面已经得到的文件中的各个点的坐标数组,对其进行遍历。创建相应的feature,为每一个要素设置对应的字段信息以及相应的几何信息、属性信息。之后将每一个要素的信息添加到图层组的要素信息组中。最后调用QgsVectorFileWriter()函数实现shp文件的创建。主要需要传入的参数包括图层信息,输出文件名,编码格式,坐标系统信息以及矢量文件的格式信息等。至此,一个点矢量图层即已被成功创建。代码如图2.2.1-5所示。

图2.2.1-5 shp文件创建

点击上方的运行,即可在对应项目文件下的Release文件夹中输出封装好插件功能的动态链接库“ceshi.dll”文件。如图2.2.1-6所示。

图2.2.1-6 编译测试插件

将编译输出得到的dll文件复制到QGIS安装文件夹的【apps】-【qgis-ltr】-【plugins】文件夹中,操作如图2.2.2-7所示。

图2.2.1-7 安装插件

至此,可以在 QGIS 中的菜单栏中看到加载的插件,如下图中的红框中所显示的内容,插件的名称叫做"test",点击按钮。至此,插件已经成功加载到对应的窗口位置中。在插件窗口中输入文件地址为“坐标.txt”,如图2.2.1-8所示。

图2.2.1-8 坐标文本文件

点击save 按钮,弹出选择存储文件结果的框,最终得到的shp文件的显示效果如图2.2.1-9所示。

图2.2.1-9 显示结果

2.2.2 Python插件

QGIS的python插件开发主要是在QGIS软件中新增一个插件geocode tool bar,实现将txt文本中地址数据,通过调用腾讯地理编码服务,解析成经纬度,并写入到shp文件,加载到QGIS窗口中。具体操作步骤如下:

首先,双击QGIS Deskopt启动QGIS软件,进入到主界面,依次在工具栏点击【插件】-【管理并安装插件】-【新插件】,搜索并安装“Plugin Builder”和“Plugin Reloader”。操作如图2.2.2-1所示。

图2.2.2-1 下载并安装插件

下载完两个插件后,可以在【已安装】中检查两个插件是否都安装配置好,如图2.2.2-2所示。

图2.2.2-2 检查插件情况

Tips:这里安装的两个插件,其中Plugin Builder是用来生成QGIS插件Python工程模板工具,而Plugin Reloader则是用来在QGIS中重新加载插件,对插件进行调试的工具。

由于本处应用的是Python进行相关的配置开发,故这里需要检查一下对应的的QGIS的Python版本。打开QGIS,点击Python 控制台图标,打开QGIS中的Python 控制台。输入“QStandardPaths.standardLocations(QStandardPaths.AppDataLocation)”,运行后,即可得到相应的QGIS内置的Python安装位置,操作如图2.2.2-3所示。

图2.2.2-3 检查Python版本

接下来,打开PyCharm,依次点击【File】-【Settings】-【project:工程名】-【Python Interpreter】-【Add】,选择【Virtualenv Environment】中的“Existing environment”,“Interpreter”选择QGIS 3.34.10\bin下的“python-qgis-ltr.bat”文件,这个批处理文件把QGIS的Python环境都配置好了,只要把它设置为解释器,就不需要再配置别的环境变量了。然后点击ok即可。操作如图2.2.2-4所示。

图2.2.2-4 配置Python解释器

配置完成后,不难发现,在QGIS的预设中,就已经提供了GDAL和shapely、PyQt5等二次开发库。如图2.2.2-5所示。

图2.2.2-5 检查Python解释器

配置完成python的环境后,回到QGIS,在工具栏重要依次点击【插件】-【Plugin Builder】-【Plugin Builder】。然后填写好插件信息,点击next。操作如图2.2.2-6所示。

图2.2.2-6 填写插件信息

接下来填写插件说明,这里内容可以不必细纠,填写完点击next。操作如图2.2.2-7所示。

图2.2.2-7 插件说明

接下来,在【Template】选择“Tool button with dialog”,即带工具按钮的对话框。并填写【Text for the menu item】为“”,将【Menu】选择为“Plugins”,接下来这个插件会在工具的【Plugins】目录下。然后点击next。操作如图2.2.2-8所示。

图2.2.2-8 插件选择

这里的国际化、帮助、单元测试、帮助脚本等都默认勾选,点击next。操作如图2.2.2-9所示。

图2.2.2-9 插件勾选

接下来勾选“Flag the plugin as experimental”,标识为测试插件,别的保持默认就行,点击next。操作如图2.2.2-10所示。

图2.2.2-10 测试插件

最后是为创建的工程选择一个路径,路径是一个文件夹,点击“Generate”。操作如图2.2.2-11所示。

图2.2.2-11 创建插件位置

接下来,会弹出创建结果,即“You just built a plugin for QGIS!”如图2.2.2-12所示。

图2.2.2-12 创建结果

完成新建插件的设置后,即可得到相应的项目文件夹,由于系统版本原因,这里已经预编译好了项目快捷文件“compile.bat”,并且也出现了对应的插件主体功能文件。如图2.2.2-13所示。

图2.2.2-13 项目文件夹

当然,该文件并没有成功的加入到QGIS的插件中,这里还需要将该文件夹复制到“C:\Users\33439\AppData\Roaming\QGIS\QGIS3\profiles\default\python\plugins”中,再重启QGIS,依次打开工具栏的【插件】-【管理并安装插件】-【已安装】,才能看到新添加的插件。勾选上该插件即会发现该插件的工具图标也在界面上,如图2.2.2-14所示。

图2.2.2-14 新增插件

点击该插件,即可得到插件原始的预设样式,如图2.2.2-15所示。

图2.2.2-15 插件初始打开样式

进行完如上操作,插件的雏形已经有了,接下来要在这个雏形的基础上开发。在开发之前,首先需要把界面重新设置一下。这里可以直接打开文件夹,选择geocode_tool文件夹下的geocode_tool_dialog_base.ui文件,使用QT Creator打开,在主界面选择【界面编辑器】,点击ok。操作如图2.2.2-16所示。

图2.2.2-16 打开ui文件

接下来,在左侧控件栏中,选择对应的控件拖拽到界面上,在右侧属性框中,修改控件的objectName。新增加的文本框和按钮的名称分别是lineEditTxt,lineEditShp,lineEditKey,pushButtonTxt,pushButtonShp。操作最终得到的ui如图2.2.2-17所示。

图2.2.2-17 修改后的ui

接下来,可以回到QGIS软件中检查一下UI是否已经成功被修改。在工具栏中依次打开【插件】-【Plugin Reloader】-【Configure】,打开【Configure Plugin Reloader】对话框。在【Select the plugin you want to reload】中选择“Geocode Tool“,点击ok。操作如图2.2.2-18所示。

图2.2.2-18 更新插件

更新完插件后,再点击一下插件,即可发现插件的UI已经成功更改,如图2.2.2-19所示。

图2.2.2-19 更新ui后的插件

显然,这里界面的ui只是一个壳子,没有槽函数响应信号,因此需要对功能函数进行编码,这里打开文件夹中的“geocode_tool.py”文件进行修改。

首先,需要引入QT库函数,如图2.2.2-20所示。

图2.2.2-20 引入库函数

接下来,新增两个方法select_input_file和select_output_file,用以读取txt文件和shp文件的路径。如图2.2.2-21所示。

图2.2.2-21 新增读写文件路径

完成之后,在run方法中,添加两行代码,调用select_input_file和select_output_file方法,点击pushButtonTxt和pushButtonShp按钮的时候触发。如图2.2.2-22所示。

图2.2.2-22 修改run函数添加按钮触发

接下来新增两个个方法,其中readTxt函数应用于读写txt文件,writeShp函数应用于读写shp文件。如图2.2.2-23所示。

图2.2.2-23 新增读写txt和shp函数

最后新增一个方法geoCode,用于调用腾讯地图API密钥,如图2.2.2-24所示。

图2.2.2-24 新增getcode函数

在run方法的if result后面添加需要执行的代码。如图2.2.2-25所示。

图2.2.-25 显示结果

其中完整的源代码将在2.4节中展示。此处不在赘述。

对代码编译完成后,将所有的文件保存,将插件再次更新,再次点击插件,将对应的txt文件和腾讯地图API密钥输入,选择好输出的shp文件地址,点击“确定”即可得到相应的解析地址。操作如图2.2.2-26所示。

图2.2.2-26 使用插件

在界面上可以看到出现的插件情况和相应的点已被成功解析。如图2.2.2-27所示。

图2.2.2-27 解析情况

同样,可以右键图层打开【属性】,将其【源】中的【数据编码】设置为“UTF-8”如图2.2.2-28所示。

图2.2.2-28 修改数据源

接下来,点击OK,将图层属性表打开,即可看到对应的点的属性信息,打开对应的txt文件发现相符合,如图2.2.2-29所示。

图2.2.2-29 属性表对应txt文件

2.3 结果展示

2.3.1 C++插件结果

QGIS的C++插件开发主要是在QGIS软件中新增一个插件,实现将txt文本中带有x/y坐标的文本文件转化为shp文件,加载到QGIS窗口中。插件如图2.3.1-1所示。

图2.3.1-1 插件样式

当我们使用插件,打开测试数据,并进行转换时,最终可以正确的解析得到两个点坐标的矢量文件,如图2.3.1-2所示。

图2.3.1-2 C++插件使用结果

2.3.2 Python插件结果

QGIS的python插件开发主要是在QGIS软件中新增一个插件geocode tool bar,实现将txt文本中地址数据,通过调用腾讯地理编码服务,解析成经纬度,并写入到shp文件,加载到QGIS窗口中。插件如图2.3.2-1所示。

图2.3.2-1 插件样式

当我们使用插件,打开测试数据,并进行转换时,最终可以正确的解析得到三个点坐标的矢量文件,如图2.3.2-2所示。

图2.3.2-2 Python插件结果

2.4 关键代码

2.4.1 C++插件代码

本处的关键代码为在Visual Studio中配置的文件“ceshi.cpp”中写入的应用QGIS二次开发实现坐标解析转换的源代码:

#include "ceshi.h"
#include "qfiledialog.h"
#include "qapplication.h"
#include "qgsproject.h"
#include "QgsVectorLayer.h"
#include "QgsVectorFileWriter.h"
#include "QString.h"
ceshi::ceshi(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);
}
ceshi::~ceshi()
{}
void ceshi::on_actionOpenProject_triggered()
{
	QString filename = QFileDialog::getOpenFileName(this, QStringLiteral("选择工程文件"), "", "QGIS project (*.qgs)");
	QFileInfo fi(filename);
	if (!fi.exists())
	{
		return;
	}
	QgsProject::instance()->read(filename);
	m_curMapLayer = QgsProject::instance()->mapLayer(0);
}
QVector<QPointF> getcoordinates(QString myfile) {
    QVector<QPointF> coordinates;
    QFile file(myfile);
    if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        QTextStream in(&file);
        while (!in.atEnd()) {
            QString line = in.readLine();
            QStringList parts = line.split(',');
            if (parts.size() == 2) {
                bool okX, okY;
                double x = parts[0].toDouble(&okX);
                double y = parts[1].toDouble(&okY);
                if (okX && okY) {
                    coordinates.append(QPointF(x, y));
                }
            }
        }
        file.close();
        return coordinates;
    }
    else {
        // 如果文件无法打开,可以在这里打印错误信息或处理异常
        qWarning() << "Could not open file:" << myfile;
        return coordinates; // 返回空的 QVector
    }
}
void ceshi::outputButton_clicked() {
    // 获取输入文件路径
    QString myfile = inputFilename->text();
    QVector<QPointF> coordinates = getcoordinates(myfile);
    // 创建一个新的点矢量图层
    QgsVectorLayer* layer = new QgsVectorLayer("Point?crs=EPSG:4326", "pointLayer", "memory");
    if (!layer->isValid()) {
        qWarning() << "Layer creation failed!";
        return;
    }
    // 添加属性字段
    QgsField idField("id", QVariant::Int);
    QgsFields fields;
    fields.append(idField);
    layer->dataProvider()->addAttributes(fields.toList());
    layer->startEditing();
    // 添加字段到图层
    layer->addAttribute(idField);
    layer->commitChanges();
    layer->updateFields();
    // 将点数据添加到图层中
    int id = 1;
    QgsFeatureList features;
    QString myId = "id";
    for (const QPointF& point : coordinates) {
        QgsFeature feature;
        feature.setFields(layer->fields());
        feature.setAttribute(myId, id++);
        feature.setGeometry(QgsGeometry::fromPointXY(QgsPointXY(point.x(), point.y())));
        features.append(feature);
    }
    // 添加特征到图层
    layer->dataProvider()->addFeatures(features);
    layer->updateExtents(); // 更新图层范围
    // 保存图层为 Shapefile
    QString outputFilename = QFileDialog::getSaveFileName(window, tr("Save File"), "", tr("Shapefiles (*.shp)"));
    if (!outputFilename.isEmpty()) {
        if (!outputFilename.endsWith(".shp", Qt::CaseInsensitive)) {
            outputFilename += ".shp";
        }
        QgsVectorFileWriter::writeAsVectorFormat(
            layer, outputFilename, "UTF-8", layer->crs(), "ESRI Shapefile"
        );
    }
}

2.4.2 Python插件代码

本处的关键代码为在Pycharm中打开的文件“geocode_tool.py”中写入的应用QGIS二次开发实现坐标解析转换的源代码:

# -*- coding: utf-8 -*-
"""
/***************************************************************************
 GeocodeTool
                                 A QGIS plugin
 地理编码工具
 Generated by Plugin Builder: http://g-sherman.github.io/Qgis-Plugin-Builder/
                              -------------------
        begin                : 2022-10-11
        git sha              : $Format:%H$
        copyright            : (C) 2022 by tt
        email                : 1404167294@qq.com
 ***************************************************************************/
/***************************************************************************
 *                                                                         *
 *   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.                                   *
 *                                                                         *
 ***************************************************************************/
"""
from qgis.PyQt.QtCore import QSettings, QTranslator, QCoreApplication
from qgis.PyQt.QtGui import QIcon
from qgis.PyQt.QtWidgets import QAction, QFileDialog
from qgis.core import Qgis, QgsProject, QgsVectorLayer
from .geocode_tool_dialog import GeocodeToolDialog
import os.path
import requests
try:
    from osgeo import gdal
    from osgeo import ogr
    from osgeo import osr
except ImportError:
    import gdal
    import ogr
    import osr

class GeocodeTool:
    """QGIS Plugin Implementation."""
    def __init__(self, iface):
        """Constructor.
        :param iface: An interface instance that will be passed to this class
            which provides the hook by which you can manipulate the QGIS
            application at run time.
        :type iface: QgsInterface
        """
        # Save reference to the QGIS interface
        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',
            'GeocodeTool_{}.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'&Geocode Tool')
        # Check if plugin was started the first time in current QGIS session
        # Must be set in initGui() to survive plugin reloads
        self.first_start = None
    # noinspection PyMethodMayBeStatic
    def tr(self, message):
        """Get the translation for a string using Qt translation API.
        We implement this ourselves since we do not inherit QObject.
        :param message: String for translation.
        :type message: str, QString
        :returns: Translated version of message.
        :rtype: QString
        """
        # noinspection PyTypeChecker,PyArgumentList,PyCallByClass
        return QCoreApplication.translate('GeocodeTool', 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):
        """Add a toolbar icon to the toolbar.
        :param icon_path: Path to the icon for this action. Can be a resource
            path (e.g. ':/plugins/foo/bar.png') or a normal file system path.
        :type icon_path: str
        :param text: Text that should be shown in menu items for this action.
        :type text: str
        :param callback: Function to be called when the action is triggered.
        :type callback: function
        :param enabled_flag: A flag indicating if the action should be enabled
            by default. Defaults to True.
        :type enabled_flag: bool
        :param add_to_menu: Flag indicating whether the action should also
            be added to the menu. Defaults to True.
        :type add_to_menu: bool
        :param add_to_toolbar: Flag indicating whether the action should also
            be added to the toolbar. Defaults to True.
        :type add_to_toolbar: bool
        :param status_tip: Optional text to show in a popup when mouse pointer
            hovers over the action.
        :type status_tip: str
        :param parent: Parent widget for the new action. Defaults None.
        :type parent: QWidget
        :param whats_this: Optional text to show in the status bar when the
            mouse pointer hovers over the action.
        :returns: The action that was created. Note that the action is also
            added to self.actions list.
        :rtype: QAction
        """
        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 = ':/plugins/geocode_tool/icon.png'
        self.add_action(
            icon_path,
            text=self.tr(u'geocode tool bar'),
            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'&Geocode Tool'),
                action)
            self.iface.removeToolBarIcon(action)
            # 读txt文件
    def readTxt(self, path_str):
        f = open(path_str, 'r', encoding='utf-8')
        flines = f.readlines()
        address_list = []
        for l in flines:
            address_list.append(l.strip('\n'))
        f.close()
        return address_list
        # 写shp文件
    def writeShp(self, path_str, geocode_list):
        # 支持中文路径
        gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "YES")
        # 属性表字段支持中文
        gdal.SetConfigOption("SHAPE_ENCODING", "UTF-8")
        # 注册驱动
        ogr.RegisterAll()
        # 创建shp数据
        strDriverName = "ESRI Shapefile"
        oDriver = ogr.GetDriverByName(strDriverName)
        if oDriver == None:
            return "驱动不可用:" + strDriverName
        # 创建数据源
        oDS = oDriver.CreateDataSource(path_str)
        if oDS == None:
            return "创建文件失败:" + path_str
        # 创建一个多边形图层,指定坐标系为WGS84
        papszLCO = []
        geosrs = osr.SpatialReference()
        geosrs.SetWellKnownGeogCS("WGS84")
        # 线:ogr_type = ogr.wkbLineString
        # 点:ogr_type = ogr.wkbPoint
        ogr_type = ogr.wkbPoint
        # 面的类型为Polygon,线的类型为Polyline,点的类型为Point
        oLayer = oDS.CreateLayer("Point", geosrs, ogr_type, papszLCO)
        if oLayer == None:
            return "图层创建失败!"
        # 创建属性表
        # 创建id字段
        oId = ogr.FieldDefn("id", ogr.OFTInteger)
        oLayer.CreateField(oId, 1)
        # 创建address、title、level字段
        oAddress = ogr.FieldDefn("address", ogr.OFTString)
        oLayer.CreateField(oAddress, 1)
        oTitle = ogr.FieldDefn("title", ogr.OFTString)
        oLayer.CreateField(oTitle, 1)
        oLevel = ogr.FieldDefn("level", ogr.OFTInteger)
        oLayer.CreateField(oLevel, 1)
        oDefn = oLayer.GetLayerDefn()
        # 创建要素
        # 数据集
        for index, f in enumerate(geocode_list):
            oFeaturePolygon = ogr.Feature(oDefn)
            oFeaturePolygon.SetField("id", index)
            oFeaturePolygon.SetField("address", f['address'])
            oFeaturePolygon.SetField("title", f['title'])
            oFeaturePolygon.SetField("level", f['level'])
            geomPolygon = ogr.CreateGeometryFromWkt(f['point'])
            oFeaturePolygon.SetGeometry(geomPolygon)
            oLayer.CreateFeature(oFeaturePolygon)
        # 创建完成后,关闭进程
        oDS.Destroy()
        return "数据集创建完成!"
    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 = GeocodeToolDialog()
            # 点击按钮,确定路径
            self.dlg.pushButtonTxt.clicked.connect(self.select_input_file)
            self.dlg.pushButtonShp.clicked.connect(self.select_output_file)
        # show the dialog
        self.dlg.show()
        # Run the dialog event loop
        result = self.dlg.exec_()
        # See if OK was pressed
        if result:
            # 获取txt文件路径,shp文件路径,腾讯key
            txtname = self.dlg.lineEditTxt.text()
            shpname = self.dlg.lineEditShp.text()
            tencentkey = self.dlg.lineEditKey.text()
            address_list = self.readTxt(txtname)
            # 读txt文件中的内容,并将geocode结果写入shp
            geocode_list = []
            for address in address_list:
                result = self.geoCode(address, tencentkey)
                if result != None:
                    geocode_list.append(result)
            self.writeShp(shpname, geocode_list)
            # 将结果加载QGIS界面
            layerName = shpname.split("/")[len(shpname.split("/")) - 1].replace(".shp", "")
            vlayer = QgsVectorLayer(shpname, layerName, "ogr")
            if vlayer.isValid():
                QgsProject.instance().addMapLayer(vlayer)
            else:
                print("图层加载失败!")
            pass
            # 在QGIS界面上打印结果
            self.iface.messageBar().pushMessage("成功", "加载图层:" + layerName, level=Qgis.Success, duration=3)
# 加载txt文件的路径
    def select_input_file(self):
        filename,_filter = QFileDialog.getOpenFileName(
            self.dlg,"Select input file","","*.txt"
        )
        self.dlg.lineEditTxt.setText(filename)
    # 导出shp文件的路径
    def select_output_file(self):
        filename,_filter = QFileDialog.getSaveFileName(
            self.dlg,"Select output file","","*.shp"
        )
        self.dlg.lineEditShp.setText(filename)
# 调用腾讯geocode服务
    def geoCode(self, address, key):
        url = 'https://apis.map.qq.com/ws/geocoder/v1/?address=' + address + '&key=' + key
        reponse = requests.get(url=url)
        reponse.encoding = 'utf-8'
        data = reponse.json()
        try:
            if data['status'] == 0:
                return {'address': address, 'title': data['result']['title'],
                        'point': 'POINT(' + str(data['result']['location']['lng']) + ' ' + str(
                            data['result']['location']['lat']) + ')',
                        'level': data['result']['level']}
        except BaseException as e:
            print(e)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值