Reputation: 73
How can I access the conditions value that is located inside my CurrentWeather
widget from Python in my AddLocationForm
? I want to edit the conditions value from my AddLocationForm
instead of doing it in CurrentWeather
. This is my code, so far:
Python:
from kivy.network.urlrequest import UrlRequest
import json
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
from kivy.uix.listview import ListItemButton
from kivy.factory import Factory
Window.clearcolor = (0.45, 0.3, 1, 0.5)
class AddLocationForm(BoxLayout):
search_input = ObjectProperty()
search_results = ObjectProperty()
currentWeather = ObjectProperty()
def search_location(self):
search_template = "http://api.openweathermap.org/data/2.5/weather?q={}&appid=f8020ca79e2de4c1dd5a125c3f22fa18"
search_url = search_template.format(self.search_input.text)
request = UrlRequest(search_url, self.found_location)
def found_location(self, request, data):
data = json.loads(data.decode()) if not isinstance(data, dict) else data
weather = "%s" %(data["weather"][0]["description"])
root.WeatherRoot.CurrentWeather.conditions = weather #Problem is here
class LocationButton(ListItemButton):
pass
class WeatherApp(App):
def build(self):
global root
root = self.root
if __name__ == '__main__':
WeatherApp().run()
Kv:
#: import ListItemButton kivy.uix.listview.ListItemButton
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import main main
WeatherRoot:
<WeatherRoot>:
AddLocationForm
<AddLocationForm>:
orientation: "vertical"
search_input: search_box
search_results: search_results_list
BoxLayout:
height: "40dp"
size_hint_y: None
TextInput:
id: search_box
size_hint_x: 50
multiline: False
Button:
text: "Search"
size_hint_x: 25
on_press: root.search_location()
background_color: (1, 0.5, 0.656, 1)
<CurrentWeather@BoxLayout>:
id: current_weather
currentWeather: current_weather
location: ""
conditions: ""
temp: None
temp_min: None
temp_max: None
orientation: "vertical"
Label:
text: root.location
pos_hint: {'x': 0.435, "y": 1}
font_size: '40dp'
size_hint_y: None
size_hint_x: None
BoxLayout:
orientation: "horizontal"
Label:
id: curCon
text: root.conditions
Upvotes: 1
Views: 2121
Reputation: 12169
Tree:
WeatherRoot: # root widget
<WeatherRoot>: # root widget class
AddLocationForm # root widget's child
Therefore you'll first access your App
's instance with app
. The instance after the build method has a root
property, which is just an instance of the root widget stored. That's why global root
is useless in larger code because of e.g. collisions, confusion with some other name, etc while accessible easier in a pretty way.
To access a class dynamically created in kv from python or kv you need to use the widget tree (to get to an already existing instance):
app.root.children[0]...
or Factory
to create an instance of the widget e.g. if you'd like to create a new one after some condition is evaluated.
But!
You've misunderstood how the dynamic classes work in kv - the <Name@Widget>:
is just a declaration, not an instance. Like a template. To actually work with it you have to put it somewhere, for example:
python:
cw = Factory.CurrentWeather()
somewhere.add_widget(cw)
kv:
WeatherRoot:
CurrentWeather: # here
<WeatherRoot>:
AddLocationForm:
CurrentWeather: # or here
If you choose to add it in python, you can easily use some variable to store an instance and still be able to access it later through widget tree. On the other hand, when added in kv, you don't have an access to __init__
and you can't really store an instance into a variable without sillyish hacks like this:
#:import Factory kivy.factory.Factory
<Blob@Button>:
BoxLayout:
Button:
on_release: self.new = Factory.Blob(); self.parent.add_widget(self.new)
Therefore to access it you have to first create an instance of it and either store the instance, or go trough the widget tree.
Upvotes: 1