├── .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 | 
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 |
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 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 | 0
163 | 0
164 | 1
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
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 |
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 |
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 |
--------------------------------------------------------------------------------