Kivy Dropdown未在ScreenManager中打开,但在屏幕中打开

时间:2019-06-13 09:34:01

标签: python kivy

我在获取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: 对于发现此问题的任何人,您都可以使用微调控件来实现相同的功能。

1 个答案:

答案 0 :(得分:1)

我相信您的问题是由于垃圾收集造成的。 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()