Reputation: 312
My question is the title. It is probably the same as this one, but I am not happy with the answer there or with my working minimal example below. That is because if I were to move the child I am making the call from one "nested layer" up or down (e.g. in my example: put the "special button" inside another Layout of the parent BoxLayout
) the callback function would not work anymore.
How to do this properly (and the intended kivy way)?
Minimal Example:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
Builder.load_string('''
<RootWidget>:
button1: b1
button2: b2
BoxLayout:
orientation: 'horizontal'
size: root.size
Button:
id: b1
text: 'I am the normal one'
SpecialButton:
id: b2
text: 'I am the special one'
<SpecialButton>:
on_release: root.clickityclick()
''')
class RootWidget(Widget):
button1 = ObjectProperty(None)
button2 = ObjectProperty(None)
class SpecialButton(Button):
def clickityclick(self):
self.parent.parent.button1.disabled = True ### <----- How to do this properly?
class MinimalExampleApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MinimalExampleApp().run()
Upvotes: 0
Views: 1283
Reputation: 312
@inclement's comment contains the answer to my question (specifically: 2nd-last example from his article ("Option 1"))
Option 1: Introduce a kivy-property in the widget from which you want to induce the change. In the kv rules set a property of the receiving widget to the one you introduced in the inducing widget (via the kv-id of the iducing widget). This way you could either have the receiving widget track a property directly or trigger a function when the property changes.
Option 2: Use App.get_running_app().root.ids ("in Python") to talk to the receiving widget directly.
Example for Option 1:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.properties import ObjectProperty, BooleanProperty
Builder.load_string('''
<RootWidget>:
button1: b1
button2: b2
BoxLayout:
orientation: 'horizontal'
size: root.size
Button:
id: b1
text: 'I am the normal one'
disabled: b2.switch # <----- track the property of the other ('special') button
SpecialButton:
id: b2
text: 'I am the special one'
<SpecialButton>:
on_release: root.clickityclick()
''')
class RootWidget(Widget):
button1 = ObjectProperty(None)
button2 = ObjectProperty(None)
class SpecialButton(Button):
switch = BooleanProperty(False) # <----- introduce a property which is then tracked by the other ('normal') button
def clickityclick(self):
self.switch = not self.switch # <----- only change your own property
class MinimalExampleApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MinimalExampleApp().run()
Example for Option 2:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.properties import ObjectProperty
Builder.load_string('''
<RootWidget>:
button1: b1
button2: b2
BoxLayout:
orientation: 'horizontal'
size: root.size
Button:
id: b1
text: 'I am the normal one'
SpecialButton:
id: b2
text: 'I am the special one'
<SpecialButton>:
on_release: root.clickityclick()
''')
class RootWidget(Widget):
button1 = ObjectProperty(None)
button2 = ObjectProperty(None)
class SpecialButton(Button):
def clickityclick(self):
App.get_running_app().root.ids.b1.disabled = \
not App.get_running_app().root.ids.b1.disabled # <---- directly access the other ('normal') button
class MinimalExampleApp(App):
def build(self):
return RootWidget()
if __name__ == '__main__':
MinimalExampleApp().run()
Upvotes: 1