Reputation: 4350
I created a widget in Kivy language, it has some properties which I'm using some of them inside this widget's python code. Since I'm using "id" keyword inside .kv file, they all have id's. I need to use same ids inside Python code. Here is the workaround:
CcaSwitch:
id: out0_bit3
name: "out0_bit3"
I'm using self.name in place of self.id in python code. How can I achieve same goal without a "duplicate" entry for each widget?
Thanks.
I'm using the "name" variable inside Python code like this:
class CcaSwitch(BoxLayout):
name = StringProperty()
def __init__(self, *args, **kwargs):
# ...
Clock.schedule_interval(self.refresh, 5)
def refresh(self, dt):
self.comm.publish(get_bool_status(self.name), self.routing_key)
So, I need a string, which identifies this widget instance itself, in a DRY way.
I would like to achieve something like that:
In .kv file:
CcaSwitch:
id: out0_bit3
In Python I'd like to use it like:
class CcaSwitch(BoxLayout):
def __init__(self, *args, **kwargs):
# ...
self.name = self.id.__name__
Clock.schedule_interval(self.refresh, 5)
def refresh(self, dt):
self.comm.publish(get_bool_status(self.name), self.routing_key)
Upvotes: 3
Views: 12273
Reputation: 1347
You don't say why you need to use these ids in python. But you can access a widget that has an id through its parent's ids dictionary (this is a special dictionary that can be queried using dot notation, e.g. if the dict variable is x, and it has element 'apple' in it, you can get its value with x.apple).
So for your example, if you have in .kv:
<ExampleWidget>:
CcaSwitch:
id: out0_bit3
state: 'ON'
you can .py:
w = ExampleWidget()
print(w.ids.out0_bit3.state)
w.ids.out0_bit3 in this case returns a reference to that CcaSwitch widget.
EDIT
As I said in the comments, there's only one way to get the id value as a string - using its parent's ids dictionary. So the following will only work if the CcaSwitch widget has a parent widget (i.e. it's not the main widget):
class CcaSwitch(Widget):
name = ''
def __init__(self, *args, **kwargs):
super(CcaSwitch, self).__init__(**kwargs)
Clock.schedule_once(self.load_name)
Clock.schedule_interval(self.refresh, 5)
def load_name(self, *l):
for id_str, widget in self.parent.ids.iteritems():
if widget.__self__ is self:
self.name = id_str
return
def refresh(self, dt):
self.comm.publish(get_bool_status(self.name), self.routing_key)
What it does, is go through the ids dict of its parent, and extracts its id string. You cannot call self.load_name directly from init, because it might not have the parent yet etc. So we schedule it for the next frame.
If the widget has no parent, you're out of luck and you either have to do like you did before, or if the name doesn't have to be human readable or the same across different runs, you can in init set self.name = str(self).
Upvotes: 2