The problem has to do with initialization order. The ids dict is populated when the kv code is processed, this is after the __init__() for the class has run. To address this use the on_kv_post() method.
https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=on_kv_post#kivy.uix.widget.Widget
The on_kv_post() event will fire after the kv code for the widget has been processed, so the ids will be valid.
--
You received this message because you are subscribed to the Google Groups "Kivy users support" group.
To unsubscribe from this group and stop receiving emails from it, send an email to kivy-users+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/d8b41e18-4b6b-4f02-b7eb-ef24a87fac60n%40googlegroups.com.
The problem has to do with initialization order. The ids dict is populated when the kv code is processed, this is after the __init__() for the class has run. To address this use the on_kv_post() method.
https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=on_kv_post#kivy.uix.widget.Widget
The above link says: "Fired after all the kv rules associated with the widget and all other widgets that are in any of those rules have had all their kv rules applied. base_widget is the base-most widget whose instantiation triggered the kv rules (i.e. the widget instantiated from Python, e.g. MyWidget())."
The on_kv_post() event will fire after the kv code for the widget has been processed, so the ids will be valid.
Trying to understand:
The self.ids dict is part of the class.
When creating widgets in __init__ we have to tell the dict the name of what we just created.
If we use the kv land the processor of the kv lang works AFTER init and hadles both the creation of the widget and the inclusion of the id in the class.
Lots of good questions here.
The ids dictionary is a member of the Widget class. It is populated when kv is process. Widgets do NOT have an id attribute. I believe this is to reduce confusion and errors.
When the kv is processed the ids dict is used to associate a widget instance with an id. An ids is only populated for each kivy “rule”. This allows you to use the ids to navigate the widget tree.
In python when you are instancing a widget, you do not know where that widget sits in the hierarchy – so you do not know which ids dict to write the id into.
Read: https://kivy.org/doc/stable/api-kivy.uix.widget.html?highlight=ids#kivy.uix.widget.Widget.ids
You could hack the ids dict, and update it with additional information. (I would NOT recommend this). Or create a separate dictionary that associates an id with a widget to ease addressing in some limited cases. I’ll add I have never felt the need to do this.
I hope this was helpful. Let me know what you think.
Here is an example that adds content to the dict from python. Some of the danger with this approach would be knowing which ids dict to update, and overwriting an existing entry.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty
kv = """
RootBoxLayout:
orientation: 'vertical'
Button:
id: button_1
text: 'Regular Button'
"""
class RootBoxLayout(BoxLayout):
def on_kv_post(self, base_widget):
print(f'ids created by kv: {self.ids}')
def update_ids(self):
# I would NOT recommend this - FOR EDUCATIONAL PURPOSES ONLY
for b in self.children:
if hasattr(b, 'id'):
self.ids.update({b.id: b})
print(f'ids after the update {self.ids}')
class IdButton(Button):
id = StringProperty('default id') # used to store the id
class BindButtonApp(App):
def build(self):
return Builder.load_string(kv)
def on_start(self):
button = IdButton(text='fake_id_0', id='fake_id_0')
self.root.add_widget(button)
button = IdButton(text='fake_id_1', id='fake_id_1')
self.root.add_widget(button)
self.root.update_ids()
BindButtonApp().run()
To view this discussion on the web visit https://groups.google.com/d/msgid/kivy-users/70c93bc4-edd2-424d-9ab2-e15db623bdc5n%40googlegroups.com.