PyQGIS开发 3 基础功能开发

PyQGIS开发 3 基础功能开发

1 添加图层树与地图视图

1.1 添加控件

1.2 Python代码

from PyQt5.QtCore import QMimeData
from qgis.PyQt.QtWidgets import QMainWindow
from qgis._core import QgsMapLayer, QgsRasterLayer, QgsVectorLayer
from qgis.core import QgsProject, QgsLayerTreeModel
from qgis.gui import QgsLayerTreeView, QgsMapCanvas, QgsLayerTreeMapCanvasBridge
import os.path as osp
from ui.mainWindow import Ui_MainWindow
from PyQt5.QtWidgets import QVBoxLayout, QHBoxLayout, QFileDialog, QMessageBox

PROJECT = QgsProject.instance()


class MainWindow(QMainWindow, Ui_MainWindow):
    def __init__(self):
        """
        MainWindow 类的初始化函数。

        该函数初始化 MainWindow 类的实例,设置窗口标题、初始化图层树、地图画布、
        图层树视图模型、建立图层树与地图画布的桥接,并注册界面事件功能。
        """
        super(MainWindow, self).__init__()
        self.setupUi(self)
        # 1 修改标题
        self.setWindowTitle("QGIS自定义界面")
        # 2 初始化图层树
        vl = QVBoxLayout(self.dockWidgetContents)
        self.layerTreeView = QgsLayerTreeView(self)
        vl.addWidget(self.layerTreeView)
        # 3 初始化地图画布
        self.mapCanvas = QgsMapCanvas(self)
        hl = QHBoxLayout(self.frame)
        hl.setContentsMargins(0, 0, 0, 0)  # 设置周围间距
        hl.addWidget(self.mapCanvas)
        # 4 设置图层树风格
        self.model = QgsLayerTreeModel(PROJECT.layerTreeRoot(), self)
        self.model.setFlag(QgsLayerTreeModel.AllowNodeRename)  # 允许图层节点重命名
        self.model.setFlag(QgsLayerTreeModel.AllowNodeReorder)  # 允许图层拖拽排序
        self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility)  # 允许改变图层节点可视性
        self.model.setFlag(QgsLayerTreeModel.ShowLegendAsTree)  # 展示图例
        self.model.setAutoCollapseLegendNodes(10)  # 当节点数大于等于10时自动折叠
        self.layerTreeView.setModel(self.model)
        # 4 建立图层树与地图画布的桥接
        self.layerTreeBridge = QgsLayerTreeMapCanvasBridge(PROJECT.layerTreeRoot(), self.mapCanvas, self)
        # 注册界面事件功能
        self.registerFunc()
        # 5 初始加载影像
        self.firstAdd = True
        # 6 允许拖拽文件
        self.setAcceptDrops(True)

    def registerFunc(self):
        """
        注册动作的触发函数

        该函数将动作与对应的触发函数连接起来,使得当用户点击动作时,相应的函数会被触发
        """
        self.actionOpenRaster.triggered.connect(self.actionOpenRasterTriggered)
        self.actionOpenVector.triggered.connect(self.actionOpenVectorTriggered)


    def actionOpenRasterTriggered(self):
        """
        处理打开栅格文件的触发事件

        此方法通过 QFileDialog 弹出文件选择对话框,获取用户选择的栅格文件路径。
        如果用户选择了文件,将调用 addRasterLayer 方法添加该文件对应的栅格图层到窗口中。

        参数:
            None

        返回值:
            无

        异常: 
            如果文件选择对话框取消或出错,不会添加任何图层。
        """
        data_file, ext = QFileDialog.getOpenFileName(
            self,
            '打开',
            '',
            'GeoTiff(*.tif;*tiff;*TIF;*TIFF);;All Files(*);;JPEG(*.jpg;*.jpeg;*.JPG;*.JPEG);;*.png;;*.pdf')
        if data_file:
            self.addRasterLayer(data_file)


    def actionOpenVectorTriggered(self):
        """
        处理打开矢量文件的触发事件

        此方法通过 QFileDialog 弹出文件选择对话框,获取用户选择的矢量文件路径。
        如果用户选择了文件,将调用 addVectorLayer 方法添加该文件对应的矢量图层到窗口中。

        参数:
            None

        返回值:
            无

        异常: 
            如果文件选择对话框取消或出错,不会添加任何图层。
        """
        data_file, ext = QFileDialog.getOpenFileName(
            self, '打开', '',
            "ShapeFile(*.shp);;All Files(*);;Other(*.gpkg;*.geojson;*.kml)")
        if data_file:
            self.addVectorLayer(data_file)


    def addRasterLayer(self, rasterFilePath):
        """
        将栅格图层添加到地图画布中。

        此方法用于将栅格文件加载为栅格图层,并将其添加到地图画布中显示。如果是第一次添加图层,它会作为基础图层添加,并设置为可编辑状态。否则,它会作为普通图层添加。

        参数:
            rasterFilePath (str): 要添加的栅格文件的路径。

        返回:
            无

        注意:
            如果文件路径无效或文件无法加载为栅格图层,则不会添加任何图层。
        """
        # 读取栅格文件并创建栅格图层
        raster_layer = self.readRasterFile(rasterFilePath)

        # 如果是首次添加图层,则将其作为基础图层添加到地图画布,并设置为可编辑
        if self.firstAdd:
            self.addMapLayer(raster_layer, self.mapCanvas, True)
            self.firstAdd = False
        # 否则,将其作为普通图层添加到地图画布
        else:
            self.addMapLayer(raster_layer, self.mapCanvas)


    def addVectorLayer(self, vectorFilePath):
        """
         向当前QGIS项目中添加一个新的矢量图层,并显示在地图画布上。
        
         参数:
            vectorFilePath (str): 要添加的矢量文件的路径。
            
         返回:
            None
        """
        vector_layer = self.readVectorFile(vectorFilePath)
        if self.firstAdd:
            self.addMapLayer(vector_layer, self.mapCanvas, True)
            self.firstAdd = False
        else:
            self.addMapLayer(vector_layer, self.mapCanvas)


    def addMapLayer(self, layer: QgsMapLayer, mapCanvas: QgsMapCanvas, firstAddLayer=False):
        """
        将地图层添加到 QGIS 项目和地图画布中。
        
        参数:
            layer (QgsMapLayer):要添加的地图层。
            mapCanvas (QgsMapCanvas):地图画布,用于显示地图层。
            firstAddLayer (bool):是否是第一次添加图层。如果是,将设置画布的 CRS 和范围。
        
        返回:
            无
        
        注意:
            如果图层已经存在,它将重命名以避免冲突。如果图层无效,它将不会被添加。
        """
        # 检查图层是否有效
        if layer.isValid():
            # 如果是第一次添加图层,设置画布的 CRS 和范围
            if firstAddLayer:
                mapCanvas.setDestinationCrs(layer.crs())
                mapCanvas.setExtent(layer.extent())

            # 确保图层名称唯一
            while PROJECT.mapLayersByName(layer.name()):
                layer.setName(layer.name() + "_1")

            # 将图层添加到项目中
            PROJECT.addMapLayer(layer)

            # 更新画布的图层列表并刷新
            layers = [layer] + [PROJECT.mapLayer(i) for i in PROJECT.mapLayers()]
            mapCanvas.setLayers(layers)
            mapCanvas.refresh()

    def readRasterFile(self, rasterFilePath: str) -> QgsRasterLayer:
        """
        从给定的文件路径中读取栅格文件,并返回相应的 QgsRasterLayer 对象。

        参数:
            rasterFilePath (str):要读取的栅格文件的完整路径。

        返回:
            QgsRasterLayer:如果成功读取文件,则返回相应的 QgsRasterLayer 对象;否则返回 None。
        """
        raster_layer = QgsRasterLayer(rasterFilePath, osp.basename(rasterFilePath))
        return raster_layer

    def readVectorFile(self, vectorFilePath):
        """
        从给定的文件路径中读取矢量文件,并返回相应的 QgsVectorLayer 对象。

        参数:
            vectorFilePath (str): 要读取的矢量文件的完整路径。

        返回:
            QgsVectorLayer: 如果成功读取文件,则返回相应的 QgsVectorLayer 对象;否则返回 None。
        """
        vector_layer = QgsVectorLayer(vectorFilePath, osp.basename(vectorFilePath), "ogr")
        return vector_layer

    def dragEnterEvent(self, fileData):
        """
        处理拖放文件进入窗口的事件。

        如果拖放的文件是URL类型,则接受事件;否则,忽略事件。

        参数:
        fileData - 拖放事件的数据。

        返回:
        None
        """
        if fileData.mimeData().hasUrls():
            fileData.accept()
        else:
            fileData.ignore()


    def dropEvent(self, fileData):
        """
        处理拖放事件,根据文件类型添加对应的图层到QGIS中

        参数:
        fileData (QDragEnterEvent): 拖放事件对象

        返回:
        None
        """
        mimeData: QMimeData = fileData.mimeData()
        filePathList = [u.path()[1:] for u in mimeData.urls()]
        for filePath in filePathList:
            filePath: str = filePath.replace("/", "//")
            if filePath.split(".")[-1] in ["tif", "TIF", "tiff", "TIFF", "GTIFF", "png", "jpg", "pdf"]:
                self.addRasterLayer(filePath)
            elif filePath.split(".")[-1] in ["shp", "SHP", "gpkg", "geojson", "kml"]:
                self.addVectorLayer(filePath)
            elif filePath == "":
                pass
            else:
                QMessageBox.about(self, '警告', f'{filePath}为不支持的文件类型,目前支持栅格影像和shp矢量')

    def getRasterLayerAttrs(self, rasterLayer: QgsRasterLayer):
        print("name: ", rasterLayer.name())  # 图层名
        print("type: ", rasterLayer.type())  # 栅格还是矢量图层
        print("height - width: ", rasterLayer.height(), rasterLayer.width())  # 尺寸
        print("bands: ", rasterLayer.bandCount())  # 波段数
        print("extent", rasterLayer.extent())  # 外接矩形范围
        print("source", rasterLayer.source())  # 图层的源文件地址
        print("crs", rasterLayer.crs())  # 图层的坐标系统

    def getVectorLayerAttrs(self, vectorLayer: QgsVectorLayer):
        print("name: ", vectorLayer.name())  # 图层名
        print("type: ", vectorLayer.type())  # 栅格还是矢量图层
        print("extent", vectorLayer.extent())  # 外接矩形范围
        print("source", vectorLayer.source())  # 图层的源文件地址
        print("crs", vectorLayer.crs())  # 图层的坐标系统

1.3 实现效果

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Winemonk

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值