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

2022-01-15 00:00:00 python kivy properties popup

问题描述

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

I am having trouble accessing dynamically created children via root.ids.created_in_kv.created_in_py in method bound to button. When I check root.ids.created_in_kv.ids dictionary it is empty, but there are children in root.ids.created_in_kv.children

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

What I'm trying to achieve is to create a popup that will act as multiselector. It will accept possible choices and dynamically create label-checkbox pair and add it to popup contents, and on 'Apply' button it will return only chosen list(str()).

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

I can't constuct popup with multiple widgets in it in kv, but the following works (suggestions to make it 'nicer' more than welcome):

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 代码:

And the python code I'm creating the label-checkbox pairs (packaged in GridLayout) and putting it into options BoxLayout:

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 方法起作用?

1) Howto make return_selected method work?

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

2) Is there a way to construct popup more nicely? I can't add widget tree into content ObjectProperty like:

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


解决方案

看起来你对 ids 的工作方式有点混淆.文档中对它们进行了一些讨论:https://kivy.org/docs/api-kivy.lang.html

It looks like you're a little mixed up on how ids work. They are talked about a little bit in the docs: https://kivy.org/docs/api-kivy.lang.html

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

Basically, they are just special tokens in .kv that lets you reference defined widgets. They are collected and placed in the ids dictionary on the root widget of the rule they are defined in. This means they aren't nested like you are referencing them, they are all on the root widget (SelectorPopup or LabeledCheckbox)

所以而不是(从 SelectorPopup 中):

So instead of (from within SelectorPopup):

self.ids.inside.options.choices

你会:

self.ids.choices

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

This also means that widgets added dynamically aren't going to be present in the ids dictionary, but they don't really need to be. Since you are creating them in code, you can just save references to them yourself (which is harder to do with .kv).

话虽如此,使用 ListView 显示您的项目列表.

All that being said, it might be a lot easier to use a ListView to display your list of items.

相关文章