简体   繁体   中英

Referencing id of dynamically created widget in Kivy

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

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()).

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 code:

<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

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()

Questions:

1) Howto make return_selected method work?

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'

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

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 )

So instead of (from within SelectorPopup ):

self.ids.inside.options.choices

You would have:

self.ids.choices

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 ).

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM