Search code examples
pythonuser-interfacepyqt5openstreetmap

Markers not updating on map in PyQt5 application with QTimer


I'm building a user interface, that put some random values in some graph and add some markers in a map randomly. This is the code:

from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QGridLayout, QHBoxLayout
from PyQt5.QtCore import QTimer
from classes.MapViewWidget import MapView
from classes.RawDataWidget import RawDataWidget
from classes.TemperatureGraphWidget import TemperatureGraph
from classes.ArduinoThread import ArduinoThread
import random


class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)
        self.setWindowTitle("Ground Control")

        # Create the widgets for the temperature and pressure graphs, the map, and the raw data
        self.map_view = MapView(self)
        self.temperature_graph = TemperatureGraph(self)
        self.pressure_graph = TemperatureGraph(self)
        self.raw_data_view = RawDataWidget(self)

        # Create a horizontal layout for the temperature and pressure graphs
        temperature_pressure_layout = QHBoxLayout()
        temperature_pressure_layout.addWidget(self.temperature_graph)
        temperature_pressure_layout.addWidget(self.pressure_graph)

        temperature_pressure_layout.setSpacing(0)  # Set spacing to zero

        # Create layout for all the widgets
        grid_layout = QGridLayout()

        # Every widget take up 1/2 of the raw
        grid_layout.setColumnStretch(0, 2)
        grid_layout.setColumnStretch(1, 2)

        grid_layout.addWidget(self.temperature_graph, 0, 0, 1, 1)
        grid_layout.addWidget(self.map_view, 0, 1, 1, 1)
        grid_layout.addWidget(self.pressure_graph, 1, 0, 1, 1)
        grid_layout.addWidget(self.raw_data_view, 1, 1, 1, 1)

        grid_layout.setSpacing(0)  # Set spacing to zero
        grid_layout.setContentsMargins(0, 0, 0, 0)  # Set margins to zero

        # Create a central widget and set the grid layout
        central_widget = QWidget()
        central_widget.setLayout(grid_layout)
        self.setCentralWidget(central_widget)

        # set timer of 1 sec
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_data)
        self.timer.start(1000)

    def update_data(self):

        latitude = random.uniform(12.0, 13.0)
        longitude = random.uniform(77.0, 78.0)
        self.map_view.add_marker(latitude, longitude)

        # update graph values randomly
        raw_text = ""
        for i in range(0, 10):
            rnd_num = random.randint(10, 24)
            raw_text += "Temperature value: " + \
                str(rnd_num) + "°C --- Time: " + str(i) + "s\n"
            self.temperature_graph.update(rnd_num, i)
            self.raw_data_view.set_data(raw_text)


if __name__ == "__main__":
    app = QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

This is the code for the MapView class:

from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWebChannel import QWebChannel


class MapView(QWebEngineView):
    def __init__(self, parent=None):
        super(MapView, self).__init__(parent)
        self.web_channel = QWebChannel(self.page())
        self.page().setWebChannel(self.web_channel)

        # Load the HTML page
        self.load(QUrl.fromLocalFile(
            "./ground_control/map/map.html"))

        # Wait for the page to finish loading before initializing the map
        self.loadFinished.connect(self.initialize_map)

    def initialize_map(self):
        self.page().runJavaScript("initializeMap();")
    
    #add the marker to the map by calling js function
    def add_marker(self, latitude, longitude):
        self.page().loadFinished.connect(lambda: self.page().runJavaScript(
            f"addMarker({latitude}, {longitude});"))

The problem is that this code is not adding the markers to the map, however I tried changing the code in this way, replacing:

        # set timer of 1 sec
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_data)
        self.timer.start(1000)

with:

        self.update_data()

and it works fine, I don't understand why. What can I do to resolve the problem?


Solution

  • I understood what was the problem, in the class MapView, there was the function:

        def add_marker(self, latitude, longitude):
           self.page().loadFinished.connect(lambda: self.page().runJavaScript(
            f"addMarker({latitude}, {longitude});"))
    

    that I needed in the previous version of the app, by substituting the add_marker() function with this one, it works fine:

         def add_marker(self, latitude, longitude):
            self.page().runJavaScript(f"addMarker({latitude}, {longitude});")