import os import requests from PyQt5.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QComboBox, QGroupBox, QToolBar, QAction, QGridLayout) from PyQt5.QtCore import Qt, QUrl, pyqtSlot, QSize from PyQt5.QtGui import QIcon from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage, QWebEngineProfile, QWebEngineSettings from PyQt5.QtWebEngineCore import QWebEngineUrlRequestInterceptor class RequestInterceptor(QWebEngineUrlRequestInterceptor): """网络请求拦截器,用于调试地图加载问题""" def interceptRequest(self, info): print(f"请求URL: {info.requestUrl().toString()}") print(f"请求方法: {info.requestMethod()}") print(f"请求头: {info.requestHeaders()}") class CustomWebEnginePage(QWebEnginePage): def javaScriptConsoleMessage(self, level, message, line, source): level_str = { 0: "INFO", 1: "WARNING", 2: "ERROR" }.get(level, "UNKNOWN") print(f"JS控制台 [{level_str}] {message} (第{line}行, 来源: {source})") class MapView(QWidget): """地图视图组件,用于在地理信息系统上显示监测区域和告警位置""" def __init__(self, config): super().__init__() self.config = config self.init_ui() def init_ui(self): """初始化UI""" # 创建主布局 layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) # 创建地图容器 map_container = QWidget() map_layout = QVBoxLayout(map_container) map_layout.setContentsMargins(0, 0, 0, 0) # 创建工具栏 toolbar = QToolBar() toolbar.setIconSize(QSize(16, 16)) # 添加地图类型选择下拉框 self.map_type_combo = QComboBox() self.map_type_combo.addItems(["卫星图", "地形图", "道路图", "混合图"]) self.map_type_combo.setCurrentIndex(0) # 设置默认选中卫星图 self.map_type_combo.currentIndexChanged.connect(self.change_map_type) toolbar.addWidget(QLabel("地图类型: ")) toolbar.addWidget(self.map_type_combo) toolbar.addSeparator() # 添加区域选择下拉框 self.region_combo = QComboBox() for region in self.config.get('monitor_regions', []): self.region_combo.addItem(region['name'], region) self.region_combo.currentIndexChanged.connect(self.change_region) toolbar.addWidget(QLabel("监测区域: ")) toolbar.addWidget(self.region_combo) toolbar.addSeparator() # 添加缩放按钮 self.zoom_in_btn = QPushButton("放大") self.zoom_in_btn.setIcon(QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'assets', 'zoom_in.png'))) self.zoom_in_btn.clicked.connect(self.zoom_in) toolbar.addWidget(self.zoom_in_btn) self.zoom_out_btn = QPushButton("缩小") self.zoom_out_btn.setIcon(QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'assets', 'zoom_out.png'))) self.zoom_out_btn.clicked.connect(self.zoom_out) toolbar.addWidget(self.zoom_out_btn) toolbar.addSeparator() # 显示/隐藏告警点 self.show_alerts_btn = QPushButton("显示告警") self.show_alerts_btn.setCheckable(True) self.show_alerts_btn.setChecked(True) self.show_alerts_btn.clicked.connect(self.toggle_alerts) toolbar.addWidget(self.show_alerts_btn) toolbar.addSeparator() # 添加定位按钮 self.location_btn = QPushButton("定位") self.location_btn.setIcon(QIcon(os.path.join(os.path.dirname(os.path.dirname(__file__)), 'assets', 'location.png'))) self.location_btn.clicked.connect(self.locate_current_position) toolbar.addWidget(self.location_btn) # 添加工具栏到地图布局 map_layout.addWidget(toolbar) # 创建Web视图用于显示地图 self.web_view = QWebEngineView() # 配置Edge浏览器引擎 profile = QWebEngineProfile.defaultProfile() profile.setHttpUserAgent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59") # 添加请求拦截器 interceptor = RequestInterceptor() profile.setUrlRequestInterceptor(interceptor) # 启用必要的Web功能 settings = profile.settings() settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True) settings.setAttribute(QWebEngineSettings.LocalStorageEnabled, True) settings.setAttribute(QWebEngineSettings.WebGLEnabled, True) settings.setAttribute(QWebEngineSettings.PluginsEnabled, True) settings.setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True) # 启用跨域访问 profile.setHttpCacheType(QWebEngineProfile.DiskHttpCache) profile.setPersistentCookiesPolicy(QWebEngineProfile.AllowPersistentCookies) # 设置页面 page = CustomWebEnginePage(self.web_view) self.web_view.setPage(page) map_layout.addWidget(self.web_view) # 将地图容器添加到主布局 layout.addWidget(map_container) # 加载初始地图 self.load_map() def load_map(self): """加载百度地图""" try: # 获取地图配置 center = self.config.get('map_center', [39.915, 116.404]) zoom = self.config.get('map_zoom', 15) # 使用临时文件加载地图 import tempfile temp_path = os.path.join(tempfile.gettempdir(), "map_temp.html") # 构建HTML html = f""" 森林监测地图
加载百度地图中...
""" # 将HTML保存到临时文件 with open(temp_path, "w", encoding="utf-8") as f: f.write(html) # 从本地文件加载 self.web_view.load(QUrl.fromLocalFile(temp_path)) print("正在从本地文件加载百度地图...") except Exception as e: print(f"地图加载失败: {e}") # 显示错误信息 error_html = f"""

地图加载失败

错误信息: {str(e)}

请检查以下内容:

  1. 确认网络连接正常
  2. 确认百度地图API密钥有效
  3. 检查PyQt WebEngine设置
  4. 查看控制台输出的详细错误信息
""" self.web_view.setHtml(error_html) @pyqtSlot(int) def change_map_type(self, index): """改变地图类型""" # 通过JS调用地图函数 script = f""" try {{ console.log('调用地图类型切换,类型索引:', {index}); if (window.mapFunctions && typeof window.mapFunctions.setMapType === 'function') {{ window.mapFunctions.setMapType({index}); return true; }} else {{ console.error('地图类型切换函数不可用'); return false; }} }} catch(e) {{ console.error('执行地图类型切换时出错:', e); return false; }} """ self.web_view.page().runJavaScript(script) @pyqtSlot(int) def change_region(self, index): """改变监测区域""" if index >= 0 and index < len(self.config.get('monitor_regions', [])): region = self.config['monitor_regions'][index] # 通过JS调用地图函数 script = """ try { if (window.mapFunctions && typeof window.mapFunctions.panTo === 'function') { window.mapFunctions.panTo(0, 0); return true; } else { console.error('地图平移函数不可用'); return false; } } catch(e) { console.error('平移到区域时出错:', e); return false; } """ self.web_view.page().runJavaScript(script) @pyqtSlot() def zoom_in(self): """地图放大""" script = """ try { if (window.mapFunctions && typeof window.mapFunctions.zoomIn === 'function') { window.mapFunctions.zoomIn(); return true; } else { console.error('地图放大函数不可用'); return false; } } catch(e) { console.error('地图放大时出错:', e); return false; } """ self.web_view.page().runJavaScript(script) @pyqtSlot() def zoom_out(self): """地图缩小""" script = """ try { if (window.mapFunctions && typeof window.mapFunctions.zoomOut === 'function') { window.mapFunctions.zoomOut(); return true; } else { console.error('地图缩小函数不可用'); return false; } } catch(e) { console.error('地图缩小时出错:', e); return false; } """ self.web_view.page().runJavaScript(script) @pyqtSlot(bool) def toggle_alerts(self, checked): """切换告警点显示状态""" script = f""" try {{ if (window.mapFunctions && typeof window.mapFunctions.toggleAlerts === 'function') {{ window.mapFunctions.toggleAlerts({str(checked).lower()}); return true; }} else {{ console.error('告警点切换函数不可用'); return false; }} }} catch(e) {{ console.error('切换告警点时出错:', e); return false; }} """ self.web_view.page().runJavaScript(script) def locate_current_position(self): """定位当前位置""" script = """ try { if (!isMapLoaded) { console.error('地图未加载完成'); return false; } // 创建定位控件 var locationControl = new BMapGL.LocationControl(); locationControl.addEventListener("locationSuccess", function(e){{ var address = ''; address += e.addressComponent.province; address += e.addressComponent.city; address += e.addressComponent.district; address += e.addressComponent.street; address += e.addressComponent.streetNumber; // 在marker上显示信息窗口 var infoWindow = new BMapGL.InfoWindow( '
' + '
当前位置
' + '
经度: ' + e.point.lng + '
' + '
纬度: ' + e.point.lat + '
' + '
地址: ' + address + '
' + '
' ); var marker = new BMapGL.Marker(e.point); map.addOverlay(marker); marker.openInfoWindow(infoWindow); console.log('定位成功'); }}); locationControl.addEventListener("locationError", function(e){{ console.error('定位失败:' + e.message); }}); locationControl.location(); return true; } catch(e) { console.error('执行定位时出错:', e); return false; } """ self.web_view.page().runJavaScript(script) def update_view(self): """更新地图视图""" # 实际项目中可以在这里添加刷新告警点等逻辑 pass def get_accurate_ip_location(self): """获取更精确的IP定位信息""" try: # 使用腾讯位置服务 response = requests.get( 'https://apis.map.qq.com/ws/location/v1/ip', params={ 'key': self.config.get('qq_map_key', ''), # 需要在配置中添加腾讯地图密钥 'output': 'json' }, timeout=5 ) if response.status_code == 200: data = response.json() if data['status'] == 0: location = data['result']['location'] return { 'lng': location['lng'], 'lat': location['lat'], 'accuracy': data['result'].get('accuracy', 0) } except Exception as e: print(f"腾讯地图IP定位失败: {e}") return None