Kivy:通过点击第一个内容中的按钮更改第一个手风琴项内容
我刚开始学习Kivy,正在做一个手风琴式的界面,里面的项目数量是动态变化的。每个项目可以有两种不同的内容。你可以通过点击第一个内容里的一个按钮来切换到另一个内容。下面是一个简单的例子:
from kivy.lang import Builder
from kivy.base import runTouchApp
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.accordion import Accordion, AccordionItem
Builder.load_string('''
<MyAccordion>:
orientation: 'vertical'
<MyAccordionItem>:
FirstContent:
<FirstContent@GridLayout>:
cols: 1
BoxLayout:
ClickMeButton:
text: 'Click me'
on_press: self.change_content()
<SecondContent>:
cols: 1
GridLayout:
rows: 1
Label:
text: 'You clicked!'
''')
class MyAccordionItem(AccordionItem):
pass
class MyAccordion(Accordion):
def __init__(self, **kwargs):
super(MyAccordion, self).__init__(**kwargs)
for i in xrange(5):
accordionitem = MyAccordionItem(title=str(i))
self.add_widget(accordionitem)
class SecondContent(GridLayout):
pass
class ClickMeButton(Button):
def change_content(self):
# how to reference the accordion item
# this button belongs to?
'''
accordionitem = None
accordionitem.clear_widgets()
accordionitem.add_widget(SecondContent())
'''
runTouchApp(MyAccordion())
我遇到的问题是,我不知道怎么找到按钮所在的手风琴项目。我试着通过父级链来找到,但最终只到达了FirstContent对象,而它的父级似乎是一个盒子布局,这让我很困惑(为什么会这样呢?)。而且,依赖父级链并不是个好主意,因为如果内容结构发生变化,这种方法就容易出错。
我注意到Kivy 1.8.1会有一个walk()方法,但我猜这个方法也是通过父级向上遍历树形结构,所以可能也不太好用?
有没有什么好的想法呢?
3 个回答
只需要给你的手风琴项(AccordionItem)一个ID。如果你想让除了当前显示的那个(active_accordion_item)之外,所有的手风琴项都收起,可以在你的按钮里这样写:
on_release: active_accordion.collapse = False
- 这样,kivy会把其他所有的手风琴项都设置为展开状态(True)。
这是我为 ClickMeButton 类想出的解决方案:
class ClickMeButton(Button):
def change_content(self):
accordionitem = self.find_anchestor(self.parent, 'MyAccordionItem')
accordionitem.remove_widget(accordionitem.ids['_first_content'])
accordionitem.add_widget(SecondContent())
def find_anchestor(self, widget, classname):
if widget:
if widget.__class__.__name__ == classname:
return widget
else:
return self.find_anchestor(widget.parent, classname)
在 kivy 语言字符串中,我还需要在 FirstContent:
下面添加 id: _first_content
,这样我就能给这个实例一个可以引用的 ID。
我创建了一个递归函数 find_anchestor
来寻找正确的父级。Paarth batra 告诉我,我可以通过父级链找到正确的祖先。但是当布局发生变化时,我不想手动添加或删除父级,所以这个递归函数会一直往上找,直到找到正确的父级。你只需要给它一个起始的组件和你想找的组件类的名字,它就能工作。
一旦找到正确的父组件,我需要移除第一个内容并添加第二个内容。因为第一个内容不是 accordionitem 组件的直接子级,所以我需要给它一个 ID,并通过 ids
属性来引用它。
最后,我只需添加第二个内容。
希望这能帮助将来有类似问题的人。感谢 Paarth batra 的想法!
把change_button的代码改成下面这样。这是一种你想要的引用方式。可能还有其他方法可以做到这一点,但希望这能对你有所帮助 :)
我们怎么做呢?
第一个父级是按钮在FirstContent类中的盒子布局... 你在上面的kv代码中指定了BoxLayout,位于ClickMeButton的上方。
第二个父级,也就是上面的父级,是FirstContent。
依此类推...
class ClickMeButton(Button):
def change_content(self):
print "I am clicked . I am button "
print self.parent.parent.parent.parent.parent.parent.title
#1kivy.uix.boxlayout.BoxLayout object at 0x06ED9228 -- boxlayout in ClickMeButton
#2<kivy.factory.FirstContent object at 0x06FCA1F0> --Parent above
#3<kivy.uix.boxlayout.BoxLayout object at 0x06F591B8> -- Parent of firstcontent class as a boxlayout
#4<kivy.uix.stencilview.StencilView object at 0x06F3B0A0>
#5<kivy.uix.boxlayout.BoxLayout object at 0x06FB7068>
#6<__main__.MyAccordionItem object at 0x06ED8030>