如何在不使用 `self.parent.parent 的情况下更改另一个 Kivy Widget 的 child 的属性。 ...`?
How to change properties of another Kivy Widget's child without using `self.parent.parent. ...`?
我的问题是标题。它可能与 相同,但我对那里的答案或下面的最小工作示例不满意。那是因为如果我要移动 child 我是从一个“嵌套层”向上或向下进行调用(例如,在我的示例中:将“特殊按钮”放在 parent 的另一个布局中BoxLayout
) 回调函数将不再起作用。
如何正确地做到这一点(以及预期的 kivy 方式)?
最小示例:
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()
@inclement 的评论包含我问题的答案(具体来说:来自 his article(“选项 1”)的倒数第二个示例)
选项 1:在要从中引发更改的小部件中引入 kivy-property。在 kv 规则中,将接收小部件的 属性 设置为您在诱导小部件中引入的那个(通过诱导小部件的 kv-id)。通过这种方式,您可以让接收小部件直接跟踪 属性 或在 属性 更改时触发函数。
选项 2:使用 App.get_running_app()。root.ids(“在 Python”中)直接与接收小部件对话。
选项 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()
选项 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()
我的问题是标题。它可能与 BoxLayout
) 回调函数将不再起作用。
如何正确地做到这一点(以及预期的 kivy 方式)?
最小示例:
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()
@inclement 的评论包含我问题的答案(具体来说:来自 his article(“选项 1”)的倒数第二个示例)
选项 1:在要从中引发更改的小部件中引入 kivy-property。在 kv 规则中,将接收小部件的 属性 设置为您在诱导小部件中引入的那个(通过诱导小部件的 kv-id)。通过这种方式,您可以让接收小部件直接跟踪 属性 或在 属性 更改时触发函数。
选项 2:使用 App.get_running_app()。root.ids(“在 Python”中)直接与接收小部件对话。
选项 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()
选项 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()