【问题标题】:Kivy Dropdown not opening in ScreenManager but open in screenKivy Dropdown 未在 ScreenManager 中打开但在屏幕中打开
【发布时间】:2019-06-13 09:34:01
【问题描述】:

我无法让 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: 对于发现此问题的任何人,您可以使用微调器小部件来实现相同的功能。

【问题讨论】:

  • 请提供minimal reproducible example。并向我们​​展示不工作的代码,而不是工作的代码。
  • @JohnAnderson 代码现在应该重现该问题。
  • @BigBadCoder 尝试:mainbutton.bind(on_release= lambda *args: dropdown.open(mainbutton))

标签: python kivy


【解决方案1】:

我相信你的问题是由于垃圾收集。 __init__() 方法中的 dropdown 引用未保存(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()

【讨论】:

  • 是的,解决了它。谢谢!
  • 仍然,如果屏幕在屏幕管理器中,为什么weakref会消失,但如果它只是一个屏幕,它会保持活动状态?你对此有什么想法吗?
  • 我看到了这种行为,但仅当在 build() 方法之外调用 Mycreen() 时(即 DropDown 失败)。但是如果在build() 方法中调用MyScreen(),它就可以工作。为什么它会这样工作对我来说是个谜。
  • 实际上,经过一番测试,它似乎时不时地随机工作,有时会失败,无论MyScreen()创建发生在哪里。但我确实验证了失败是由于mainbutton 发布时dropdown 引用不存在。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-09
  • 2015-11-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多