如何将圆形标记添加到嵌入在 QWebEngineView 中的渲染大叶地图?

时间:2021-08-01 22:09:39

标签: python pyqt5 folium python-3.9 qwebengineview

我想开发一个桌面应用程序,涉及每秒从串行端口接收一个地理坐标并实时添加到地图中。地图应类似于以下链接:

enter image description here

我编写了一段代码来测试 Folium 执行此任务的能力。

import sys
import io
import folium
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QMainWindow, QPushButton
from PyQt5.QtWebEngineWidgets import QWebEngineView


class Window(QMainWindow):
    def __init__(self):
        super().__init__()

        coordinate = (41.8828, 12.4761)

        self.m = folium.Map(
            zoom_start = 18,
            location = coordinate,
            control_scale=True,
            tiles = None
        )

        folium.raster_layers.TileLayer(
            tiles='http://mt1.google.com/vt/lyrs=m&h1=p1Z&x={x}&y={y}&z={z}',
            name='Standard Roadmap',
            attr = 'Google Map',
        ).add_to(self.m)

        folium.raster_layers.TileLayer(
            tiles='http://mt1.google.com/vt/lyrs=s&h1=p1Z&x={x}&y={y}&z={z}',
            name='Satellite Only',
            attr = 'Google Map',
        ).add_to(self.m)

        folium.raster_layers.TileLayer(
            tiles='http://mt1.google.com/vt/lyrs=y&h1=p1Z&x={x}&y={y}&z={z}',
            name='Hybrid',
            attr = 'Google Map',
        ).add_to(self.m)      

        folium.LayerControl().add_to(self.m)

        folium.Marker(coordinate).add_to(self.m)
                                
        self.data = io.BytesIO()
        self.m.save(self.data, close_file=False)

        widget=QWidget()
        vbox = QVBoxLayout()

        buttun1 = QPushButton("Insert Marker")
        buttun1.clicked.connect(self.insert_marker)

        self.webView = QWebEngineView()
        self.webView.setHtml(self.data.getvalue().decode())
        self.webView.setContextMenuPolicy(Qt.NoContextMenu)
    
        vbox.addWidget(buttun1)
        vbox.addWidget(self.webView)
        widget.setLayout(vbox)
        
        self.setCentralWidget(widget)
        
        self.setWindowTitle("App")
        
        self.setMinimumSize(1000, 600)
        self.showMaximized()

    def insert_marker(self):
        folium.CircleMarker([41.8829, 12.4766],
            radius=2,
            weight=5,
        ).add_to(self.m)  
        self.m.save(self.data, close_file=False)
        self.webView.setHtml(self.data.getvalue().decode())
       

App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())

在这段代码中,folium地图嵌入在一个PyQt5 QWebEngineView中,点击上面的按钮后,预计会在地图上添加一个圆形标记。但是,点击后,地图只会重新渲染。

尽管 discussions 关于不可能无缝更新生成的大叶植物地图,似乎使用 ClickForMarker() 可以向渲染的地图添加标记。

有没有办法在不点击的情况下获得相同的功能?

1 个答案:

答案 0 :(得分:2)

您可以通过 runJavaScript() 方法执行 javascript 添加标记:

import io
import sys

from jinja2 import Template

import folium

from PyQt5.QtCore import pyqtSignal, QObject, QTimer
from PyQt5.QtWidgets import QApplication, QMainWindow
from PyQt5.QtWebEngineWidgets import QWebEngineView


class CoordinateProvider(QObject):
    coordinate_changed = pyqtSignal(float, float)

    def __init__(self, parent=None):
        super().__init__(parent)
        self._timer = QTimer(interval=1000)
        self._timer.timeout.connect(self.generate_coordinate)

    def start(self):
        self._timer.start()

    def stop(self):
        self._timer.stop()

    def generate_coordinate(self):
        import random

        center_lat, center_lng = 41.8828, 12.4761
        x, y = (random.uniform(-0.001, 0.001) for _ in range(2))
        latitude = center_lat + x
        longitude = center_lng + y
        self.coordinate_changed.emit(latitude, longitude)


class Window(QMainWindow):
    def __init__(self):
        super().__init__()
        coordinate = (41.8828, 12.4761)
        self.map = folium.Map(
            zoom_start=18, location=coordinate, control_scale=True, tiles=None
        )
        folium.raster_layers.TileLayer(
            tiles="http://mt1.google.com/vt/lyrs=m&h1=p1Z&x={x}&y={y}&z={z}",
            name="Standard Roadmap",
            attr="Google Map",
        ).add_to(self.map)
        folium.raster_layers.TileLayer(
            tiles="http://mt1.google.com/vt/lyrs=s&h1=p1Z&x={x}&y={y}&z={z}",
            name="Satellite Only",
            attr="Google Map",
        ).add_to(self.map)
        folium.raster_layers.TileLayer(
            tiles="http://mt1.google.com/vt/lyrs=y&h1=p1Z&x={x}&y={y}&z={z}",
            name="Hybrid",
            attr="Google Map",
        ).add_to(self.map)
        folium.LayerControl().add_to(self.map)
        folium.Marker(coordinate).add_to(self.map)

        data = io.BytesIO()
        self.map.save(data, close_file=False)

        self.map_view = QWebEngineView()
        self.map_view.setHtml(data.getvalue().decode())

        self.setCentralWidget(self.map_view)

    def add_marker(self, latitude, longitude):
        js = Template(
            """
        L.marker([{{latitude}}, {{longitude}}] )
            .addTo({{map}});
        L.circleMarker(
            [{{latitude}}, {{longitude}}], {
                "bubblingMouseEvents": true,
                "color": "#3388ff",
                "dashArray": null,
                "dashOffset": null,
                "fill": false,
                "fillColor": "#3388ff",
                "fillOpacity": 0.2,
                "fillRule": "evenodd",
                "lineCap": "round",
                "lineJoin": "round",
                "opacity": 1.0,
                "radius": 2,
                "stroke": true,
                "weight": 5
            }
        ).addTo({{map}});
        """
        ).render(map=self.map.get_name(), latitude=latitude, longitude=longitude)
        self.map_view.page().runJavaScript(js)


def main():
    app = QApplication(sys.argv)

    window = Window()
    window.showMaximized()

    provider = CoordinateProvider()
    provider.coordinate_changed.connect(window.add_marker)
    provider.start()

    sys.exit(app.exec())


if __name__ == "__main__":
    main()

enter image description here