Карта фолиума, отображаемая с помощью PyQT5, мигает при каждом обновлении.Python

Программы на Python
Ответить Пред. темаСлед. тема
Anonymous
 Карта фолиума, отображаемая с помощью PyQT5, мигает при каждом обновлении.

Сообщение Anonymous »

Я разрабатываю визуализатор карт с помощью PyQT5 и использую folium. Я кое-что создал, но есть несколько проблем, которые я не смог решить. В этом вопросе я сосредотачиваюсь только на одном из них и спрошу других, если тем временем не смогу решить.
Вот в чем проблема. У меня есть data_provider для целей тестирования. Когда он обновляет координаты корабля и карту курса, необходимо обновить его, чтобы корабль оставался в центре. Но при обновлении я думаю, что мне нужно заново создать карту, и что-то вызывает перепрошивку. Вот проблема в видео.
https://drive.google.com/file/d/1Gf3c2a ... sp=sharing
А вот мой код.

Код: Выделить всё

import io
import sys
import folium

from PyQt5.QtGui import QRegion
from PyQt5.QtCore import QRect, QTimer
from PyQt5 import QtWidgets, QtWebEngineWidgets

class Map(QtWidgets.QWidget):
"""
Updates the map's location and heading based on parameters.
Places a circular map inside a frame with a circular alarm mask.
"""
triggered = False

def __init__(self) -> None:
super().__init__()
self.map = None
self.init_ui()

def init_ui(self) -> None:
# Create layout
self.layout = QtWidgets.QVBoxLayout(self)
self.setLayout(self.layout)

# Create a parent frame for the circular map
self.frame = QtWidgets.QWidget(self)
self.frame.setFixedSize(310, 310)
self.frame.setStyleSheet(
"border: 5px solid black; border-radius: 155px;")
self.frame.setGeometry(145, 10, 310, 310)
self.layout.addWidget(self.frame)

# Add the WebEngineView for the map inside the frame
self.map_view = QtWebEngineWidgets.QWebEngineView(self.frame)
self.map_view.setFixedSize(300, 300)
self.map_view.setGeometry(5, 5, 300, 300)

# Apply a circular mask to the map view
circular_region = QRegion(QRect(0, 0, self.map_view.width(),
self.map_view.height()), QRegion.Ellipse)
self.map_view.setMask(circular_region)

# Create buttons and input fields
self.control_layout = QtWidgets.QHBoxLayout()
self.layout.addLayout(self.control_layout)

self.lat_input = QtWidgets.QLineEdit(self)
self.lat_input.setPlaceholderText("Latitude")
self.control_layout.addWidget(self.lat_input)

self.lon_input = QtWidgets.QLineEdit(self)
self.lon_input.setPlaceholderText("Longitude")
self.control_layout.addWidget(self.lon_input)

self.heading_input = QtWidgets.QLineEdit(self)
self.heading_input.setPlaceholderText("Heading (degrees)")
self.control_layout.addWidget(self.heading_input)

self.update_button = QtWidgets.QPushButton("Update Location", self)
self.update_button.clicked.connect(self.update_location)
self.control_layout.addWidget(self.update_button)

self.update_button = QtWidgets.QPushButton("Test", self)
self.update_button.clicked.connect(self.data_provider)
self.control_layout.addWidget(self.update_button)

self.trigger_button = QtWidgets.QPushButton("Trigger Frame Color", self)
self.trigger_button.clicked.connect(self.trigger_frame)
self.control_layout.addWidget(self.trigger_button)

self.example_continous_data = [
(40.851, 29.041, 311, [(40.85851, 29.04981, 1)]),
(40.852, 29.042, 312, [(40.85852, 29.04982, 2)]),
(40.853, 29.043, 313, [(40.85853, 29.04983, 3)]),
(40.854, 29.044, 314, [(40.85854, 29.04984, 4)]),
(40.855, 29.045, 315, [(40.85855, 29.04985, 5)]),
(40.856, 29.046, 316, [(40.85856, 29.04986, 6)]),
(40.857, 29.047, 317, [(40.85857, 29.04987, 7)]),
(40.858, 29.048, 318, [(40.85858, 29.04988, 8)]),
(40.859, 29.049, 319, [(40.85859, 29.04989, 9)])
]
self.data_index = 0

def data_provider(self) -> None:
"""Update the map with the next data point every second."""
if self.data_index < len(self.example_continous_data):
latitude, longitude, degree, dangerous_areas = \
self.example_continous_data[self.data_index]
self.create_map(latitude, longitude, degree, dangerous_areas)
self.data_index += 1
else:
self.data_index = 0
self.timer2 = QTimer()
self.timer2.timeout.connect(self.data_provider)
self.timer2.start(1000)

def create_map(self, latitude, longitude, heading, dangerous_areas) ->  None:
"""
Create or update a Folium map centered on the given location
with a heading arrow.
"""
self.map = folium.Map(
location=[latitude, longitude],
zoom_start=14,
tiles="OpenStreetMap",
attribution_control=False,
zoom_control=True
)
folium.TileLayer("OpenSeaMap", name="OpenSeaMap").add_to(self.map)
# Custom CSS for circular map and repositioned controls
circular_css = """

.leaflet-top.leaflet-left {
left: 24%; /* Adjust horizontal positioning of controls */
top: 90%; /* Adjust vertical positioning of controls */
transform: translate(-24%, -90%);
position: absolute;
z-index: 1000;/*Ensure controls are visible above the map*/
}

"""
# Inject the custom CSS into the map HTML
self.map.get_root().header.add_child(folium.Element(circular_css))
# Add a ship marker with an arrow to indicate heading
size = 22
arrow_icon = folium.DivIcon(html=f"""
font-size: {size}px; color: red;">
➤

""")
marker = folium.Marker(
location=[latitude, longitude],
icon=arrow_icon,
tooltip=f"{latitude}, {longitude}, {heading}°"
)
marker.add_to(self.map)

# Add dangerous areas
for lat, lon, depth in dangerous_areas:
circle = folium.Circle(
location=[lat, lon],
radius=100,
color="red",
fill=True,
fill_color="red",
fill_opacity=0.5,
tooltip=f"Depth: {depth}m"
)
circle.add_to(self.map)
self.render_map()

def render_map(self) -> None:
# Save map to memory
data = io.BytesIO()
self.map.save(data, close_file=False)
# Display the map in the WebEngineView
self.map_view.setHtml(data.getvalue().decode())
data.close()

def update_location(self) -> None:
"""Update the map's location and heading based on user input."""
try:
latitude = float(self.lat_input.text())
longitude = float(self.lon_input.text())
heading = float(self.heading_input.text())
self.create_map(latitude, longitude, heading, [])
except ValueError:
QtWidgets.QMessageBox.critical(self,
"Error", "Invalid latitude, longitude, or heading")

def update_frame_style(self) -> None:
"""Update the frame style based on the `triggered` variable."""
red = "border: 5px solid red; border-radius: 155px;"
black = "border: 5px solid black; border-radius: 155px;"
if self.triggered:
# create a loop to blink the frame in parallel
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame_style)
self.timer.start(1000)
if self.frame.styleSheet() == red:
self.frame.setStyleSheet(black)
else:
self.frame.setStyleSheet(red)
else:
# reset the frame to black
self.frame.setStyleSheet(black)

def trigger_frame(self) -> None:
"""Toggle the frame color based on an external trigger."""
self.triggered = not self.triggered
self.update_frame_style()

class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Dynamic Location Update with Heading")
self.resize(600, 600)
self.setCentralWidget(Map())

if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main_window = Map()
main_window.show()
sys.exit(app.exec_())

Спасибо.


Подробнее здесь: https://stackoverflow.com/questions/792 ... ery-update
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Python»