Reputation: 371
In my kivy/python program I add a row at the press of a button. In the init function of my row I create variables which I need in the kivy file of the row. It doesn't work, I guess because first the row is being build, and only then is the init funtion called. Is there a way to change the order? Thanks in advance!
I add my row like this:
self.ids.container.add_widget(Row(link))
Some code to clarify:
main.py
class AllitemsScreen(Screen):
def AddItem(self, link):
row = Row(link)
self.ids.container.add_widget(row)
class Row(BoxLayout):
def __init__(self, link, **kwargs):
super(Row, self).__init__(**kwargs)
item_dict[self] = Item(link)
self.image_source = item_dict[self].image
self.itemname = item_dict[self].name
kiv file:
Row>:
orientation: "horizontal"
BoxLayout:
orientation: "vertical"
font_name:"Nunito"
Label:
text: root.itemname
font_name:"Nunito"
Button:
id: root.count
text: "delete item"
on_press: root.delete_item()
Image:
source: root.image_source
width: 100
So when AddItem is called, a new row is created. I get the following error:
Traceback (most recent call last):
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 124, in <module>
source: root.image_source
File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__
AttributeError: 'Row' object has no attribute 'image_source'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 692, in _apply_rule
rctx['ids'])
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 254, in create_handler
cause=tb)
kivy.lang.builder.BuilderException: Parser: File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 124:
...
122: on_press: root.delete_item()
123: Image:
>> 124: source: root.image_source
125: width: 100
126:
...
AttributeError: 'Row' object has no attribute 'image_source'
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 124, in <module>
source: root.image_source
File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "main.py", line 95, in <module>
MyApp().run()
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\app.py", line 855, in run
runTouchApp()
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\base.py", line 504, in runTouchApp
EventLoop.window.mainloop()
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\core\window\window_sdl2.py", line 747, in mainloop
self._mainloop()
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\core\window\window_sdl2.py", line 479, in _mainloop
EventLoop.idle()
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\base.py", line 342, in idle
self.dispatch_input()
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\base.py", line 327, in dispatch_input
post_dispatch_input(*pop(0))
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\base.py", line 233, in post_dispatch_input
listener.dispatch('on_motion', etype, me)
File "kivy\_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\core\window\__init__.py", line 1402, in on_motion
self.dispatch('on_touch_down', me)
File "kivy\_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\core\window\__init__.py", line 1418, in on_touch_down
if w.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\screenmanager.py", line 1191, in on_touch_down
return super(ScreenManager, self).on_touch_down(touch)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\widget.py", line 549, in on_touch_down
if child.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\relativelayout.py", line 288, in on_touch_down
ret = super(RelativeLayout, self).on_touch_down(touch)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\widget.py", line 549, in on_touch_down
if child.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\widget.py", line 549, in on_touch_down
if child.dispatch('on_touch_down', touch):
File "kivy\_event.pyx", line 707, in kivy._event.EventDispatcher.dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\behaviors\button.py", line 151, in on_touch_down
self.dispatch('on_press')
File "kivy\_event.pyx", line 703, in kivy._event.EventDispatcher.dispatch
File "kivy\_event.pyx", line 1214, in kivy._event.EventObservers.dispatch
File "kivy\_event.pyx", line 1098, in kivy._event.EventObservers._dispatch
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 64, in custom_callback
exec(__kvlang__.co_value, idmap)
File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 49, in <module>
on_press: root.manager.screens[1].AddItem(input.text), app.AddImage(), root.manager.screens[1].AddRow(), app.ShowPopup()
File "main.py", line 47, in AddItem
row = Row(link)
File "main.py", line 57, in __init__
super(Row, self).__init__(**kwargs)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\boxlayout.py", line 145, in __init__
super(BoxLayout, self).__init__(**kwargs)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\layout.py", line 76, in __init__
super(Layout, self).__init__(**kwargs)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\widget.py", line 361, in __init__
rule_children=rule_children)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\uix\widget.py", line 469, in apply_class_lang_rules
rule_children=rule_children)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 538, in apply
rule_children=rule_children)
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 707, in _apply_rule
e), cause=tb)
kivy.lang.builder.BuilderException: Parser: File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 124:
...
122: on_press: root.delete_item()
123: Image:
>> 124: source: root.image_source
125: width: 100
126:
...
BuilderException: Parser: File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 124:
...
122: on_press: root.delete_item()
123: Image:
>> 124: source: root.image_source
125: width: 100
126:
...
AttributeError: 'Row' object has no attribute 'image_source'
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 249, in create_handler
return eval(value, idmap), bound_list
File "C:\Users\caspe\Documents\Casper app\myapp.kv", line 124, in <module>
source: root.image_source
File "kivy\weakproxy.pyx", line 32, in kivy.weakproxy.WeakProxy.__getattr__
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 692, in _apply_rule
rctx['ids'])
File "C:\Users\caspe\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 254, in create_handler
cause=tb)
Upvotes: 0
Views: 1939
Reputation: 7384
The kv language file is processed when you call super(Row, self).__init__(**kwargs)
by the Widget.__init__
function. While you could just do your initialisation before calling super
it will not enable all of kivys features esp. changes of attributes will not propagate properly. The kivy way is to define your properties as kivy properties, in your code this would probably be something like:
class Row(BoxLayout):
itemname = StringProperty()
image_source = StringProperty()
...
Otherwise changes to itemname or image_source will not change the text of the label. Because kivy properties have default values, it doesn't throw an error anymore if you first call super
and then initialize your values, although first initializing is probably more efficient.
Upvotes: 4
Reputation: 1552
It looks like the superclass' __init__
method (BoxLayout.__init__
) is trying to access the Row.image_source
attribute, which does not exist at the time you call it.
To fix that, just move the super
call so BoxLayout.__init__
is called after you declared all attributes:
class Row(BoxLayout):
def __init__(self, link, **kwargs):
item_dict[self] = Item(link)
self.image_source = item_dict[self].image
self.itemname = item_dict[self].name
super(Row, self).__init__(**kwargs)
Upvotes: 3