├── .gitignore ├── PyQGIS.py ├── README.md ├── config.py ├── data ├── point.csv ├── test.html ├── test.tif ├── world.dbf ├── world.prj ├── world.qgs ├── world.shp └── world.shx ├── examples └── qgis_scripts.py ├── images ├── pyqgis.ico ├── pyqgis.png └── splash.png ├── scripts └── build.cmd ├── splash.py ├── test ├── test_crs.py └── test_identify.py ├── ui ├── PostGIS.ui ├── PostGIS_ui.py ├── __init__.py ├── main.ui └── main_ui.py ├── utils ├── __init__.py ├── customMenu.py ├── interface.py └── plugins.py └── widgets ├── PostGIS.py ├── __init__.py ├── attributeDialog.py ├── custom_maptool.py └── mainWindow.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | pip-wheel-metadata/ 24 | share/python-wheels/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | MANIFEST 29 | 30 | # PyInstaller 31 | # Usually these files are written by a python script from a template 32 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 33 | *.manifest 34 | *.spec 35 | 36 | # Installer logs 37 | pip-log.txt 38 | pip-delete-this-directory.txt 39 | 40 | # Unit test / coverage reports 41 | htmlcov/ 42 | .tox/ 43 | .nox/ 44 | .coverage 45 | .coverage.* 46 | .cache 47 | nosetests.xml 48 | coverage.xml 49 | *.cover 50 | *.py,cover 51 | .hypothesis/ 52 | .pytest_cache/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | target/ 76 | 77 | # Jupyter Notebook 78 | .ipynb_checkpoints 79 | 80 | # IPython 81 | profile_default/ 82 | ipython_config.py 83 | 84 | # pyenv 85 | .python-version 86 | 87 | # pipenv 88 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 89 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 90 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 91 | # install all needed dependencies. 92 | #Pipfile.lock 93 | 94 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 95 | __pypackages__/ 96 | 97 | # Celery stuff 98 | celerybeat-schedule 99 | celerybeat.pid 100 | 101 | # SageMath parsed files 102 | *.sage.py 103 | 104 | # Environments 105 | .env 106 | .venv 107 | env/ 108 | venv/ 109 | ENV/ 110 | env.bak/ 111 | venv.bak/ 112 | 113 | # Spyder project settings 114 | .spyderproject 115 | .spyproject 116 | 117 | # Rope project settings 118 | .ropeproject 119 | 120 | # mkdocs documentation 121 | /site 122 | 123 | # mypy 124 | .mypy_cache/ 125 | .dmypy.json 126 | dmypy.json 127 | 128 | # Pyre type checker 129 | .pyre/ 130 | .idea -------------------------------------------------------------------------------- /PyQGIS.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/4/19 16:23 4 | 5 | from qgis.PyQt import QtCore 6 | from qgis.PyQt.QtCore import Qt 7 | from qgis.PyQt.QtGui import QIcon 8 | from qgis.core import QgsApplication 9 | 10 | from config import setup_env 11 | from splash import NewSplashScreen 12 | # from utils.plugins import loadPlugins 13 | # from utils.interface import initInterface 14 | from widgets.mainWindow import MainWindow 15 | 16 | # from qgis.utils import iface 17 | 18 | # 添加插件目录 19 | # os.environ["QGIS_PLUGINPATH"] = r"D:\workspace\QGIS\plugins" 20 | 21 | setup_env() 22 | # 适应高分辨率 23 | QgsApplication.setAttribute(Qt.AA_EnableHighDpiScaling) 24 | # 设置窗口风格 25 | QgsApplication.setStyle("Fusion") 26 | # 创建对QgsApplication的引用,第二个参数设置为False将禁用GUI 27 | qgs = QgsApplication([], True) 28 | 29 | t = QtCore.QTranslator() # 先新建一个 QTranslator 30 | # 加载翻译文件 31 | t.load(r'C:\Program Files\QGIS 3.16\apps\qgis-ltr\i18n\qgis_zh-Hans.qm') 32 | qgs.installTranslator(t) 33 | 34 | # 启动画面 35 | splash = NewSplashScreen() 36 | splash.show() 37 | # 提供qgis安装位置的路径(windows默认:C:\Program Files\QGIS 3.4\apps\qgis-ltr) 38 | qgs.setPrefixPath("qgis", True) 39 | # 初始化 40 | qgs.initQgis() 41 | 42 | # 主窗口 43 | mainWindow = MainWindow() 44 | # 初始化iface 45 | # iface = initInterface(mainWindow) 46 | # 加载插件 47 | # loadPlugins(iface) 48 | # 设置图标 49 | mainWindow.setWindowIcon(QIcon('./images/pyqgis.png')) 50 | splash.finish(mainWindow) 51 | mainWindow.show() 52 | # 脚本完成后,调用exitQgis()从内存中删除提供者和图层注册 53 | qgs.exec_() 54 | qgs.exitQgis() 55 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # PyQGIS 2 | 3 | ![splash](./images/splash.png) 4 | 5 | PyQGIS 二次开发独立应用 6 | 7 | - [环境配置](https://blog.csdn.net/this_is_id/article/details/84562649) 8 | 9 | - [pyinstaller打包](https://blog.csdn.net/this_is_id/article/details/102974721) 10 | 11 | ## 编译 12 | 13 | ```shell 14 | # 管理员运行,基于QGIS 3.16.4测试 15 | 1. "C:\Program Files\QGIS 3.16\bin\python-qgis-ltr.bat" -m pip install pyinstaller 16 | 2. scripts\build.cmd 17 | ``` -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/10/20 17:45 4 | 5 | import os 6 | 7 | _here = os.path.dirname(__file__) 8 | 9 | 10 | def setup_env(): 11 | if not os.path.exists(os.path.join(_here, 'share')): 12 | return 13 | # gdal data 14 | os.environ['GDAL_DATA'] = os.path.join(_here, 'share', 'gdal') 15 | # proj lib 16 | os.environ['PROJ_LIB'] = os.path.join(_here, 'share', 'proj') 17 | # geotiff_csv 18 | os.environ['GEOTIFF_CSV'] = os.path.join(_here, 'share', 'epsg_csv') 19 | # gdalplugins 20 | # os.environ['GDAL_DRIVER_PATH'] = os.path.join(_here, 'gdalplugins') 21 | -------------------------------------------------------------------------------- /data/point.csv: -------------------------------------------------------------------------------- 1 | id,x,y 2 | 0,0,0 3 | 1,10,10 4 | 2,20,20 -------------------------------------------------------------------------------- /data/test.html: -------------------------------------------------------------------------------- 1 |
Driver: GTiff/GeoTIFF
 2 | Files: ../data/test.tif
 3 | Size is 1002, 1002
 4 | Coordinate System is:
 5 | PROJCRS["WGS 84 / Pseudo-Mercator",
 6 |     BASEGEOGCRS["WGS 84",
 7 |         DATUM["World Geodetic System 1984",
 8 |             ELLIPSOID["WGS 84",6378137,298.257223563,
 9 |                 LENGTHUNIT["metre",1]]],
10 |         PRIMEM["Greenwich",0,
11 |             ANGLEUNIT["degree",0.0174532925199433]],
12 |         ID["EPSG",4326]],
13 |     CONVERSION["Popular Visualisation Pseudo-Mercator",
14 |         METHOD["Popular Visualisation Pseudo Mercator",
15 |             ID["EPSG",1024]],
16 |         PARAMETER["Latitude of natural origin",0,
17 |             ANGLEUNIT["degree",0.0174532925199433],
18 |             ID["EPSG",8801]],
19 |         PARAMETER["Longitude of natural origin",0,
20 |             ANGLEUNIT["degree",0.0174532925199433],
21 |             ID["EPSG",8802]],
22 |         PARAMETER["False easting",0,
23 |             LENGTHUNIT["metre",1],
24 |             ID["EPSG",8806]],
25 |         PARAMETER["False northing",0,
26 |             LENGTHUNIT["metre",1],
27 |             ID["EPSG",8807]]],
28 |     CS[Cartesian,2],
29 |         AXIS["easting (X)",east,
30 |             ORDER[1],
31 |             LENGTHUNIT["metre",1]],
32 |         AXIS["northing (Y)",north,
33 |             ORDER[2],
34 |             LENGTHUNIT["metre",1]],
35 |     USAGE[
36 |         SCOPE["unknown"],
37 |         AREA["World - 85°S to 85°N"],
38 |         BBOX[-85.06,-180,85.06,180]],
39 |     ID["EPSG",3857]]
40 | Data axis to CRS axis mapping: 1,2
41 | Origin = (-20037508.342799998819828,20037508.342799998819828)
42 | Pixel Size = (39995.026632335328031,-39995.026632335328031)
43 | Metadata:
44 |   AREA_OR_POINT=Area
45 | Image Structure Metadata:
46 |   INTERLEAVE=PIXEL
47 | Corner Coordinates:
48 | Upper Left  (-20037508.343,20037508.343) (180d 0' 0.00"E, 85d 3' 4.06"N)
49 | Lower Left  (-20037508.343,-20037508.343) (180d 0' 0.00"E, 85d 3' 4.06"S)
50 | Upper Right (20037508.343,20037508.343) (180d 0' 0.00"W, 85d 3' 4.06"N)
51 | Lower Right (20037508.343,-20037508.343) (180d 0' 0.00"W, 85d 3' 4.06"S)
52 | Center      (   0.0000000,   0.0000000) (  0d 0' 0.01"E,  0d 0' 0.01"N)
53 | Band 1 Block=1002x2 Type=Byte, ColorInterp=Red
54 |   Mask Flags: PER_DATASET ALPHA 
55 | Band 2 Block=1002x2 Type=Byte, ColorInterp=Green
56 |   Mask Flags: PER_DATASET ALPHA 
57 | Band 3 Block=1002x2 Type=Byte, ColorInterp=Blue
58 |   Mask Flags: PER_DATASET ALPHA 
59 | Band 4 Block=1002x2 Type=Byte, ColorInterp=Alpha
60 | 
-------------------------------------------------------------------------------- /data/test.tif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/data/test.tif -------------------------------------------------------------------------------- /data/world.dbf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/data/world.dbf -------------------------------------------------------------------------------- /data/world.prj: -------------------------------------------------------------------------------- 1 | GEOGCS["GCS_WGS_1984",DATUM["D_WGS_1984",SPHEROID["WGS_1984",6378137.0,298.257223563]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]] -------------------------------------------------------------------------------- /data/world.qgs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | +proj=longlat +datum=WGS84 +no_defs 11 | 3452 12 | 4326 13 | EPSG:4326 14 | WGS 84 15 | longlat 16 | WGS84 17 | true 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | world_cf93afac_b471_4ac8_98e1_2073f3fd7ffb 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | degrees 37 | 38 | -175.96901840340419199 39 | -94.3037083356420851 40 | 202.03098159659580801 41 | 88.00106766533372138 42 | 43 | 0 44 | 45 | 46 | +proj=longlat +datum=WGS84 +no_defs 47 | 3452 48 | 4326 49 | EPSG:4326 50 | WGS 84 51 | longlat 52 | WGS84 53 | true 54 | 55 | 56 | 0 57 | 58 | 59 | 60 | 61 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -180 72 | -90 73 | 180 74 | 83.62359619140625 75 | 76 | world_cf93afac_b471_4ac8_98e1_2073f3fd7ffb 77 | ./world.shp 78 | 79 | 80 | 81 | world 82 | 83 | 84 | +proj=longlat +datum=WGS84 +no_defs 85 | 3452 86 | 4326 87 | EPSG:4326 88 | WGS 84 89 | longlat 90 | WGS84 91 | true 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 0 108 | 0 109 | 110 | 111 | 112 | 113 | false 114 | 115 | 116 | 117 | 118 | ogr 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 1 130 | 1 131 | 1 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 0 163 | 0 164 | 1 165 | 166 | 167 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 0 208 | 209 | 210 | 0 211 | generatedlayout 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | false 225 | 226 | 227 | 1 228 | 229 | 230 | false 231 | 232 | 233 | 0 234 | 255 235 | 255 236 | 255 237 | 255 238 | 255 239 | 255 240 | 241 | 242 | WGS84 243 | 244 | 245 | 0 246 | false 247 | 0 248 | false 249 | 16 250 | true 251 | 50 252 | 30 253 | false 254 | 255 | 256 | true 257 | 2 258 | 259 | 260 | meters 261 | m2 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | c 275 | 2020-06-07T10:31:44 276 | 277 | 278 | 279 | 280 | -------------------------------------------------------------------------------- /data/world.shp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/data/world.shp -------------------------------------------------------------------------------- /data/world.shx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/data/world.shx -------------------------------------------------------------------------------- /examples/qgis_scripts.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2021/4/3 10:52 4 | import os 5 | import sys 6 | 7 | from qgis.core import QgsApplication, QgsProcessingAlgorithm 8 | 9 | # 提供qgis安装位置的路径(windows默认:C:\Program Files\QGIS 3.x\apps\qgis-ltr) 10 | QgsApplication.setPrefixPath("/path/to/qgis/installation", True) 11 | # 创建对QgsApplication的引用,第二个参数设置为False将禁用GUI 12 | qgs = QgsApplication([], False) 13 | # 加载提供者 14 | qgs.initQgis() 15 | prefix = QgsApplication.prefixPath() 16 | print(prefix) 17 | 18 | # 在这里编写代码,加载一些图层,使用处理算法等 19 | sys.path.append(os.path.join(prefix, "python", "plugins")) 20 | from plugins.processing.core.Processing import Processing 21 | from plugins import processing 22 | 23 | Processing.initialize() 24 | 25 | for alg in QgsApplication.processingRegistry().algorithms(): 26 | alg: QgsProcessingAlgorithm 27 | print(alg.group(), alg.provider().name(), alg.name()) 28 | 29 | result = processing.run('gdal:gdalinfo', 30 | { 31 | 'EXTRA': '', 32 | 'INPUT': '../data/test.tif', 33 | 'MIN_MAX': False, 34 | 'NOGCP': False, 35 | 'NO_METADATA': False, 36 | # 'OUTPUT': 'TEMPORARY_OUTPUT', 37 | 'OUTPUT': '../data/test.html', 38 | 'STATS': False 39 | } 40 | ) 41 | print(result) 42 | # 脚本完成后,调用exitQgis()从内存中删除提供者和图层注册 43 | qgs.exitQgis() 44 | -------------------------------------------------------------------------------- /images/pyqgis.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/images/pyqgis.ico -------------------------------------------------------------------------------- /images/pyqgis.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/images/pyqgis.png -------------------------------------------------------------------------------- /images/splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/luolingchun/PyQGIS/5f571d4f32722ec3ad6b3f491bdb3e407c0841ba/images/splash.png -------------------------------------------------------------------------------- /scripts/build.cmd: -------------------------------------------------------------------------------- 1 | :: -w 窗口程序 -c 控制台程序 2 | set QGIS_VERSION=3.16 3 | "C:\Program Files\QGIS %QGIS_VERSION%\bin\python-qgis-ltr.bat" -m PyInstaller -c ^ 4 | --add-data="C:\Program Files\QGIS %QGIS_VERSION%\apps\Python37\Lib\site-packages\PyQt5\*.pyd;PyQt5" ^ 5 | --add-data="C:\Program Files\QGIS %QGIS_VERSION%\apps\qgis-ltr\plugins;qgis\plugins" ^ 6 | --add-data="C:\Program Files\QGIS %QGIS_VERSION%\share;share" ^ 7 | --add-data="data;data" ^ 8 | --add-data="images;images" ^ 9 | --icon=images\pyqgis.ico ^ 10 | PyQGIS.py -------------------------------------------------------------------------------- /splash.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/4/21 21:44 4 | from qgis.PyQt.QtGui import QPixmap 5 | from qgis.PyQt.QtWidgets import QSplashScreen 6 | 7 | 8 | class NewSplashScreen(QSplashScreen): 9 | def __init__(self): 10 | super(NewSplashScreen, self).__init__() 11 | self.setPixmap(QPixmap('./images/splash.png')) 12 | 13 | def mousePressEvent(self, event): 14 | pass 15 | -------------------------------------------------------------------------------- /test/test_crs.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author llc 3 | # @Date 2020/4/1 11:10 4 | import time 5 | 6 | from PyQt5.QtCore import QThread, pyqtSignal 7 | from PyQt5.QtGui import QColor 8 | from PyQt5.QtWidgets import QDialog, QPushButton, QVBoxLayout, QLabel 9 | from qgis.core import QgsProject, QgsCoordinateReferenceSystem, QgsApplication, QgsVectorLayer, QgsRectangle 10 | from qgis.gui import QgsMapCanvas 11 | 12 | 13 | class MoveThread(QThread): 14 | degreeSignal = pyqtSignal(int) 15 | 16 | def __init__(self, parent=None): 17 | super(MoveThread, self).__init__(parent) 18 | 19 | def run(self) -> None: 20 | for i in range(180): 21 | self.degreeSignal.emit(i) 22 | time.sleep(0.1) 23 | 24 | 25 | class MyApp(QDialog): 26 | def __init__(self, parent=None): 27 | super(MyApp, self).__init__() 28 | self.vl = QVBoxLayout(self) 29 | self.pushbuttonStart = QPushButton("start", self) 30 | self.vl.addWidget(self.pushbuttonStart) 31 | 32 | self.label = QLabel(self) 33 | self.vl.addWidget(self.label) 34 | 35 | self.mapCanvas = QgsMapCanvas() 36 | # self.mapCanvas.setCanvasColor(QColor(0, 0, 0)) 37 | self.vl.addWidget(self.mapCanvas) 38 | 39 | self.pushbuttonStart.clicked.connect(self.add_layer) 40 | self.mapCanvas.xyCoordinates.connect(lambda p: self.label.setText(str(p.x()) + ', ' + str(p.y()))) 41 | 42 | def add_layer(self): 43 | QgsProject.instance().removeAllMapLayers() 44 | 45 | shp = r"../data/world.shp" 46 | layer = QgsVectorLayer(shp, "shp", "ogr") 47 | print(layer.isValid()) 48 | QgsProject.instance().addMapLayer(layer) 49 | self.mapCanvas.setLayers([layer]) 50 | self.mapCanvas.setExtent(layer.extent()) 51 | 52 | # crsSrc = QgsCoordinateReferenceSystem("EPSG:4326") 53 | # crsDest = QgsCoordinateReferenceSystem("EPSG:3857") 54 | crsDest = QgsCoordinateReferenceSystem( 55 | "PROJ:+proj=ortho +lat_0=0 +lon_0=100 +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs") 56 | 57 | # QgsProject.instance().setCrs(crsDest) 58 | self.mapCanvas.setDestinationCrs(crsDest) 59 | self.mapCanvas.setExtent(QgsRectangle(-6378137, -6378137, 6378137, 6378137)) 60 | self.mapCanvas.refresh() 61 | 62 | # self.set_crs() 63 | 64 | def set_crs(self): 65 | self.moveThread = MoveThread(self) 66 | self.moveThread.degreeSignal.connect(self.process_signal) 67 | self.moveThread.start() 68 | 69 | def process_signal(self, d): 70 | print(d) 71 | crsDest = QgsCoordinateReferenceSystem( 72 | f"PROJ:+proj=ortho +lat_0=0 +lon_0={d} +x_0=0 +y_0=0 +ellps=WGS84 +units=m +no_defs") 73 | 74 | self.mapCanvas.setDestinationCrs(crsDest) 75 | self.mapCanvas.refresh() 76 | 77 | 78 | if __name__ == '__main__': 79 | qgsAPP = QgsApplication([], True) 80 | QgsApplication.setPrefixPath("qgis", True) 81 | 82 | qgsAPP.initQgis() 83 | 84 | myApp = MyApp() 85 | myApp.show() 86 | 87 | qgsAPP.exec_() 88 | qgsAPP.exitQgis() 89 | -------------------------------------------------------------------------------- /test/test_identify.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Time : 2019/12/12 13:26 3 | # @Author : llc 4 | # @File : main_ui.py 5 | import os 6 | 7 | from PyQt5.QtWidgets import QMainWindow, QFileDialog, QVBoxLayout, QHBoxLayout 8 | from qgis.gui import QgsLayerTreeMapCanvasBridge, QgsLayerTreeView, QgsMapCanvas, QgsMapToolIdentifyFeature,QgisInterface 9 | from qgis.core import QgsVectorLayer, QgsProject, QgsLayerTreeModel, QgsApplication, QgsFeature, QgsDataSourceUri, \ 10 | QgsVectorDataProvider 11 | from qgis.utils import iface 12 | 13 | iface 14 | 15 | from main_ui import Ui_MainWindow 16 | QgsVectorDataProvider 17 | 18 | class Window(QMainWindow, Ui_MainWindow): 19 | def __init__(self): 20 | super(Window, self).__init__() 21 | self.setupUi(self) 22 | 23 | self.layers = [] 24 | 25 | # ---------初始化图层和画布---------- 26 | self.vl = QVBoxLayout(self.dockWidgetContents) 27 | self.layer_tree_view = QgsLayerTreeView(self) 28 | self.vl.addWidget(self.layer_tree_view) 29 | self.hl = QHBoxLayout(self.frame) 30 | self.mapCanvas = QgsMapCanvas(self.frame) 31 | self.hl.addWidget(self.mapCanvas) 32 | # ---------初始化图层和画布---------- 33 | 34 | self.action_open.triggered.connect(self.action_open_triggered) 35 | 36 | # 建立桥梁 37 | self.model = QgsLayerTreeModel(QgsProject.instance().layerTreeRoot(), self) 38 | self.model.setFlag(QgsLayerTreeModel.AllowNodeRename) 39 | self.model.setFlag(QgsLayerTreeModel.AllowNodeReorder) 40 | self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility) 41 | self.model.setFlag(QgsLayerTreeModel.ShowLegendAsTree) 42 | self.model.setAutoCollapseLegendNodes(10) 43 | self.layer_tree_view.setModel(self.model) 44 | self.layer_tree_bridge = QgsLayerTreeMapCanvasBridge(QgsProject.instance().layerTreeRoot(), self.mapCanvas) 45 | 46 | # 设置识别工具 47 | self.identifyTool = QgsMapToolIdentifyFeature(self.mapCanvas) 48 | # 发送识别的要素 49 | self.identifyTool.featureIdentified.connect(self.print_features) 50 | self.mapCanvas.setMapTool(self.identifyTool) 51 | 52 | def action_open_triggered(self): 53 | data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '所有文件(*)') 54 | if data_file: 55 | if data_file.endswith('.shp'): 56 | basename = os.path.splitext(os.path.basename(data_file))[0] 57 | layer = QgsVectorLayer(data_file, basename, "ogr") 58 | QgsProject.instance().addMapLayer(layer) 59 | self.layers.append(layer) 60 | self.mapCanvas.setExtent(layer.extent()) 61 | self.mapCanvas.setLayers(self.layers) 62 | self.mapCanvas.refresh() 63 | self.layer_tree_view.setCurrentLayer(layer) 64 | 65 | # 设置需要识别的图层 66 | self.identifyTool.setLayer(layer) 67 | 68 | elif data_file.endswith('.qgz') or data_file.endswith('.qgs'): 69 | QgsProject.instance().read(data_file) 70 | else: 71 | print('error') 72 | 73 | def print_features(self, feature): 74 | print(feature.attributes()) 75 | print(feature.fields()) 76 | print(feature.geometry()) 77 | 78 | 79 | if __name__ == '__main__': 80 | # 应用入口,使用GUI 81 | qgs = QgsApplication([], True) 82 | # 设置,qgis安装路径,这里写相对路径,如果是源码运行,这行可不写 83 | qgs.setPrefixPath('qgis', True) 84 | # 初始化 85 | qgs.initQgis() 86 | 87 | window = Window() 88 | window.show() 89 | 90 | exit_code = qgs.exec_() 91 | # 退出 92 | qgs.exitQgis() 93 | -------------------------------------------------------------------------------- /ui/PostGIS.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | Dialog 4 | 5 | 6 | 7 | 0 8 | 0 9 | 442 10 | 448 11 | 12 | 13 | 14 | Dialog 15 | 16 | 17 | 18 | 19 | 20 | test2020 21 | 22 | 23 | 24 | 25 | 26 | 27 | lakes 28 | 29 | 30 | 31 | 32 | 33 | 34 | localhost 35 | 36 | 37 | 38 | 39 | 40 | 41 | 5432 42 | 43 | 44 | 45 | 46 | 47 | 48 | 123456 49 | 50 | 51 | 52 | 53 | 54 | 55 | host: 56 | 57 | 58 | 59 | 60 | 61 | 62 | password: 63 | 64 | 65 | 66 | 67 | 68 | 69 | username: 70 | 71 | 72 | 73 | 74 | 75 | 76 | geometry column: 77 | 78 | 79 | 80 | 81 | 82 | 83 | port: 84 | 85 | 86 | 87 | 88 | 89 | 90 | database: 91 | 92 | 93 | 94 | 95 | 96 | 97 | wkb_geometry 98 | 99 | 100 | 101 | 102 | 103 | 104 | layer: 105 | 106 | 107 | 108 | 109 | 110 | 111 | postgres 112 | 113 | 114 | 115 | 116 | 117 | 118 | ok 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /ui/PostGIS_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'PostGIS.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.11.3 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_Dialog(object): 12 | def setupUi(self, Dialog): 13 | Dialog.setObjectName("Dialog") 14 | Dialog.resize(442, 448) 15 | self.gridLayout = QtWidgets.QGridLayout(Dialog) 16 | self.gridLayout.setObjectName("gridLayout") 17 | self.lineEditDatabase = QtWidgets.QLineEdit(Dialog) 18 | self.lineEditDatabase.setObjectName("lineEditDatabase") 19 | self.gridLayout.addWidget(self.lineEditDatabase, 2, 2, 1, 1) 20 | self.lineEditLayer = QtWidgets.QLineEdit(Dialog) 21 | self.lineEditLayer.setObjectName("lineEditLayer") 22 | self.gridLayout.addWidget(self.lineEditLayer, 5, 2, 1, 1) 23 | self.lineEditHost = QtWidgets.QLineEdit(Dialog) 24 | self.lineEditHost.setObjectName("lineEditHost") 25 | self.gridLayout.addWidget(self.lineEditHost, 0, 2, 1, 1) 26 | self.lineEditPort = QtWidgets.QLineEdit(Dialog) 27 | self.lineEditPort.setObjectName("lineEditPort") 28 | self.gridLayout.addWidget(self.lineEditPort, 1, 2, 1, 1) 29 | self.lineEditPassword = QtWidgets.QLineEdit(Dialog) 30 | self.lineEditPassword.setObjectName("lineEditPassword") 31 | self.gridLayout.addWidget(self.lineEditPassword, 4, 2, 1, 1) 32 | self.label = QtWidgets.QLabel(Dialog) 33 | self.label.setObjectName("label") 34 | self.gridLayout.addWidget(self.label, 0, 0, 1, 1) 35 | self.label_4 = QtWidgets.QLabel(Dialog) 36 | self.label_4.setObjectName("label_4") 37 | self.gridLayout.addWidget(self.label_4, 4, 0, 1, 1) 38 | self.label_3 = QtWidgets.QLabel(Dialog) 39 | self.label_3.setObjectName("label_3") 40 | self.gridLayout.addWidget(self.label_3, 3, 0, 1, 1) 41 | self.label_7 = QtWidgets.QLabel(Dialog) 42 | self.label_7.setObjectName("label_7") 43 | self.gridLayout.addWidget(self.label_7, 6, 0, 1, 1) 44 | self.label_2 = QtWidgets.QLabel(Dialog) 45 | self.label_2.setObjectName("label_2") 46 | self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1) 47 | self.label_5 = QtWidgets.QLabel(Dialog) 48 | self.label_5.setObjectName("label_5") 49 | self.gridLayout.addWidget(self.label_5, 2, 0, 1, 1) 50 | self.lineEditGeometryColumn = QtWidgets.QLineEdit(Dialog) 51 | self.lineEditGeometryColumn.setObjectName("lineEditGeometryColumn") 52 | self.gridLayout.addWidget(self.lineEditGeometryColumn, 6, 2, 1, 1) 53 | self.label_6 = QtWidgets.QLabel(Dialog) 54 | self.label_6.setObjectName("label_6") 55 | self.gridLayout.addWidget(self.label_6, 5, 0, 1, 1) 56 | self.lineEditUsername = QtWidgets.QLineEdit(Dialog) 57 | self.lineEditUsername.setObjectName("lineEditUsername") 58 | self.gridLayout.addWidget(self.lineEditUsername, 3, 2, 1, 1) 59 | self.pushButtonOk = QtWidgets.QPushButton(Dialog) 60 | self.pushButtonOk.setObjectName("pushButtonOk") 61 | self.gridLayout.addWidget(self.pushButtonOk, 7, 2, 1, 1) 62 | 63 | self.retranslateUi(Dialog) 64 | QtCore.QMetaObject.connectSlotsByName(Dialog) 65 | 66 | def retranslateUi(self, Dialog): 67 | _translate = QtCore.QCoreApplication.translate 68 | Dialog.setWindowTitle(_translate("Dialog", "Dialog")) 69 | self.lineEditDatabase.setText(_translate("Dialog", "test2020")) 70 | self.lineEditLayer.setText(_translate("Dialog", "lakes")) 71 | self.lineEditHost.setText(_translate("Dialog", "localhost")) 72 | self.lineEditPort.setText(_translate("Dialog", "5432")) 73 | self.lineEditPassword.setText(_translate("Dialog", "123456")) 74 | self.label.setText(_translate("Dialog", "host:")) 75 | self.label_4.setText(_translate("Dialog", "password:")) 76 | self.label_3.setText(_translate("Dialog", "username:")) 77 | self.label_7.setText(_translate("Dialog", "geometry column:")) 78 | self.label_2.setText(_translate("Dialog", "port:")) 79 | self.label_5.setText(_translate("Dialog", "database:")) 80 | self.lineEditGeometryColumn.setText(_translate("Dialog", "wkb_geometry")) 81 | self.label_6.setText(_translate("Dialog", "layer:")) 82 | self.lineEditUsername.setText(_translate("Dialog", "postgres")) 83 | self.pushButtonOk.setText(_translate("Dialog", "ok")) 84 | 85 | -------------------------------------------------------------------------------- /ui/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/5/30 15:48 4 | 5 | -------------------------------------------------------------------------------- /ui/main.ui: -------------------------------------------------------------------------------- 1 | 2 | 3 | MainWindow 4 | 5 | 6 | 7 | 0 8 | 0 9 | 654 10 | 471 11 | 12 | 13 | 14 | MainWindow 15 | 16 | 17 | 18 | 19 | 20 | 21 | QFrame::StyledPanel 22 | 23 | 24 | QFrame::Raised 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 0 34 | 0 35 | 654 36 | 23 37 | 38 | 39 | 40 | 41 | Project 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | Action 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | Layer 59 | 60 | 61 | 62 | Vector 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | Raster 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | Maptool 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | Projection 92 | 93 | 94 | 95 | 96 | 97 | Help 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | layer 113 | 114 | 115 | 1 116 | 117 | 118 | 119 | 120 | 121 | Open 122 | 123 | 124 | 125 | 126 | Quit 127 | 128 | 129 | 130 | 131 | Zoom in 132 | 133 | 134 | 135 | 136 | Zoom out 137 | 138 | 139 | 140 | 141 | Identify 142 | 143 | 144 | 145 | 146 | Shapefile 147 | 148 | 149 | 150 | 151 | CSV 152 | 153 | 154 | 155 | 156 | PostGIS 157 | 158 | 159 | 160 | 161 | WFS 162 | 163 | 164 | 165 | 166 | Geotiff 167 | 168 | 169 | 170 | 171 | Rectangle 172 | 173 | 174 | 175 | 176 | Polygon 177 | 178 | 179 | 180 | 181 | Circle 182 | 183 | 184 | 185 | 186 | Point 187 | 188 | 189 | 190 | 191 | Line 192 | 193 | 194 | 195 | 196 | XYZ 197 | 198 | 199 | 200 | 201 | Transform 202 | 203 | 204 | 205 | 206 | Pan 207 | 208 | 209 | 210 | 211 | About Qt 212 | 213 | 214 | 215 | 216 | About 217 | 218 | 219 | 220 | 221 | 222 | 223 | -------------------------------------------------------------------------------- /ui/main_ui.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Form implementation generated from reading ui file 'main.ui' 4 | # 5 | # Created by: PyQt5 UI code generator 5.11.3 6 | # 7 | # WARNING! All changes made in this file will be lost! 8 | 9 | from PyQt5 import QtCore, QtGui, QtWidgets 10 | 11 | class Ui_MainWindow(object): 12 | def setupUi(self, MainWindow): 13 | MainWindow.setObjectName("MainWindow") 14 | MainWindow.resize(654, 471) 15 | self.centralwidget = QtWidgets.QWidget(MainWindow) 16 | self.centralwidget.setObjectName("centralwidget") 17 | self.gridLayout = QtWidgets.QGridLayout(self.centralwidget) 18 | self.gridLayout.setObjectName("gridLayout") 19 | self.frame = QtWidgets.QFrame(self.centralwidget) 20 | self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel) 21 | self.frame.setFrameShadow(QtWidgets.QFrame.Raised) 22 | self.frame.setObjectName("frame") 23 | self.gridLayout.addWidget(self.frame, 0, 0, 1, 1) 24 | MainWindow.setCentralWidget(self.centralwidget) 25 | self.menubar = QtWidgets.QMenuBar(MainWindow) 26 | self.menubar.setGeometry(QtCore.QRect(0, 0, 654, 23)) 27 | self.menubar.setObjectName("menubar") 28 | self.menufile = QtWidgets.QMenu(self.menubar) 29 | self.menufile.setObjectName("menufile") 30 | self.menuaction = QtWidgets.QMenu(self.menubar) 31 | self.menuaction.setObjectName("menuaction") 32 | self.menulayer = QtWidgets.QMenu(self.menubar) 33 | self.menulayer.setObjectName("menulayer") 34 | self.menuvector = QtWidgets.QMenu(self.menulayer) 35 | self.menuvector.setObjectName("menuvector") 36 | self.menuraster = QtWidgets.QMenu(self.menulayer) 37 | self.menuraster.setObjectName("menuraster") 38 | self.menumaptool = QtWidgets.QMenu(self.menubar) 39 | self.menumaptool.setObjectName("menumaptool") 40 | self.menuproject = QtWidgets.QMenu(self.menubar) 41 | self.menuproject.setObjectName("menuproject") 42 | self.menuhelp = QtWidgets.QMenu(self.menubar) 43 | self.menuhelp.setObjectName("menuhelp") 44 | MainWindow.setMenuBar(self.menubar) 45 | self.statusbar = QtWidgets.QStatusBar(MainWindow) 46 | self.statusbar.setObjectName("statusbar") 47 | MainWindow.setStatusBar(self.statusbar) 48 | self.dockWidget = QtWidgets.QDockWidget(MainWindow) 49 | self.dockWidget.setObjectName("dockWidget") 50 | self.dockWidgetContents = QtWidgets.QWidget() 51 | self.dockWidgetContents.setObjectName("dockWidgetContents") 52 | self.dockWidget.setWidget(self.dockWidgetContents) 53 | MainWindow.addDockWidget(QtCore.Qt.DockWidgetArea(1), self.dockWidget) 54 | self.actionOpen = QtWidgets.QAction(MainWindow) 55 | self.actionOpen.setObjectName("actionOpen") 56 | self.actionQuit = QtWidgets.QAction(MainWindow) 57 | self.actionQuit.setObjectName("actionQuit") 58 | self.actionZoomin = QtWidgets.QAction(MainWindow) 59 | self.actionZoomin.setObjectName("actionZoomin") 60 | self.actionZoomout = QtWidgets.QAction(MainWindow) 61 | self.actionZoomout.setObjectName("actionZoomout") 62 | self.actionIdentity = QtWidgets.QAction(MainWindow) 63 | self.actionIdentity.setObjectName("actionIdentity") 64 | self.actionShapefile = QtWidgets.QAction(MainWindow) 65 | self.actionShapefile.setObjectName("actionShapefile") 66 | self.actionCsv = QtWidgets.QAction(MainWindow) 67 | self.actionCsv.setObjectName("actionCsv") 68 | self.actionPostGIS = QtWidgets.QAction(MainWindow) 69 | self.actionPostGIS.setObjectName("actionPostGIS") 70 | self.actionWFS = QtWidgets.QAction(MainWindow) 71 | self.actionWFS.setObjectName("actionWFS") 72 | self.actionGeotiff = QtWidgets.QAction(MainWindow) 73 | self.actionGeotiff.setObjectName("actionGeotiff") 74 | self.actionRectangle = QtWidgets.QAction(MainWindow) 75 | self.actionRectangle.setObjectName("actionRectangle") 76 | self.actionPolygon = QtWidgets.QAction(MainWindow) 77 | self.actionPolygon.setObjectName("actionPolygon") 78 | self.actionCircle = QtWidgets.QAction(MainWindow) 79 | self.actionCircle.setObjectName("actionCircle") 80 | self.actionPoint = QtWidgets.QAction(MainWindow) 81 | self.actionPoint.setObjectName("actionPoint") 82 | self.actionLine = QtWidgets.QAction(MainWindow) 83 | self.actionLine.setObjectName("actionLine") 84 | self.actionXYZ = QtWidgets.QAction(MainWindow) 85 | self.actionXYZ.setObjectName("actionXYZ") 86 | self.actionTransform = QtWidgets.QAction(MainWindow) 87 | self.actionTransform.setObjectName("actionTransform") 88 | self.actionPan = QtWidgets.QAction(MainWindow) 89 | self.actionPan.setObjectName("actionPan") 90 | self.actionAboutQt = QtWidgets.QAction(MainWindow) 91 | self.actionAboutQt.setObjectName("actionAboutQt") 92 | self.actionAbout = QtWidgets.QAction(MainWindow) 93 | self.actionAbout.setObjectName("actionAbout") 94 | self.menufile.addAction(self.actionOpen) 95 | self.menufile.addSeparator() 96 | self.menufile.addAction(self.actionQuit) 97 | self.menuaction.addAction(self.actionPan) 98 | self.menuaction.addAction(self.actionZoomin) 99 | self.menuaction.addAction(self.actionZoomout) 100 | self.menuaction.addAction(self.actionIdentity) 101 | self.menuvector.addAction(self.actionShapefile) 102 | self.menuvector.addAction(self.actionCsv) 103 | self.menuvector.addAction(self.actionPostGIS) 104 | self.menuvector.addAction(self.actionWFS) 105 | self.menuraster.addAction(self.actionGeotiff) 106 | self.menuraster.addAction(self.actionXYZ) 107 | self.menulayer.addAction(self.menuvector.menuAction()) 108 | self.menulayer.addAction(self.menuraster.menuAction()) 109 | self.menumaptool.addAction(self.actionPoint) 110 | self.menumaptool.addAction(self.actionLine) 111 | self.menumaptool.addAction(self.actionPolygon) 112 | self.menumaptool.addAction(self.actionRectangle) 113 | self.menumaptool.addAction(self.actionCircle) 114 | self.menuproject.addAction(self.actionTransform) 115 | self.menuhelp.addAction(self.actionAboutQt) 116 | self.menuhelp.addAction(self.actionAbout) 117 | self.menubar.addAction(self.menufile.menuAction()) 118 | self.menubar.addAction(self.menuaction.menuAction()) 119 | self.menubar.addAction(self.menulayer.menuAction()) 120 | self.menubar.addAction(self.menumaptool.menuAction()) 121 | self.menubar.addAction(self.menuproject.menuAction()) 122 | self.menubar.addAction(self.menuhelp.menuAction()) 123 | 124 | self.retranslateUi(MainWindow) 125 | QtCore.QMetaObject.connectSlotsByName(MainWindow) 126 | 127 | def retranslateUi(self, MainWindow): 128 | _translate = QtCore.QCoreApplication.translate 129 | MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) 130 | self.menufile.setTitle(_translate("MainWindow", "Project")) 131 | self.menuaction.setTitle(_translate("MainWindow", "Action")) 132 | self.menulayer.setTitle(_translate("MainWindow", "Layer")) 133 | self.menuvector.setTitle(_translate("MainWindow", "Vector")) 134 | self.menuraster.setTitle(_translate("MainWindow", "Raster")) 135 | self.menumaptool.setTitle(_translate("MainWindow", "Maptool")) 136 | self.menuproject.setTitle(_translate("MainWindow", "Projection")) 137 | self.menuhelp.setTitle(_translate("MainWindow", "Help")) 138 | self.dockWidget.setWindowTitle(_translate("MainWindow", "layer")) 139 | self.actionOpen.setText(_translate("MainWindow", "Open")) 140 | self.actionQuit.setText(_translate("MainWindow", "Quit")) 141 | self.actionZoomin.setText(_translate("MainWindow", "Zoom in")) 142 | self.actionZoomout.setText(_translate("MainWindow", "Zoom out")) 143 | self.actionIdentity.setText(_translate("MainWindow", "Identify")) 144 | self.actionShapefile.setText(_translate("MainWindow", "Shapefile")) 145 | self.actionCsv.setText(_translate("MainWindow", "CSV")) 146 | self.actionPostGIS.setText(_translate("MainWindow", "PostGIS")) 147 | self.actionWFS.setText(_translate("MainWindow", "WFS")) 148 | self.actionGeotiff.setText(_translate("MainWindow", "Geotiff")) 149 | self.actionRectangle.setText(_translate("MainWindow", "Rectangle")) 150 | self.actionPolygon.setText(_translate("MainWindow", "Polygon")) 151 | self.actionCircle.setText(_translate("MainWindow", "Circle")) 152 | self.actionPoint.setText(_translate("MainWindow", "Point")) 153 | self.actionLine.setText(_translate("MainWindow", "Line")) 154 | self.actionXYZ.setText(_translate("MainWindow", "XYZ")) 155 | self.actionTransform.setText(_translate("MainWindow", "Transform")) 156 | self.actionPan.setText(_translate("MainWindow", "Pan")) 157 | self.actionAboutQt.setText(_translate("MainWindow", "About Qt")) 158 | self.actionAbout.setText(_translate("MainWindow", "About")) 159 | 160 | -------------------------------------------------------------------------------- /utils/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2021/5/5 14:56 4 | -------------------------------------------------------------------------------- /utils/customMenu.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/10/19 11:38 4 | from qgis.PyQt.QtWidgets import QMenu, QAction 5 | from qgis.core import QgsLayerTreeNode, QgsLayerTree, QgsMapLayerType 6 | from qgis.gui import QgsLayerTreeViewMenuProvider, QgsLayerTreeView, QgsLayerTreeViewDefaultActions, QgsMapCanvas 7 | 8 | from widgets.attributeDialog import AttributeDialog 9 | 10 | 11 | class CustomMenuProvider(QgsLayerTreeViewMenuProvider): 12 | def __init__(self, layerTreeView: QgsLayerTreeView, mapCanvas: QgsMapCanvas, *args, **kwargs): 13 | super().__init__(*args, **kwargs) 14 | self.layerTreeView = layerTreeView 15 | self.mapCanvas = mapCanvas 16 | 17 | def createContextMenu(self): 18 | menu = QMenu() 19 | actions: QgsLayerTreeViewDefaultActions = self.layerTreeView.defaultActions() 20 | if not self.layerTreeView.currentIndex().isValid(): 21 | # 不在图层上右键 22 | self.actionAddGroup = actions.actionAddGroup(menu) 23 | menu.addAction(self.actionAddGroup) 24 | menu.addAction('Expand All', self.layerTreeView.expandAll) 25 | menu.addAction('Collapse All', self.layerTreeView.collapseAll) 26 | return menu 27 | 28 | node: QgsLayerTreeNode = self.layerTreeView.currentNode() 29 | 30 | if QgsLayerTree.isGroup(node): 31 | # 图组操作 32 | print('group') 33 | pass 34 | elif QgsLayerTree.isLayer(node): 35 | print('layer') 36 | self.actionZoomToLayer = actions.actionZoomToLayer(self.mapCanvas, menu) 37 | menu.addAction(self.actionZoomToLayer) 38 | # 图层操作 39 | layer = self.layerTreeView.currentLayer() 40 | if layer.type() == QgsMapLayerType.VectorLayer: 41 | # 矢量图层 42 | actionOpenAttributeDialog = QAction('open Attribute Table', menu) 43 | actionOpenAttributeDialog.triggered.connect(lambda: self.openAttributeDialog(layer)) 44 | menu.addAction(actionOpenAttributeDialog) 45 | else: 46 | # 栅格图层 47 | pass 48 | else: 49 | print('node type is none') 50 | 51 | return menu 52 | 53 | def openAttributeDialog(self, layer): 54 | self.attributeDialog = AttributeDialog(self.mapCanvas, parent=self.mapCanvas.parent()) 55 | self.attributeDialog.openAttributeDialog(layer) 56 | self.attributeDialog.show() 57 | -------------------------------------------------------------------------------- /utils/interface.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2021/5/5 15:21 4 | from PyQt5.QtCore import QSize 5 | from qgis.gui import QgisInterface 6 | 7 | from widgets.mainWindow import MainWindow 8 | 9 | 10 | def initInterface(mainWindow): 11 | iface = Interface(mainWindow) 12 | return iface 13 | 14 | 15 | class Interface(QgisInterface): 16 | def __init__(self, mainWindow: MainWindow): 17 | super(Interface, self).__init__() 18 | 19 | self._mainWindow = mainWindow 20 | 21 | def mapCanvas(self): 22 | return self._mainWindow.mapCanvas 23 | 24 | def addToolBar(self, *__args): 25 | toolBar = self._mainWindow.addToolBar(*__args) 26 | return toolBar 27 | 28 | def iconSize(self, dockedToolbar=False): 29 | return QSize(24, 24) 30 | -------------------------------------------------------------------------------- /utils/plugins.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2021/5/5 15:27 4 | import os 5 | import sys 6 | 7 | 8 | def loadPlugins(iface): 9 | QGIS_PLUGINPATH = os.environ["QGIS_PLUGINPATH"] 10 | if not os.path.exists(QGIS_PLUGINPATH): 11 | print("QGIS_PLUGINPATH not exists.") 12 | return 13 | print("QGIS_PLUGINPATH:", QGIS_PLUGINPATH) 14 | sys.path.append(QGIS_PLUGINPATH) 15 | sys.path_importer_cache.clear() 16 | for plugin in os.listdir(QGIS_PLUGINPATH): 17 | if os.path.isdir(os.path.join(QGIS_PLUGINPATH, plugin)): 18 | # print(plugin) 19 | __import__(plugin) 20 | pluginPackage = sys.modules[plugin] 21 | pluginObj = pluginPackage.classFactory(iface) 22 | pluginObj.initGui() 23 | -------------------------------------------------------------------------------- /widgets/PostGIS.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/6/7 12:33 4 | from qgis.PyQt.QtWidgets import QDialog 5 | 6 | from ui.PostGIS_ui import Ui_Dialog 7 | 8 | 9 | class PostGISDialog(QDialog, Ui_Dialog): 10 | def __init__(self, parent=None): 11 | super(PostGISDialog, self).__init__(parent) 12 | 13 | self.setupUi(self) 14 | 15 | self.pushButtonOk.clicked.connect(self.accept) 16 | -------------------------------------------------------------------------------- /widgets/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/4/21 21:40 4 | 5 | -------------------------------------------------------------------------------- /widgets/attributeDialog.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/10/20 15:01 4 | from qgis.PyQt.QtWidgets import QDialog, QHBoxLayout 5 | from qgis.core import QgsVectorLayerCache 6 | from qgis.gui import QgsAttributeTableView, QgsAttributeTableModel, QgsAttributeTableFilterModel 7 | 8 | 9 | class AttributeDialog(QDialog): 10 | def __init__(self, mapCanvas, parent=None): 11 | super().__init__(parent) 12 | self.mapCanvas = mapCanvas 13 | 14 | self.resize(600, 400) 15 | 16 | self.tableView = QgsAttributeTableView(self) 17 | 18 | self.hl = QHBoxLayout(self) 19 | self.hl.addWidget(self.tableView) 20 | 21 | def openAttributeDialog(self, layer): 22 | self.layerCache = QgsVectorLayerCache(layer, layer.featureCount()) 23 | self.tableModel = QgsAttributeTableModel(self.layerCache) 24 | self.tableModel.loadLayer() 25 | 26 | self.tableFilterModel = QgsAttributeTableFilterModel(self.mapCanvas, self.tableModel, parent=self.tableModel) 27 | self.tableFilterModel.setFilterMode(QgsAttributeTableFilterModel.ShowAll) 28 | self.tableView.setModel(self.tableFilterModel) 29 | -------------------------------------------------------------------------------- /widgets/custom_maptool.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/6/7 15:30 4 | from qgis.PyQt.QtCore import Qt 5 | from qgis.PyQt.QtGui import QColor 6 | from qgis.core import Qgis 7 | from qgis.core import QgsRectangle, QgsPointXY, QgsWkbTypes, QgsSnappingConfig, QgsTolerance 8 | from qgis.gui import QgsMapToolEmitPoint, QgsRubberBand, QgsVertexMarker, QgsSnapIndicator 9 | 10 | 11 | class PointMapTool(QgsMapToolEmitPoint): 12 | def __init__(self, canvas): 13 | super(PointMapTool, self).__init__(canvas) 14 | self.canvas = canvas 15 | self.marker = QgsVertexMarker(canvas) 16 | self.marker.setColor(QColor(0, 0, 255)) 17 | self.marker.setPenWidth(3) 18 | 19 | def canvasPressEvent(self, e): 20 | self.point = self.toMapCoordinates(e.pos()) 21 | self.marker.setCenter(self.point) 22 | 23 | def deactivate(self): 24 | super(PointMapTool, self).deactivate() 25 | self.deactivated.emit() 26 | self.canvas.scene().removeItem(self.marker) 27 | 28 | 29 | class LineMapTool(QgsMapToolEmitPoint): 30 | def __init__(self, canvas): 31 | super(LineMapTool, self).__init__(canvas) 32 | self.canvas = canvas 33 | # 捕捉 34 | self.snapIndicator = QgsSnapIndicator(self.canvas) 35 | self.snapper = self.canvas.snappingUtils() 36 | config = QgsSnappingConfig() 37 | config.setEnabled(True) 38 | config.setType(QgsSnappingConfig.Vertex) 39 | config.setUnits(QgsTolerance.Pixels) 40 | config.setTolerance(12) 41 | # https://qgis.org/pyqgis/master/core/QgsSnappingConfig.html#qgis.core.QgsSnappingConfig.SnappingMode 42 | config.setMode(Qgis.SnappingMode.AllLayers) 43 | self.snapper.setConfig(config) 44 | 45 | self.rubberBand = QgsRubberBand(self.canvas, True) 46 | self.rubberBand.setColor(QColor(255, 0, 0, 100)) 47 | self.rubberBand.setWidth(3) 48 | self.reset() 49 | 50 | self.snapMatchPoint = None 51 | 52 | def reset(self): 53 | self.points = [] 54 | self.isEmittingPoint = False 55 | self.rubberBand.reset(True) 56 | 57 | def canvasPressEvent(self, e): 58 | if self.snapMatchPoint: 59 | self.points.append(self.snapMatchPoint) 60 | else: 61 | self.points.append(e.mapPoint()) 62 | self.isEmittingPoint = True 63 | 64 | def canvasReleaseEvent(self, e): 65 | if e.button() == Qt.RightButton: 66 | # 右键结束 67 | self.isEmittingPoint = False 68 | 69 | def canvasMoveEvent(self, e): 70 | # 捕捉 71 | snapMatch = self.snapper.snapToMap(e.pos()) 72 | self.snapIndicator.setMatch(snapMatch) 73 | if snapMatch.isValid(): 74 | self.snapMatchPoint = snapMatch.point() 75 | else: 76 | self.snapMatchPoint = None 77 | if not self.isEmittingPoint: 78 | return 79 | self.cursor_point = e.mapPoint() 80 | self.showLine() 81 | 82 | def showLine(self): 83 | self.rubberBand.reset(QgsWkbTypes.LineGeometry) 84 | if not self.points: 85 | return 86 | 87 | for point in self.points: 88 | self.rubberBand.addPoint(point, False) 89 | 90 | self.rubberBand.addPoint(self.cursor_point) 91 | self.rubberBand.show() 92 | 93 | def deactivate(self): 94 | super(LineMapTool, self).deactivate() 95 | self.deactivated.emit() 96 | self.reset() 97 | 98 | 99 | class RectangleMapTool(QgsMapToolEmitPoint): 100 | def __init__(self, canvas): 101 | super(RectangleMapTool, self).__init__(canvas) 102 | self.canvas = canvas 103 | self.rubberBand = QgsRubberBand(self.canvas, True) 104 | self.rubberBand.setColor(QColor(255, 0, 0, 100)) 105 | self.rubberBand.setWidth(1) 106 | self.reset() 107 | 108 | def reset(self): 109 | self.startPoint = self.endPoint = None 110 | self.isEmittingPoint = False 111 | self.rubberBand.reset(True) 112 | 113 | def canvasPressEvent(self, e): 114 | self.startPoint = self.toMapCoordinates(e.pos()) 115 | self.endPoint = self.startPoint 116 | self.isEmittingPoint = True 117 | self.showRect(self.startPoint, self.endPoint) 118 | 119 | def canvasReleaseEvent(self, e): 120 | self.isEmittingPoint = False 121 | r = self.rectangle() 122 | if r is not None: 123 | print("Rectangle:", r.xMinimum(), r.yMinimum(), r.xMaximum(), r.yMaximum()) 124 | 125 | def canvasMoveEvent(self, e): 126 | if not self.isEmittingPoint: 127 | return 128 | 129 | self.endPoint = self.toMapCoordinates(e.pos()) 130 | self.showRect(self.startPoint, self.endPoint) 131 | 132 | def showRect(self, startPoint, endPoint): 133 | self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) 134 | if startPoint.x() == endPoint.x() or startPoint.y() == endPoint.y(): 135 | return 136 | 137 | point1 = QgsPointXY(startPoint.x(), startPoint.y()) 138 | point2 = QgsPointXY(startPoint.x(), endPoint.y()) 139 | point3 = QgsPointXY(endPoint.x(), endPoint.y()) 140 | point4 = QgsPointXY(endPoint.x(), startPoint.y()) 141 | 142 | self.rubberBand.addPoint(point1, False) 143 | self.rubberBand.addPoint(point2, False) 144 | self.rubberBand.addPoint(point3, False) 145 | self.rubberBand.addPoint(point4, True) # true to update canvas 146 | self.rubberBand.show() 147 | 148 | def rectangle(self): 149 | if self.startPoint is None or self.endPoint is None: 150 | return None 151 | elif self.startPoint.x() == self.endPoint.x() or self.startPoint.y() == self.endPoint.y(): 152 | return None 153 | 154 | return QgsRectangle(self.startPoint, self.endPoint) 155 | 156 | def deactivate(self): 157 | super(RectangleMapTool, self).deactivate() 158 | self.deactivated.emit() 159 | self.reset() 160 | 161 | 162 | class PolygonMapTool(QgsMapToolEmitPoint): 163 | def __init__(self, canvas): 164 | self.canvas = canvas 165 | QgsMapToolEmitPoint.__init__(self, self.canvas) 166 | self.rubberBand = QgsRubberBand(self.canvas, QgsWkbTypes.PolygonGeometry) 167 | self.rubberBand.setColor(QColor(255, 0, 0, 100)) 168 | self.rubberBand.setWidth(1) 169 | self.reset() 170 | 171 | def reset(self): 172 | self.is_start = False # 开始绘图 173 | self.is_vertical = False # 垂直画线 174 | self.cursor_point = None 175 | self.points = [] 176 | self.rubberBand.reset(True) 177 | 178 | def canvasPressEvent(self, event): 179 | if event.button() == Qt.LeftButton: 180 | self.points.append(self.cursor_point) 181 | self.is_start = True 182 | elif event.button() == Qt.RightButton: 183 | # 右键结束绘制 184 | if self.is_start: 185 | self.is_start = False 186 | self.cursor_point = None 187 | self.show_polygon() 188 | self.points = [] 189 | else: 190 | pass 191 | else: 192 | pass 193 | 194 | def canvasMoveEvent(self, event): 195 | self.cursor_point = event.mapPoint() 196 | if not self.is_start: 197 | return 198 | self.show_polygon() 199 | 200 | def show_polygon(self): 201 | self.rubberBand.reset(QgsWkbTypes.PolygonGeometry) # 防止拖影 202 | first_point = self.points[0] 203 | last_point = self.points[-1] 204 | self.rubberBand.addPoint(first_point, False) 205 | for point in self.points[1:-1]: 206 | self.rubberBand.addPoint(point, False) 207 | if self.cursor_point: 208 | self.rubberBand.addPoint(QgsPointXY(last_point.x(), last_point.y()), False) 209 | else: 210 | self.rubberBand.addPoint(QgsPointXY(last_point.x(), last_point.y()), True) 211 | self.rubberBand.show() 212 | return 213 | 214 | self.rubberBand.addPoint(self.cursor_point, True) 215 | self.rubberBand.show() 216 | 217 | def deactivate(self): 218 | super(PolygonMapTool, self).deactivate() 219 | self.deactivated.emit() 220 | self.reset() 221 | -------------------------------------------------------------------------------- /widgets/mainWindow.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # @Author : llc 3 | # @Time : 2020/4/21 21:40 4 | import os 5 | 6 | from qgis.PyQt.QtWidgets import QMainWindow, QFileDialog, QHBoxLayout, QVBoxLayout, QMessageBox 7 | from qgis.core import QgsVectorLayer, QgsProject, QgsLayerTreeModel, QgsDataSourceUri, QgsRasterLayer,QgsLayerTree 8 | from qgis.gui import QgsMapCanvas, QgsMapToolZoom, QgsMapToolPan, QgsMapToolIdentifyFeature, QgsLayerTreeView, \ 9 | QgsLayerTreeMapCanvasBridge 10 | 11 | from ui.main_ui import Ui_MainWindow 12 | from utils.customMenu import CustomMenuProvider 13 | from widgets.PostGIS import PostGISDialog 14 | from widgets.custom_maptool import RectangleMapTool, PolygonMapTool, PointMapTool, LineMapTool 15 | 16 | PROJECT = QgsProject.instance() 17 | 18 | 19 | class MainWindow(QMainWindow, Ui_MainWindow): 20 | def __init__(self): 21 | super(MainWindow, self).__init__() 22 | self.setupUi(self) 23 | self.first_flag = True 24 | self.setWindowTitle('PyQGIS') 25 | # 调整窗口大小 26 | self.resize(800, 600) 27 | # 初始化图层树 28 | vl = QVBoxLayout(self.dockWidgetContents) 29 | self.layerTreeView = QgsLayerTreeView(self) 30 | vl.addWidget(self.layerTreeView) 31 | # 初始化地图画布 32 | self.mapCanvas = QgsMapCanvas(self) 33 | hl = QHBoxLayout(self.frame) 34 | hl.setContentsMargins(0, 0, 0, 0) 35 | hl.addWidget(self.mapCanvas) 36 | 37 | # 建立桥梁 38 | self.model = QgsLayerTreeModel(PROJECT.layerTreeRoot(), self) 39 | self.model.setFlag(QgsLayerTreeModel.AllowNodeRename) 40 | self.model.setFlag(QgsLayerTreeModel.AllowNodeReorder) 41 | self.model.setFlag(QgsLayerTreeModel.AllowNodeChangeVisibility) 42 | self.model.setFlag(QgsLayerTreeModel.ShowLegendAsTree) 43 | self.model.setAutoCollapseLegendNodes(10) 44 | self.layerTreeView.setModel(self.model) 45 | self.layerTreeBridge = QgsLayerTreeMapCanvasBridge(PROJECT.layerTreeRoot(), self.mapCanvas, self) 46 | # 显示经纬度 47 | self.mapCanvas.xyCoordinates.connect(self.showLngLat) 48 | 49 | # 打开工程 50 | self.actionOpen.triggered.connect(self.actionOpenTriggered) 51 | # 退出程序 52 | self.actionQuit.triggered.connect(self.close) 53 | 54 | # 地图工具 55 | # TODO:放大、缩小没有图标 56 | self.actionPanTriggered() 57 | self.actionPan.triggered.connect(self.actionPanTriggered) 58 | self.actionZoomin.triggered.connect(self.actionZoomInTriggered) 59 | self.actionZoomout.triggered.connect(self.actionZoomOutTriggered) 60 | self.actionIdentity.triggered.connect(self.actionIdentifyTriggered) 61 | 62 | # 图层 63 | self.actionShapefile.triggered.connect(self.actionShapefileTriggered) 64 | self.actionCsv.triggered.connect(self.actionCsvTriggered) 65 | self.actionPostGIS.triggered.connect(self.actionPostGISTriggered) 66 | self.actionWFS.triggered.connect(self.actionWFSTriggered) 67 | 68 | self.actionGeotiff.triggered.connect(self.actionGeotiffTriggered) 69 | self.actionXYZ.triggered.connect(self.actionXYZTriggered) 70 | 71 | # 绘图工具 72 | self.actionPoint.triggered.connect(self.actionPointTriggered) 73 | self.actionLine.triggered.connect(self.actionLineTriggered) 74 | self.actionRectangle.triggered.connect(self.actionRectangleTriggered) 75 | self.actionPolygon.triggered.connect(self.actionPolygonTriggered) 76 | 77 | # 关于Qt 78 | self.actionAboutQt.triggered.connect(lambda: QMessageBox.aboutQt(self, '关于Qt')) 79 | self.actionAbout.triggered.connect(lambda: QMessageBox.about(self, '关于', 'PyQGIS二次开发')) 80 | 81 | # self.actionPan.triggered.connect(self.actionPanTriggered) 82 | # self.actionIdentify.triggered.connect(self.actionIdentifyTriggered) 83 | 84 | # 图层右键菜单 85 | self.customMenuProvider = CustomMenuProvider(self.layerTreeView, self.mapCanvas) 86 | self.layerTreeView.setMenuProvider(self.customMenuProvider) 87 | # self.layerTreeRegistryBridge = QgsLayerTreeRegistryBridge(PROJECT.layerTreeRoot(), PROJECT, self) 88 | 89 | def actionOpenTriggered(self): 90 | """打开工程""" 91 | data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '工程文件(*.qgs , *.qgz)') 92 | if data_file: 93 | PROJECT.read(data_file) 94 | 95 | def actionPanTriggered(self): 96 | self.mapTool = QgsMapToolPan(self.mapCanvas) 97 | self.mapCanvas.setMapTool(self.mapTool) 98 | 99 | def actionZoomInTriggered(self): 100 | self.mapTool = QgsMapToolZoom(self.mapCanvas, False) 101 | self.mapCanvas.setMapTool(self.mapTool) 102 | 103 | def actionZoomOutTriggered(self): 104 | self.mapTool = QgsMapToolZoom(self.mapCanvas, True) 105 | self.mapCanvas.setMapTool(self.mapTool) 106 | 107 | def actionIdentifyTriggered(self): 108 | # 设置识别工具 109 | self.identifyTool = QgsMapToolIdentifyFeature(self.mapCanvas) 110 | self.identifyTool.featureIdentified.connect(self.showFeatures) 111 | self.mapCanvas.setMapTool(self.identifyTool) 112 | 113 | # 设置需要识别的图层 114 | layers = self.mapCanvas.layers() 115 | if layers: 116 | # 识别画布中第一个图层 117 | self.identifyTool.setLayer(layers[0]) 118 | 119 | def showFeatures(self, feature): 120 | print(type(feature)) 121 | 122 | QMessageBox.information(self, '信息', ''.join(feature.attributes())) 123 | 124 | def actionAddGroupTriggered(self): 125 | PROJECT.layerTreeRoot().addGroup('group1') 126 | 127 | def actionShapefileTriggered(self): 128 | """打开shp""" 129 | data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '*.shp') 130 | if data_file: 131 | layer = QgsVectorLayer(data_file, os.path.splitext(os.path.basename(data_file))[0], "ogr") 132 | self.addLayer(layer) 133 | 134 | def actionCsvTriggered(self): 135 | """加载csv数据""" 136 | data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '*.csv') 137 | if data_file: 138 | # 去掉盘符,否则图层无效 139 | data_file = os.path.splitdrive(data_file)[1] 140 | uri = f"file://{data_file}?delimiter=,&xField=x&yField=y" 141 | print(uri) 142 | layer = QgsVectorLayer(uri, "point", "delimitedtext") 143 | self.addLayer(layer) 144 | 145 | def actionPostGISTriggered(self): 146 | """加载postgis图层""" 147 | dialog = PostGISDialog(self) 148 | if dialog.exec_(): 149 | uri = QgsDataSourceUri() 150 | uri.setConnection( 151 | dialog.lineEditHost.text(), 152 | dialog.lineEditPort.text(), 153 | dialog.lineEditDatabase.text(), 154 | dialog.lineEditUsername.text(), 155 | dialog.lineEditPassword.text()) 156 | # lineEditGeometryColumn:根据实际情况,可能为:wkb_geometry、geometry、the_geom... 157 | uri.setDataSource("public", 158 | dialog.lineEditLayer.text(), 159 | dialog.lineEditGeometryColumn.text()) 160 | 161 | layer = QgsVectorLayer(uri.uri(False), dialog.lineEditLayer.text(), "postgres") 162 | self.addLayer(layer) 163 | 164 | def actionWFSTriggered(self): 165 | """加载天地图WFS图层""" 166 | uri = 'http://gisserver.tianditu.gov.cn/TDTService/wfs?' \ 167 | 'srsname=EPSG:4326&typename=TDTService:RESA&version=auto&request=GetFeature&service=WFS' 168 | layer = QgsVectorLayer(uri, "RESA", "WFS") 169 | self.addLayer(layer) 170 | 171 | def actionGeotiffTriggered(self): 172 | """加载geotiff""" 173 | data_file, ext = QFileDialog.getOpenFileName(self, '打开', '', '*.tif') 174 | if data_file: 175 | layer = QgsRasterLayer(data_file, os.path.basename(data_file)) 176 | self.addLayer(layer) 177 | 178 | def actionXYZTriggered(self): 179 | uri = 'type=xyz&' \ 180 | 'url=https://www.google.cn/maps/vt?lyrs=s@804%26gl=cn%26x={x}%26y={y}%26z={z}&' \ 181 | 'zmax=19&' \ 182 | 'zmin=0&' \ 183 | 'crs=EPSG3857' 184 | layer = QgsRasterLayer(uri, 'google', 'wms') 185 | self.addLayer(layer) 186 | 187 | def addLayer(self, layer): 188 | if layer.isValid(): 189 | if self.first_flag: 190 | self.mapCanvas.setDestinationCrs(layer.crs()) 191 | self.mapCanvas.setExtent(layer.extent()) 192 | self.first_flag = False 193 | PROJECT.addMapLayer(layer) 194 | layers = [layer] + [PROJECT.mapLayer(i) for i in PROJECT.mapLayers()] 195 | self.mapCanvas.setLayers(layers) 196 | self.mapCanvas.refresh() 197 | else: 198 | print('图层无效.') 199 | 200 | def actionPointTriggered(self): 201 | self.pointTool = PointMapTool(self.mapCanvas) 202 | self.mapCanvas.setMapTool(self.pointTool) 203 | 204 | def actionLineTriggered(self): 205 | self.lineTool = LineMapTool(self.mapCanvas) 206 | self.mapCanvas.setMapTool(self.lineTool) 207 | 208 | def actionRectangleTriggered(self): 209 | self.rectangleTool = RectangleMapTool(self.mapCanvas) 210 | self.mapCanvas.setMapTool(self.rectangleTool) 211 | 212 | def actionPolygonTriggered(self): 213 | self.polygonTool = PolygonMapTool(self.mapCanvas) 214 | self.mapCanvas.setMapTool(self.polygonTool) 215 | 216 | def showLngLat(self, point): 217 | x = point.x() 218 | y = point.y() 219 | self.statusbar.showMessage(f'经度:{x}, 纬度:{y}') 220 | --------------------------------------------------------------------------------