Im trying to display a mapview on my naviwindow. However, i dont really know how to implement the class MapviewApp to the naviwindow. Any help would be appreciated since im new to kivy !!
.py file
from kivy.garden.mapview import MapView, MapMarker
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
KV = """
WindowManager:
NaviWindow:
<NaviWindow>:
Label:
text:"hi"
"""
class MapViewApp(App):
def build(self):
map = MapView(zoom=18, lat=1.3099, lon=103.7775, double_tap_zoom = True)
marker_1 = MapMarker(lat=1.3099, lon=103.7775)
map.add_marker(marker_1)
return map
class WindowManager(ScreenManager):
pass
class NaviWindow(Screen):
pass
class MyMainApp(App):
def build(self):
return Builder.load_string(KV)
if __name__ == "__main__":
MyMainApp().run()
Related
I am a beginner to Kivy (though not to Python), and I am struggling to get the ids from a kv string into my main code. I have the following, but the 'print' statement tells me that there are no IDs. The application itself runs with no errors.
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.image import Image
kvString = """
MainScreen:
id: maincontainer
cols: 1
thumbnails: thumbnails.__self__
GridLayout:
id: thumbnails
cols: 3
rows: 3
Image:
source: "test.png"
"""
class MainScreen(GridLayout):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
# This prints 0
print("Ids: {}".format(len(self.ids.items())))
class ExampleApp(App):
def build(self):
root = Builder.load_string(kvString)
return root
if __name__ == "__main__":
ExampleApp().run()
When I ran your code, I got a critical warning that there are no screens, and therefore the app will terminate. As soon as I switched MainScreen to a screen, it worked out perfectly. Here is the code:
.py
import kivy
kivy.require('2.1.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.image import Image
sm = ScreenManager()
#I removed some unnecessary code such as the cols, thumbnail, etc.
kvString = """
<MainScreen>
GridLayout:
id: thumbnails
cols: 3
rows: 3
Image:
source: "test.png"
"""
#NEEDS TO INHERIT SCREEN
class MainScreen(Screen):
def __init__(self, **kwargs):
super(MainScreen, self).__init__(**kwargs)
# This now prints 1
print(f'There are {len(self.ids.items())} id(s)')
class ExampleApp(App):
def build(self):
root = Builder.load_string(kvString)
#Adds the screen
sm.add_widget(MainScreen(name='screen'))
return sm
if __name__ == "__main__":
ExampleApp().run()
In this example I'm adding a ListProperty with a default value. If I write a new value in kv
, it's keeping the default value instead of taking the new one. (here text_list: ["Apple","Orange","Banana"] should replace text_list = ListProperty(["WHY DEFAULT PARAMETER IS STILL HERE :("]) but it's not the case.
Is there a way to write value on new property from .kv file ?
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty
KV = '''
BoxLayout:
ChoiceList:
text_list: ["Apple","Orange","Banana"]
'''
class ChoiceList(BoxLayout):
text_list = ListProperty(["WHY DEFAULT PARAMETER IS STILL HERE :("])
def __init__(self, **kwargs):
super().__init__(**kwargs)
for text in self.text_list:
print(text)
class App(MDApp):
def build(self):
self.box = Builder.load_string(KV)
return self.box
App().run()
Thanks to Kivy Discord:
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty
KV = '''
BoxLayout:
ChoiceList:
text_list: ["Apple","Orange","Banana"]
'''
class ChoiceList(BoxLayout):
text_list = ListProperty(["WHY DEFAULT PARAMETER IS STILL HERE :("])
def on_kv_post(self, base_widget):
super().on_kv_post(base_widget)
for text in self.text_list:
print(text)
class App(MDApp):
def build(self):
self.box = Builder.load_string(KV)
return self.box
App().run()
Expected output: ['name', 'age']
Actual output: ['name']
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
KV = '''
BoxLayout:
Label:
id: name
text: "Bob"
'''
class MyApp(App):
def build(self):
box = Builder.load_string(KV)
box.add_widget(Label(text="24", id="age"))
print(list(box.ids.keys()))
return box
if __name__ == "__main__":
MyApp().run()
What can I do to get id of widget that I add with add_widget ?
The ids dictionary is created when a kv file (or string) is parsed. You cannot add an id to the ids dictionary by adding an id to a widget. However, you can manually add an id to the ids. See this related question.
Let's add this to the official kivy Github !
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
KV = '''
ObjBoxLayout:
Label:
id: name
text: "Bob"
'''
class MyApp(App):
def build(self):
box = Builder.load_string(KV)
box.add_widget(Label(text="24"), key="age")
print(list(box.ids.keys()))
return box
class ObjBoxLayout(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def add_widget(self, widget, index=0, canvas=None, key=None):
if key: self.ids[key] = widget
super(ObjBoxLayout, self).add_widget(widget, index, canvas)
if __name__ == "__main__":
MyApp().run()
Firstly, this is a large piece of code so I will try to simplify it for the sake of this question. I have a Kivy Language script which has a root widget, with an action bar and boxlayout. The code's general structure goes a bit like this (I do not believe this is required for answering this question but here it is anyway): Root > MenuBarWidg > BoxLayout > Image + Other buttons/labels....
Now, here is what my widget looks like in kivy (for the boxlayout):
<DisplayPhoto>:
Image:
id: image_display
allow_strech: True
#StringProperty in the class
source: root.image_path
Button:
Inside my python script:
class DisplayPhoto(BoxLayout):
image_path = StringProperty()
def __init__(self, **kwargs):
super(DisplayPhoto, self).__init__(self)
self.image_path = 'reload.png'
#this is called from another class on a button press
def update(self):
self.image_path = 'new_image_path.png'
Upon calling update in the python script, nothing happens. I have tried print(self.image_path) which displays new_image_path.png, but it is also a string - not a kivy object.
I have tried things such as updating the source by calling the id etc but got nowhere with that. Any help is appreciated!
I guess the problem is how you call that update() method.
Please refer to the following code
One way of doing it:
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
Config.set('graphics', 'position', 'custom')
Config.set('graphics', 'left', 0)
Config.set('graphics', 'top', 0)
Builder.load_file('main.kv')
class MainView (BoxLayout):
image_source = StringProperty()
def __init__(self, **kwargs):
super(MainView, self).__init__(**kwargs)
self.image_source = 'pic1.png'
class AnotherClass(BoxLayout):
def change_image(self):
app = App.get_running_app()
app.root.ids['my_image'].source = 'pic2.png'
class ImageChangeApp (App):
def build(self):
return MainView()
if __name__ == '__main__':
ImageChangeApp().run()
main.kv:
<MainView>:
Image:
id: my_image
source: root.image_source
AnotherClass:
<AnotherClass>:
Button:
text: 'Change picture'
on_release: root.change_image()
Another way of doing it is using event dispatcher
main.py:
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
Config.set('graphics', 'position', 'custom')
Config.set('graphics', 'left', 0)
Config.set('graphics', 'top', 0)
Builder.load_file('main.kv')
class MainView (BoxLayout):
pass
class DisplayPhoto(BoxLayout):
image_path = StringProperty()
def __init__(self, **kwargs):
super(DisplayPhoto, self).__init__(**kwargs)
self.image_path = 'pic1.png'
self.register_event_type('on_image_path')
def on_image_path(self, instance, val):
print(instance)
print(val)
self.image_path = val
class AnotherClass(BoxLayout):
def change_image(self):
app = App.get_running_app()
app.root.ids['display_photo'].dispatch('on_image_path', self, 'pic2.png')
class ImageChangeApp (App):
def build(self):
return MainView()
if __name__ == '__main__':
ImageChangeApp().run()
main.kv
<MainView>:
DisplayPhoto:
id: display_photo
AnotherClass:
<DisplayPhoto>:
Image:
source: root.image_path
<AnotherClass>:
Button:
text: 'Change picture'
on_release: root.change_image()
I'm having issues with parsing a data structure to a widget in Kivy, which would then access the structure and be able to show a value on the screen be updated continuously via a clock interval (not sure of a better to do this yet).
I have highlighted the issues in the (non-working) code below:
main.py
from kivy.app import App
from test import TestWidget
class TestApp(App):
def build(self):
testStructTable = {'randomVal1': 1, 'testVal': 2, 'randomVal2': 3}
# Issue here parsing the table like this?
return TestWidget(testStructTable)
if __name__ == '__main__':
TestApp().run()
test.py
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.relativelayout import RelativeLayout
from kivy.properties import NumericProperty
class TestWidget(RelativeLayout):
def __init__(self, testStructTable, **kwargs):
super(TestWidget, self).__init__(**kwargs)
Builder.load_file('test.kv')
sm = ScreenManager()
sm.add_widget(MainScreen(name='MainScreen'))
self.add_widget(sm)
# Error accessing the table
print self.testStructTable
# Have the update_test_val continuously called
#Clock.schedule_interval(MainScreen.update_test_val(testStructTable), 1 / 60)
class MainScreen(Screen):
def __init__(self, **kwargs):
testVal = NumericProperty(0)
def update_test_val(self, testStructTable):
# Get testVal from testStructTable
# Something like:
# self.testVal = testStructTable.testVal + 1 ?
self.testVal = self.testVal + 1
test.kv
<MainScreen>:
FloatLayout:
Label:
text: str(root.testVal)
font_size: 80
My aim is to have the testVal constantly updating on the screen by accessing that data structure, however I am currently unable to achieve this, can you please advise?
In your __init__ method you're passing testStructTable and then you're trying to access self.testStructTable which does not exist untill you explicitly make an assignment:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.relativelayout import RelativeLayout
from kivy.properties import NumericProperty
class TestWidget(RelativeLayout):
def __init__(self, testStructTable, **kwargs):
super(TestWidget, self).__init__(**kwargs)
print(testStructTable)
self.testStructTable = testStructTable
print(self.testStructTable)
class TestApp(App):
def build(self):
testStructTable = {'randomVal1': 1, 'testVal': 2, 'randomVal2': 3}
# Issue here parsing the table like this?
return TestWidget(testStructTable)
if __name__ == '__main__':
TestApp().run()