I am trying to use a MapView widget from kivy garden, but the position of my marker does not update. I have added a MapView
with a MapMarker
into the main.kv
file. These have the properties lat
and lon
. I tried to assign them the variables latitude
and longitude
form the main.py
variable by using app.latitude
and app.longitude
.
Inside my main.py I am using a update function inside the on_start
method. The update function simply calls two helper functions that fetches longitude and latitude coordinates (at the moment just random values).
The problem is that my mapview and the marker do not update when I run the code. What am I doing wrong?
# section of main.kv
MapView:
id: map_view
zoom: 17
lat: app.latitude
lon: app.longitude
MapMarker:
id: map_view_marker
lat: app.latitude
lon: app.longitude
And here is the section of the main.py
# main.py
…
class MainApp(App):
…
# map parameters
latitude = 50
longitude = 3
# Getting latitude and longitude (at the moment just random stuff
def get_gps_latitude(self):
self.latitude = self.decimal_precision(0.01 * random.random() + 50.6394, DECIMAL_PRECISION)
return self.latitude # rounding
def get_gps_longitude(self):
self.longitude = self.decimal_precision(0.01 * random.random() + 50.6394, DECIMAL_PRECISION)
return self.longitude
def update(self, _):
self.latitude = self.get_gps_latitude()
self.longitude = self.get_gps_longitude()
def on_start(self):
Clock.schedule_interval(self.update, 1)
Update: Adding the header of my kv file.
#:kivy 1.10.1
#:import Toolbar kivymd.toolbar.Toolbar
#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer
#:import NavigationLayout kivymd.navigationdrawer.NavigationLayout
#:import NavigationDrawerDivider kivymd.navigationdrawer.NavigationDrawerDivider
#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar
#:import NavigationDrawerSubheader kivymd.navigationdrawer.NavigationDrawerSubheader
#:import MDTextField kivymd.textfields.MDTextField
#:import MDSwitch kivymd.selectioncontrols.MDSwitch
#:import labels application.labels
#:import MapView kivy.garden.mapview
#:import MapMarkerPopup kivy.garden.mapview
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
id: nav_drawer
NavigationDrawerToolbar:
title: labels.NAVIGATION
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.OPERATING_MODE
on_release: app.root.ids.scr_mngr.current = 'operating_mode'
BoxLayout:
orientation: 'vertical'
halign: "center"
Toolbar:
id: toolbar
title: labels.APPLICATION_NAME
md_bg_color: app.theme_cls.primary_color
background_palette: 'Primary'
background_hue: '500'
left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]]
#right_action_items: [['dots-vertical', lambda x: app.root.toggle_nav_drawer()]]
ScreenManager:
id: scr_mngr
Screen:
name: 'operating_mode'
BoxLayout:
orientation: "vertical"
padding: dp(48)
width: dp(100)
spacing: 24
BoxLayout:
orientation: "horizontal"
spacing: 24
BoxLayout:
orientation: "horizontal"
MapView:
id: map_view
zoom: 10
lat: app.latitude
lon: app.longitude
MapMarkerPopup:
id: map_view_marker
lat: app.latitude
lon: app.longitude
You can only make binding when using Properties
, in your case latitude and longitude are not Properties, so they do not generate the change. In this case you must use NumericProperty
:
On the other hand lat
and lon
of MapView
are read-only so the assignment:
MapView:
id: map_view
zoom: 17
lat: app.latitude # <---
lon: app.longitude # <---
set the start value but you can not update it, to update the center of the MapView you must use center_on()
.
main.py
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import NumericProperty
import random
DECIMAL_PRECISION = 2
class MainApp(App):
# map parameters
latitude = NumericProperty(50)
longitude = NumericProperty(3)
def decimal_precision(self, val, precision):
# foo process
return val
# Getting latitude and longitude (at the moment just random stuff
def get_gps_latitude(self):
self.latitude = self.decimal_precision(0.01 * random.random() + 50.6394, DECIMAL_PRECISION)
return self.latitude # rounding
def get_gps_longitude(self):
self.longitude = self.decimal_precision(0.01 * random.random() + 50.6394, DECIMAL_PRECISION)
return self.longitude
def update(self, _):
self.latitude = self.get_gps_latitude()
self.longitude = self.get_gps_longitude()
self.root.center_on(self.latitude, self.longitude)
def on_start(self):
Clock.schedule_interval(self.update, 1)
if __name__ == '__main__':
MainApp().run()
main.kv
#:import MapView kivy.garden.mapview.MapView
# section of main.kv
MapView:
id: map_view
zoom: 17
lat: app.latitude
lon: app.longitude
MapMarker:
id: map_view_marker
lat: app.latitude
lon: app.longitude
Update:
map_view is the root child of a very deep hierarchy, so to access it in a simple way a property is created: map_view: map_view
, and then we access through the self.root.map_view
:
*.kv
NavigationLayout:
id: nav_layout
map_view: map_view # <---
*.py
def update(self, _):
self.latitude = self.get_gps_latitude()
self.longitude = self.get_gps_longitude()
self.root.map_view.center_on(self.latitude, self.longitude)