引用 Kivy 中动态创建的小部件的 id

Posted

技术标签:

【中文标题】引用 Kivy 中动态创建的小部件的 id【英文标题】:Referencing id of dynamically created widget in Kivy 【发布时间】:2016-06-22 16:34:10 【问题描述】:

我无法通过 root.ids.created_in_kv.created_in_py 在绑定到按钮的方法中访问动态创建的子项。当我检查 root.ids.created_in_kv.ids 字典时它是空的,但是 root.ids.created_in_kv.children

中有孩子

我想要实现的是创建一个充当多选器的弹出窗口。它将接受可能的选择并动态创建标签-复选框对并将其添加到弹出内容中,并且在“应用”按钮上它将仅返回选择的列表(str())。

我无法在 kv 中构建包含多个小部件的弹出窗口,但以下工作(建议使其“更好”而不是受欢迎):

kv代码:

<SelectorPopup>:
    title: 'empty'
    BoxLayout:
        id: inside
        orientation: 'vertical'
        BoxLayout:
            id: options
        BoxLayout:
            id: buttons
            orientation: 'vertical'
            Button:
                text: 'Apply'
                on_release: root.return_selected()
            Button:
                text: 'Cancel'
                on_release: root.dismiss()

<LabeledCheckbox@BoxLayout>:
    id: entity
    CheckBox:
        id: choice
    Label:
        text: root.id

我正在创建标签-复选框对(打包在 GridLayout 中)并将其放入 options BoxLayout 的 python 代码:

class SelectorPopup(Popup):
    def return_selected(self):
        selected=[]
        a = self.ids.inside.options.choices.ids # dict is empty
        for item in a.keys():
             selected.append(item) if a[item].ids.choice.value #add if checkbox checked
        return selected

class MultiselectForm(BoxLayout):
    data = ListProperty([])
    def __init__(self, **kwargs):
        super(MultiselectForm, self).__init__(**kwargs)
        self.prompt = SelectorPopup()

    def apply_data(self):
        # write data to self.data
        pass

    def create_popup(self):
        try:
            # some code to check if choices are already created
            check = self.prompt.ids.inside.options.choices.id
        except AttributeError:
            possible = ['choice1','choice2','choice3'] #query db for possible instances
            choices = GridLayout(id='choices',cols=2)
            for entity in possible:
                choice = Factory.LabeledCheckbox(id=entity)
                choices.add_widget(choice)
            self.prompt.ids.options.add_widget(choices)
        self.prompt.open()

问题:

1) 如何使 return_selected 方法起作用?

2) 有没有办法更好地构建弹出窗口?我无法将小部件树添加到 content ObjectProperty 中,例如:

<MyPopup>:
    content:
        BoxLayout:
            Label:
                text: 'aaa'
            Label:
                text: 'bbb'

【问题讨论】:

【参考方案1】:

您似乎对 id 的工作方式有些混淆。文档中对它们进行了一些讨论:https://kivy.org/docs/api-kivy.lang.html

基本上,它们只是.kv 中的特殊标记,可让您引用已定义的小部件。它们被收集并放置在定义它们的规则的根小部件上的ids 字典中。这意味着它们不像您引用它们那样嵌套,它们都在根小部件上(SelectorPopupLabeledCheckbox

所以而不是(来自SelectorPopup):

self.ids.inside.options.choices

你会:

self.ids.choices

这也意味着动态添加的小部件不会出现在ids 字典中,但它们实际上并不需要。由于您是在代码中创建它们,因此您可以自己保存对它们的引用(这对于 .kv 来说更难做到)。

话虽如此,使用ListView 显示您的项目列表可能会容易得多。

【讨论】:

大开眼界,我一定误读了关于 ids' 没有嵌套的事情。在 python 代码中保存引用是什么意思?您能告诉我如何将“内部”BoxLayout 绑定到 kv 中的弹出内容吗? 我的意思是,如果您在 python 代码中创建小部件,您可以将对该小部件的引用保存在列表或字典或代码中的某些数据结构中,以便以后引用。我不确定您的第二个问题是什么意思,您不是只是在显示之前将标签(字符串)列表添加到弹出窗口吗? 我的意思是我不能像我在最后的问题中输入的那样做 2)。文档说内容属性只需要一个小部件,所以我试图在 kv 中做到这一点。我知道如何通过python来做,但是你能告诉我如何通过kv来做吗? 去掉kv中的“content:”,把BoxLayout放在Popup里面就好象是一个容器一样。

以上是关于引用 Kivy 中动态创建的小部件的 id的主要内容,如果未能解决你的问题,请参考以下文章

如果未动态添加,如何正确删除Kivy中的小部件

Kivy中的动态网格,每个网格元素包含多个小部件

Kivy - 通过引用根属性动态添加按钮

Gridstack 动态创建的小部件不拖动

如何删除 kivy 中的小部件?

用python添加的kivy中的引用对象