Caspertijmen1
Caspertijmen1

Reputation: 371

Kivy: How to first initialize the class and then build it?

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

Answers (2)

syntonym
syntonym

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

Dion
Dion

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

Related Questions