'Attribute error when using Kivy Screen Manager and self.ids
from kivymd.app import MDApp
from kivy.config import Config
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
from kivy.core.window import Window
Window.minimum_width, Window.minimum_height = (1200, 700)
Window.maximize()
from kivy.lang import Builder
import requests
from geopy.geocoders import Nominatim
import geopy
from kivy.uix.widget import Widget
from kivymd.uix.menu import MDDropdownMenu
from datetime import datetime
import pytz
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
class WindowManager(ScreenManager):
pass
class Weather(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_interval(self.update_time, 60)
city = 'Tokyo'
self.get_weather(city)
def search_weather(self):
self.get_weather(self.ids.city_name.text)
def get_weather(self, city_name):
self.ids.location.text = 'City : '+city_name
def update_time(self, *args):
print(datetime.now())
class Login(Screen):
username = ObjectProperty(None)
password = ObjectProperty(None)
message = StringProperty()
def action(self):
print(f'logged in as {username}')
class App(MDApp):
def build(self):
return kv = Builder.load_file('destest.kv')
if __name__ == '__main__':
App().run()
This is the python code
And the following is the code in the destest.kv file
#: import utils kivy.utils
WindowManager:
Login:
Weather:
<Login>
username: username
password: password
name: 'logsin'
GridLayout:
cols:2
padding: 0, 20, 0 , 0
spacing: 5
TextInput:
id : username
multiline: False
write_tab : False
background_color: utils.get_color_from_hex('#B8F9EE')
size_hint_x: None
width : (root.width/3)*1.5
foreground_color: utils.get_color_from_hex('#1b3446') # changes colour of text
font_size: 32
hint_text : 'Username'
TextInput:
id : password
multiline: False
write_tab : False
background_color: utils.get_color_from_hex('#B8F9EE')
size_hint_x: None
width : (root.width/3)*1.5
foreground_color: utils.get_color_from_hex('#1b3446') # changes colour of text
font_size: 25
hint_text: 'Password'
Button:
text : 'Login'
font_size : 40
on_press: root.action()
size_hint_y : None
height : 60
size_hint_x : None
width : 180
background_normal : ''
background_color: 0, 0, 0, 0
canvas.before:
Color:
rgba: utils.get_color_from_hex('#0CD408')
RoundedRectangle:
radius : [5]
size: self.size
pos: self.pos
Button:
text : 'Go to weather'
font_size : 40
on_release: app.root.current = 'weathers'
size_hint_y : None
height : 60
size_hint_x : None
width : 180
background_normal : ''
background_color: 0, 0, 0, 0
canvas.before:
Color:
rgba: utils.get_color_from_hex('#0CD408')
RoundedRectangle:
radius : [5]
size: self.size
pos: self.pos
<Weather>:
name: 'weathers'
MDFloatLayout:
spacing : 30, 10
md_bg_color : 1,1,1,1
size: root.size
pos_hint: {'x': 0, 'y': 0}
MDLabel:
id : location
text: "City"
pos_hint: {"center_x": .5,"center_y": .89}
halign : "center"
font_size: 60
MDFloatLayout:
size_hint_y : .3
canvas:
Color:
rgb: rgba(148, 117, 255, 255)
RoundedRectangle:
size: self.size
pos: self.pos
radius : [10, 10, 0, 0]
MDFloatLayout:
pos_hint: {"center_x": 0.5,"center_y": .71}
size_hint: .9, .32
canvas:
Color:
rgb: rgba(131, 69, 255, 255)
RoundedRectangle:
size: self.size
pos: self.pos
radius : [6]
TextInput:
id: city_name
hint_text : "Enter City Name"
size_hint: 1, None
height: self.minimum_height
pos_hint: {"center_x": 0.5,"center_y": .5}
multiline: False
font_name : "fonts/Exo/Exo2-RegularCondensed.otf"
font_size : 30
hint_text_color : 1, 1, 1, 1
foreground_color: 1, 1, 1, 1
background_color: 1, 1, 1, 0
padding : 15
cursor_color : 1, 1, 1, 1
cursor_width : 3
Button:
id: button
text : "Get Weather"
font_name : "fonts/Exo/Exo2-SemiBoldCondensed.otf"
font_size : 30
size_hint : .9, .32
pos_hint :{"center_x": 0.5,"center_y": .29}
background_color : 1, 1, 1, 0
color: rgba(148, 117, 255, 255)
on_release: root.search_weather()
on_press: root.change_bg()
canvas.before:
Color:
rgba: 1, 1, 1, 1
RoundedRectangle:
size: self.size
pos: self.pos
radius : [6]
Button:
text : 'switch to login'
pos_hint : {"center_x": 0.85,"center_y": .9}
font_size : 10
on_press: app.root.current = 'logsin'
size_hint_y : None
height : 20
size_hint_x : None
width : 60
background_normal : ''
background_color: 0, 0, 0, 0
canvas.before:
Color:
rgba: utils.get_color_from_hex('#0CD408')
RoundedRectangle:
radius : [5]
size: self.size
pos: self.pos
However when I run the code I get the following error:
Traceback (most recent call last):
File "kivy\properties.pyx", line 861, in kivy.properties.ObservableDict.__getattr__
KeyError: 'location'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\KERAI\Documents\Darsh_work\Python stuff\imagine_cup\altlog.py", line 42, in <module>
kv = Builder.load_file('destest.kv')
File "C:\Users\KERAI\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 306, in load_file
return self.load_string(data, **kwargs)
File "C:\Users\KERAI\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 408, in load_string
File "C:\Users\KERAI\AppData\Local\Programs\Python\Python39\lib\site-packages\kivy\lang\builder.py", line 659, in _apply_rule
child = cls(__no_builder=True)
File "C:\Users\KERAI\Documents\Darsh_work\Python stuff\imagine_cup\altlog.py", line 27, in __init__
self.get_weather(city)
File "C:\Users\KERAI\Documents\Darsh_work\Python stuff\imagine_cup\altlog.py", line 31, in get_weather
self.ids.location.text = 'City : '+city_name
File "kivy\properties.pyx", line 864, in kivy.properties.ObservableDict.__getattr__
AttributeError: 'super' object has no attribute '__getattr__'
I am aware that the error is because using screen manager the value of self.ids changes and that you have to access the ids another way, I would really appreciate if someone could help me with this program and I made it as simple as I could since the original file was much to long.
Solution 1:[1]
I found a fix:
from kivy.app import App
plus
class Weather(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_interval(self.update_time, 60)
Clock.schedule_once(after_init)
def after_init(self, *largs):
app = App.get_running_app()
self.ids = app.root.get_screen('weathers').ids
city = 'Tokyo'
self.get_weather(city)
def search_weather(self):
self.get_weather(self.ids.city_name.text)
def get_weather(self, city_name):
self.ids.location.text = 'City : '+city_name
def update_time(self, *args):
print(datetime.now())
plus
class AnotherName(MDApp):
def build(self):
self.root = Builder.load_file('destest.kv')
if __name__ == '__main__':
AnotherName().run()
Do let me know if there is another simpler method.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | DrHakeshi |
