首页 > 解决方案 > Kivy Dropdown 未在 ScreenManager 中打开但在屏幕中打开

问题描述

我无法让 kivy.DropDown 小部件与屏幕管理器一起使用。

我正在使用 kivy 文档提供的下拉代码,并将其添加到屏幕小部件,然后我将其添加到屏幕管理器以进行显示。以下代码应自行重现该问题。

import kivy
kivy.require('1.10.1')

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout

class MyScreen(Screen):
    def __init__(self, **kwargs):
        super(MyScreen, self).__init__(**kwargs)

        anchor = AnchorLayout()
        anchor.anchor_x = "center"
        anchor.anchor_y = "center"
        anchor.size = self.size
        anchor.pos = self.pos

        dropdown = DropDown()
        for index in range(10):
            # When adding widgets, we need to specify the height manually
            # (disabling the size_hint_y) so the dropdown can calculate
            # the area it needs.

            btn = Button(text='Value %d' % index, size_hint_y=None, height=44)

            # for each button, attach a callback that will call the select() method
            # on the dropdown. We'll pass the text of the button as the data of the
            # selection.
            btn.bind(on_release=lambda btn: dropdown.select(btn.text))

            # then add the button inside the dropdown
            dropdown.add_widget(btn)

        # create a big main button
        mainbutton = Button(text='Hello', size_hint=(None, None))

        # show the dropdown menu when the main button is released
        # note: all the bind() calls pass the instance of the caller (here, the
        # mainbutton instance) as the first argument of the callback (here,
        # dropdown.open.).
        mainbutton.bind(on_release=dropdown.open)

        # one last thing, listen for the selection in the dropdown list and
        # assign the data to the button text.
        dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
        anchor.add_widget(mainbutton)

        self.add_widget(anchor)

sm = ScreenManager() # transition = NoTransition())
sm.add_widget(MyScreen(name='screen'))

class MyApp(App):

    def build(self):
        return sm

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

为什么如果在 ScreenManager 中放入屏幕小部件,下拉小部件不起作用?欢迎澄清。

PS:对于发现此问题的任何人,您可以使用微调器小部件来实现相同的功能。

标签: pythonkivy

解决方案


我相信你的问题是由于垃圾收集。您的方法中的dropdown引用__init__()未保存(bind使用weakref不会阻止垃圾收集)。所以我认为你需要做的就是用一个实例变量替换你的dropdown局部变量:self.dropdown

import kivy
kivy.require('1.10.1')

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout

class MyScreen(Screen):
    def __init__(self, **kwargs):
        super(MyScreen, self).__init__(**kwargs)

        anchor = AnchorLayout()
        anchor.anchor_x = "center"
        anchor.anchor_y = "center"
        anchor.size = self.size
        anchor.pos = self.pos

        self.dropdown = DropDown()
        for index in range(10):
            # When adding widgets, we need to specify the height manually
            # (disabling the size_hint_y) so the dropdown can calculate
            # the area it needs.

            btn = Button(text='Value %d' % index, size_hint_y=None, height=44)

            # for each button, attach a callback that will call the select() method
            # on the dropdown. We'll pass the text of the button as the data of the
            # selection.
            btn.bind(on_release=lambda btn: self.dropdown.select(btn.text))

            # then add the button inside the dropdown
            self.dropdown.add_widget(btn)

        # create a big main button
        mainbutton = Button(text='Hello', size_hint=(None, None))

        # show the dropdown menu when the main button is released
        # note: all the bind() calls pass the instance of the caller (here, the
        # mainbutton instance) as the first argument of the callback (here,
        # dropdown.open.).
        mainbutton.bind(on_release=self.dropdown.open)

        # one last thing, listen for the selection in the dropdown list and
        # assign the data to the button text.
        self.dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
        anchor.add_widget(mainbutton)

        self.add_widget(anchor)

sm = ScreenManager() # transition = NoTransition())
sm.add_widget(MyScreen(name='screen'))

class MyApp(App):

    def build(self):
        return sm

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

推荐阅读