You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt5+Leaflet船舶地图开发:L未定义及标记不显示问题求助

问题修复:Leaflet + PyQt5地图标记失败及JS错误

核心问题分析

  1. Uncaught ReferenceError: L is not defined:Python执行JS代码时,Leaflet库可能尚未加载完成,或地图初始化的变量作用域受限导致无法访问。
  2. Python ships对象标记不显示:
    • HTML中mymap是DOMContentLoaded回调的局部变量,外部JS无法访问。
    • Python在HTML未完全加载时就执行了标记添加逻辑,此时地图还未完成初始化。

修复步骤

1. 修改map.html(调整变量作用域)

将mymap和shipIcon改为全局变量,确保外部JS能访问;保留DOM加载完成后的初始化逻辑:

<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Ship Map</title>
  <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
  <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
</head>
<body>
<div id="map" style="height: 100vh;"></div>

<script>
  // 声明全局变量,供外部JS调用
  var mymap;
  var shipIcon;

  document.addEventListener('DOMContentLoaded', function() {
    mymap = L.map('map').setView([0, 0], 2);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
      attribution: '© OpenStreetMap contributors'
    }).addTo(mymap);

    shipIcon = L.icon({
      // 建议改用相对路径,避免本地绝对路径的访问限制
      iconUrl: 'photos/ship.png',
      iconSize: [64, 64],
      iconAnchor: [16, 16],
      popupAnchor: [0, -16]
    });

    // 保留原有示例标记(可选)
    var ships = [
      { Embarkation: [18.9750, 72.8258], Name: 'Ship1' },
      { Embarkation: [13.0827, 80.2707], Name: 'Ship2' }
    ];

    ships.forEach(function (ship) {
      var marker = L.marker(ship.Embarkation, { icon: shipIcon }).addTo(mymap);
      marker.bindPopup("<b>" + ship.Name + "</b>").openPopup();
    });
  });
</script>
</body>
</html>

2. 修改map.py(调整JS执行时机)

监听页面加载完成信号,确保HTML完全加载后再执行标记添加逻辑;优化JS命令:

import sys
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
import random

class MapApp(QMainWindow):
    class ships:
        speed = 0
        
        def __init__(self,Name,TYPE,IMO,Capacity,Condition,Navigation_Status,Embarkation,Departure_Time,Departure,Arrival_Time,Image):
            self.Name = Name
            self.IMO = IMO
            self.Condition = Condition
            self.Capacity = Capacity
            self.Navigation_Status = Navigation_Status
            self.Type = TYPE
            self.Embarkation = Embarkation
            self.Departure_Time = Departure_Time
            self.Departure = Departure
            self.Arrival_Time = Arrival_Time
            self.Image = Image

        @classmethod
        def change_condition(cls, condition):
            cls.condition = condition
        
        @classmethod
        def change_navigation_status(cls, navigation_status):
            cls.navigation_status = navigation_status

        def update_speed(self):
            self.speed = random.randint(25, 30)

    def __init__(self):
        super().__init__()

        self.setWindowTitle("Map App")
        self.setGeometry(100, 100, 800, 600)

        self.web_view = QWebEngineView()
        self.setCentralWidget(self.web_view)

        # 监听页面加载完成信号,确保地图初始化后再添加标记
        self.web_view.loadFinished.connect(self.on_page_loaded)

        # 加载HTML文件(建议改用相对路径,避免硬编码绝对路径)
        self.web_view.setUrl(QUrl.fromLocalFile("E:\\Project CS\\Vessel Traffic Management System\\GUI\\map.html"))

        self.ship_objects = []
        self.create_ships()

    def create_ships(self):
        ship1 = self.ships(Name="Eren", TYPE="Type1", IMO="IMO1", Capacity=100, Condition="Good",
                           Navigation_Status="Active", Embarkation=[0, 0], Departure_Time="Time1",
                           Departure="Departure1", Arrival_Time="Arrival1", Image="Image1")
        ship2 = self.ships(Name="Mikasa", TYPE="Type2", IMO="IMO2", Capacity=150, Condition="Excellent",
                           Navigation_Status="Inactive", Embarkation=[10, 10], Departure_Time="Time2",
                           Departure="Departure2", Arrival_Time="Arrival2", Image="Image2")

        self.ship_objects.append(ship1)
        self.ship_objects.append(ship2)

    def on_page_loaded(self, success):
        if success:
            self.update_map()

    def update_map(self):
        js_commands = []
        
        for ship in self.ship_objects:
            lat, lng = ship.Embarkation
            # 使用全局的mymap和shipIcon创建标记
            js_command = f"L.marker([{lat},{lng}], {{icon: shipIcon}}).addTo(mymap).bindPopup('<b>{ship.Name}</b>').openPopup();"
            js_commands.append(js_command)

        js_code = "\n".join(js_commands)
        self.web_view.page().runJavaScript(js_code)
        print("Ship markers added successfully")

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MapApp()
    window.show()
    sys.exit(app.exec_())

额外注意事项

  • 本地资源路径:HTML中的shipIcon建议使用相对路径(如photos/ship.png),确保和HTML文件的目录结构匹配,避免QWebEngineView的本地文件访问限制。
  • 调试方法:可通过web_view.page().runJavaScript("console.log('调试信息')")输出日志,或开启开发者工具(web_view.page().settings().setAttribute(QWebEngineSettings.DeveloperExtrasEnabled, True))查看JS错误详情。

内容的提问来源于stack exchange,提问作者Nakul Desai

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 10:45:57