【问题标题】:Adding variable number of controls to DropDown - weakly-referenced object no longer exists向 DropDown 添加可变数量的控件 - 弱引用对象不再存在
【发布时间】:2016-10-07 19:33:32
【问题描述】:

我有一个下拉列表,其中包含月份列表。选择月份后,我试图在第二个下拉列表中使用正确的天数动态填充按钮。当我这样做时,我得到:

ReferenceError: weakly-referenced object no longer exists

这是我的文件供参考:

main.py:

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button

globIDs = {}

class appScreen(BoxLayout):

    def dayDropPop(self, num):
        globIDs['dayDropDown'].populate(num)


class ExtDropDown(BoxLayout):
    heldValue = ''

    def setID(self, key):
        globIDs[key] = self

    def changeValue(self, sentText, parent):
        self.heldValue = sentText
        parent.text = sentText

class PriorityDropDown(ExtDropDown):
    pass

class MonthDropDown(ExtDropDown):

    def __init__(self, **kwargs):
        super(MonthDropDown, self).__init__(**kwargs)
        self.setID('monthDropDown')

    def monthSelect(self, month):
        monthDay = {'Jan': 31, 'Feb': 29, 'Mar': 31, 'Apr': 30, 'May': 31, 'Jun': 30, 'Jul': 31, 'Aug': 31, 'Sep': 30,
                    'Oct': 31, 'Nov': 30, 'Dec': 31}

        numOfDays = monthDay[month]
        appScreen().dayDropPop(numOfDays)

    def testingFurther(self):
        print()

class DayDropDown(ExtDropDown):

    def __init__(self, **kwargs):
        super(DayDropDown, self).__init__(**kwargs)
        self.setID('dayDropDown')

    def populate(self, num):

        for i in range(0, num):
            newButt = Button(text=str(num + 1))
            self.ids.drop.add_widget(newButt)

class schedulerApp(App):

    def build(self):
        return appScreen()

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

scheduler.kv:

<PriorityDropDown>:
    Button:
        id: ddRoot
        text: 'Priority'
        on_release: drop.open(ddRoot)
        size_hint_y: None
        height: root.height

    DropDown:
        id: drop
        on_parent: self.dismiss()
        on_select: root.changeValue(args[1], ddRoot)

        Button:
            text: 'Top'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'High'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Medium'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Low'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)

<MonthDropDown>:
    Button:
        id: ddRoot
        text: 'Month'
        on_release: drop.open(ddRoot)
        size_hint_y: None
        height: root.height

    DropDown:
        id: drop
        on_parent: self.dismiss()
        on_select: root.monthSelect(args[1])

        Button:
            text: 'Jan'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Feb'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Mar'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Apr'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'May'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Jun'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Jul'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Aug'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Sep'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Oct'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Nov'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)
        Button:
            text: 'Dec'
            size_hint_y: None
            height: root.height
            on_release: drop.select(self.text)

<DayDropDown>:
    height: root.height
    Button:
        id: ddRoot
        text: 'Day'
        on_release: drop.open(ddRoot)
        size_hint_y: None
        height: root.height

    DropDown:
        id: drop
        on_parent: self.dismiss()
        on_select: root.changeValue(args[1], ddRoot)

<appScreen>:
    orientation: 'vertical'
    Label:
        size_hint_y: .1
        text: 'Hello World'
    GridLayout:
        size_hint_y:.1
        width: root.width
        cols: 3
        Button:
        Button:
        Button:
    ScrollView:
        canvas.before:
            Color:
                rgba: .3, .3, .3, 5
            Rectangle:
                pos: self.pos
                size: self.size
        GridLayout:
            cols: 3
            Label:
                id: textReceiver
                text: 'Words'
                text_size: self.size
                halign: 'left'
                valign: 'top'
            Label:
            Label:
    BoxLayout:
        size_hint_y: .125
        TextInput:
            size_hint_x: .7
        PriorityDropDown:
            size_hint_x: .3
    BoxLayout:
        size_hint_y: .125
        MonthDropDown:
            size_hint_x: .35
        DayDropDown:
            id: 'dayDrop'
            size_hint_y: 1
            size_hint_x: .2
        TextInput:
            size_hint_x: .45

我认为这个问题源于有问题的控件是在 Kivy 代码中创建的,而不是在 Python 中。我所做的测试使我相信我错误地引用了我的 DayDropDown 小部件。但是,我不知道我该怎么做。考虑到这一点,我将如何使用我已有的内容来引用我的 DayDropDown?如果这不是我的问题,还有什么可能导致 ReferenceError 被抛出?

编辑:

我的代码有点乱。我用方法“getID”创建了一个新类“globAddable” - 一个简单的返回自我 - 并将 setID 放在那里。然后我设置我的 setID 现在将 self.getID() 分配给一个变量,然后将该变量用作要添加到 globObjects(以前称为 globIDs)字典的对象。

我还为我的 DropDown 对象创建了一个名为 ExtDropArray 的新类,它位于我的 DayDropDown 中。我将 populate() 方法移到这个新类中,以便可以直接由 Dropdown 调用,而不是其父 BoxLayout。我让 ExtDropArray 和 ExtDropDown 继承自 globAddable 以公开 setID(和隐式 getID)方法。

这一切的最终结果是完全一样的。单击 DayDropDown 上的按钮时,我仍然看不到我的一天 DropDown,并且在使用 MonthDropDown 上的不同值进行测试后,我再次收到“ReferenceError:弱引用对象不再存在”错误。但是,我注意到有问题的行实际上是打开下拉列表的方法(drop.open(ddRoot),在我的 .kv 文件的第 114 行调用)。这仍然没有给我足够的信息来了解导致错误的过程的哪一部分,无论是将按钮添加到 DropDown 还是只是调用 open 方法。鉴于这些新信息,是否有人能够推断出需要更改的内容?

【问题讨论】:

    标签: python kivy


    【解决方案1】:

    好吧,我终于想通了。

    我的 ReferenceError 不是我的方法的结果,而是我对 DropDown 对象实现的根本误解。修复很简单

    <DayDropDown>:
        drop: drop.__self__
        ...
    

    这花了我很长时间才找到,但以this 文档的形式出现。由于没有其他提及这些 ReferenceErrors 的帖子提及此文档,因此我将其留在这里供其他人使用,以防他们遇到类似问题。

    【讨论】:

      【解决方案2】:

      2020 年的答案

      官方文档 (Kv language Programming Guide) 说要在 KV 代码中添加“强”引用,例如 id_name: id_name.__self__,但不清楚这在哪里是必要的。更重要的是,它并没有为我解决 ReferenceError: weakly-referenced object no longer exists 错误。

      所做的工作是通过将其添加到 buildozer.spec 文件的 requirements 行来强制 Buildozer 使用特定版本的 hostpython3

      python3==3.7.5, hostpython3==3.7.5
      

      还有一点注意:在将上述内容添加到 requirements 之后,我返回并删除了我所有的 __self__ 引用,它仍然可以正常工作,因此显然 Kivy KV 语言不再需要这些。

      这归功于the beautiful answer from leo10011

      【讨论】:

        猜你喜欢
        • 2023-04-04
        • 2018-08-28
        • 2016-10-01
        • 1970-01-01
        • 2020-07-19
        • 1970-01-01
        • 1970-01-01
        • 2010-12-01
        • 2020-12-01
        相关资源
        最近更新 更多