Kivy:如何正确绑定下拉菜单?

Kivy: How to bind dropdown opening properly?

我正在努力使 DropDown 打开正确绑定到选择按钮的释放。我试过使用这个:

selection_button.bind(on_release=drpdn.open)

当我创建多个 DropDown 时,绑定似乎相当随机地工作(一些 DropDown 打开其他不打开,我看不到其中的任何逻辑)。 然而它显示准确就像 Kivy documentation.

中的示例一样

我能够通过为 DropDown 打开创建我自己的回调函数来解决这个问题,我在其中传递选择按钮和 DropDown 实例(使用 functools.partial)并通过以下方式简单地打开 DropDown:

def open_dropdown(self, wid, drpdn, *largs):
    drpdn.open(wid)

虽然这个解决方法有效,但它确实让我很困扰,因为我显然没有正确理解绑定和回调的工作原理。谁能指出我正确的方向?我预计 selection_button.bind(on_release=drpdn.open) 将选择按钮传递给 DropDown 打开方法,DropDown 在其上打开,但显然它没有。最令人难以置信的是它似乎随机工作(例如,当我创建四个选择按钮时,其中一些会工作)。

这是我的测试应用程序代码。 create_dropdown 方法完美运行,而 create_dropdown2 方法会导致奇怪的行为(实际上只有最后一个 DropDown 打开)。

from functools import partial
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout


class TestApp(App):

    def create_dropdown(self, text, options):
        selection_button = Button(text=text)
        drpdn = DropDown()
        for o in options:
            btn = Button(text=o, size_hint_y=None, height=44)
            btn.bind(on_release=partial(self.change_select,
                                        selection_button,
                                        btn.text
                                        )
                     )
            btn.bind(on_release=drpdn.dismiss)
            drpdn.add_widget(btn)
        selection_button.bind(on_release=partial(self.open_dropdown,
                                                 selection_button,
                                                 drpdn
                                                 )
                              )
        return selection_button

    def create_dropdown2(self, text, options):
        selection_button = Button(text=text)
        drpdn = DropDown()
        for o in options:
            btn = Button(text=o, size_hint_y=None, height=44)
            btn.bind(on_release=partial(self.change_select,
                                        selection_button,
                                        btn.text
                                        )
                     )
            btn.bind(on_release=drpdn.dismiss)
            drpdn.add_widget(btn)
        selection_button.bind(on_release=drpdn.open)
        return selection_button

    def change_select(self, wid, text, *largs):
        wid.text = text

    def open_dropdown(self, wid, drpdn, *largs):
        drpdn.open(wid)

    def build(self):
        root = BoxLayout(orientation="vertical")

        for _ in range(3):
            root.add_widget(self.create_dropdown("Works",
                                                 ["yes", "no"]
                                                 )
                            )

        for _ in range(4):
            root.add_widget(self.create_dropdown2("Does not work",
                                                  ["yes", "no"]
                                                  )
                            )

        return root


if __name__ == '__main__':
    TestApp().run()

在您的 create_dropdown2() 方法中,您将 on_release 绑定到局部变量 (drpdn)。该绑定创建了对 drpdn 的弱引用。这意味着当 drpdn 超出范围时,绑定不会阻止它被删除和垃圾收集。然后,当按钮被释放时,on_release 绑定到的方法现在是 None.

create_dropdown() 中的 partial 调用冻结了提供的参数并避免了超出范围的问题。

请注意,在文档中,dropdown 不是局部变量。