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, QMessageBoxPROJECT = QgsProject. instance( ) class MainWindow ( QMainWindow, Ui_MainWindow) : def __init__ ( self) : """MainWindow 类的初始化函数。该函数初始化 MainWindow 类的实例,设置窗口标题、初始化图层树、地图画布、图层树视图模型、建立图层树与地图画布的桥接,并注册界面事件功能。""" super ( MainWindow, self) . __init__( ) self. setupUi( self) self. setWindowTitle( "QGIS自定义界面" ) vl = QVBoxLayout( self. dockWidgetContents) self. layerTreeView = QgsLayerTreeView( self) vl. addWidget( self. layerTreeView) self. mapCanvas = QgsMapCanvas( self) hl = QHBoxLayout( self. frame) hl. setContentsMargins( 0 , 0 , 0 , 0 ) hl. addWidget( self. mapCanvas) 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 ) self. layerTreeView. setModel( self. model) self. layerTreeBridge = QgsLayerTreeMapCanvasBridge( PROJECT. layerTreeRoot( ) , self. mapCanvas, self) self. registerFunc( ) self. firstAdd = True 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( ) : 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_layerdef readVectorFile ( self, vectorFilePath) : """从给定的文件路径中读取矢量文件,并返回相应的 QgsVectorLayer 对象。参数:vectorFilePath (str): 要读取的矢量文件的完整路径。返回:QgsVectorLayer: 如果成功读取文件,则返回相应的 QgsVectorLayer 对象;否则返回 None。""" vector_layer = QgsVectorLayer( vectorFilePath, osp. basename( vectorFilePath) , "ogr" ) return vector_layerdef 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 实现效果