向DropDown添加可变数量的控件 - 弱引用的对象不再存在

时间:2016-10-07 19:33:32

标签: python kivy

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

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?

修改

稍微弄清楚我的代码。我创建了一个新类&#34; globAddable&#34;用方法&#34; getID&#34; - 一个简单的返回自我 - 并将setID放在那里。然后我设置我的setID现在将self.getID()分配给一个变量,然后使用该变量作为要添加到globObjects(以前的globIDs)字典的对象。

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

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

2 个答案:

答案 0 :(得分:1)

好吧,我终于想出了这个。

我的ReferenceError不是我的方法的结果,而是我对DropDown对象实现的一个基本误解。修复只是

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

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

答案 1 :(得分:0)

2020年的答案

官方文档(Kv language Programming Guide)表示要在KV代码中添加“强”引用,例如id_name: id_name.__self__,但尚不清楚在哪里需要这样做。而且,它没有为我解决ReferenceError: weakly-referenced object no longer exists错误。

没有的工作是通过将Buildozer添加到buildozer.spec文件的hostpython3行来迫使Buildozer使用特定版本的requirements

python3==3.7.5, hostpython3==3.7.5

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

这笔款项记入the beautiful answer from leo10011