python-3.x kivy自定义小部件中存在未知app.root.function?

hrirmatl  于 2022-11-19  发布在  Python
关注(0)|答案(2)|浏览(117)

我正在学习Kivy,但我不明白为什么add_key()函数可以和Checkbox一起使用,而不能和Spinner一起使用?
我得到:属性错误:'NoneType'对象没有属性'add_key'?
两个自定义小部件的结构看起来是一样的,add_key函数必须存储在“MainWidget”中。奇怪的是,它可以和复选框一起工作,但不能和微调器一起工作?!
对应于我的问题的最小代码:

from kivy.app import App 
from kivy.uix.screenmanager import Screen
from kivy.lang import Builder

selection = {}

pizza = ["margarita", "vegetarian", "american", "3 cheeses"]

KV="""
<Selection@BoxLayout>:
    orientation: "horizontal"
    label_txt: ""
    key_name: ""
    Label:
        text: root.label_txt
    Spinner:
        id: spin_id
        text: ""
        on_text: app.root.add_key(root.key_name, self.text)

<Radio_op@BoxLayout>:
    orientation: "horizontal"
    op: ""
    label_op: ""
    Label:
        text: root.label_op
    CheckBox:
        group:"topping"
        on_active: app.root.add_key("topping", root.op)

<MainScreen>:
    BoxLayout:
        orientation: "vertical"
        Selection:
            id: pizza_sel
            label_txt: "pizza"
            key_name: "pizza"
        Label: 
            text: "Choose topping:"
        BoxLayout:
            orientation: "horizontal"
            Radio_op:
                label_op:"cream"
                op: "cream"
            Radio_op:
                label_op:"cheese"
                op: "cheese"
            Radio_op:
                label_op:"tomatoes"
                op: "tomatoes"
        BoxLayout:
            Label:
                id: pizza_lbl
            Label:
                id: topping_lbl
"""

class MainScreen(Screen):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)
        self.ids.pizza_sel.ids.spin_id.text   = pizza[0]
        self.ids.pizza_sel.ids.spin_id.values = pizza

    def add_key(self, name, text):
        selection[name] = text
        #self.ids.pizza_lbl.text = selection["pizza"]
        self.ids.topping_lbl.text = selection["topping"]

Builder.load_string(KV)

class MyApp(App):
    def build(self):
        return MainScreen()

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

错误代码:

File "c:\Users\florian\Desktop\Local\Scripts python\Utilitaire de puissance V3\help.py", line 76, in <module>
     MyApp().run()
   File "C:\Users\florian\Anaconda3\lib\site-packages\kivy\app.py", line 954, in run
     self._run_prepare()
   File "C:\Users\florian\Anaconda3\lib\site-packages\kivy\app.py", line 924, in _run_prepare
     root = self.build()
   File "c:\Users\florian\Desktop\Local\Scripts python\Utilitaire de puissance V3\help.py", line 73, in build
     return MainScreen()
   File "c:\Users\florian\Desktop\Local\Scripts python\Utilitaire de puissance V3\help.py", line 61, in __init__
     self.ids.pizza_sel.ids.spin_id.text   = pizza[0]
   File "kivy\weakproxy.pyx", line 35, in kivy.weakproxy.WeakProxy.__setattr__
   File "kivy\properties.pyx", line 520, in kivy.properties.Property.__set__
   File "kivy\properties.pyx", line 567, in kivy.properties.Property.set
   File "kivy\properties.pyx", line 606, in kivy.properties.Property._dispatch
   File "kivy\_event.pyx", line 1307, in kivy._event.EventObservers.dispatch
   File "kivy\_event.pyx", line 1189, in kivy._event.EventObservers._dispatch
   File "C:\Users\florian\Anaconda3\lib\site-packages\kivy\lang\builder.py", line 55, in custom_callback
     exec(__kvlang__.co_value, idmap)
   File "<string>", line 11, in <module>
 AttributeError: 'NoneType' object has no attribute 'add_key'

当我注解Spinner on_text属性时,复选框工作正常:

拜托,谁能解释一下为什么?谢谢。

whlutmcx

whlutmcx1#

创建MainScreen对象时,尚未设置app.root属性。并且由于您正在MainScreen构造函数中设置Spinner的text属性:

self.ids.pizza_sel.ids.spin_id.text   = pizza[0]

在设置app.root之前调用Spinner的on_text事件,这就是为什么会出现异常。在这个阶段,app.root仍然设置为None。
不要在构造函数中设置spin_id.text,而要在KV定义中设置它。

#self.ids.pizza_sel.ids.spin_id.text   = pizza[0]

Spinner:
    id: spin_id
    text: "margarita"

您还可以将比萨饼列表添加为MyApp类属性:

class MyApp(App):
    def __init__(self):
        super(MyApp, self).__init__()
        self.pizza = pizza

然后,您将能够在KV定义中设置微调器文本和值,如下所示:

Spinner:
    id: spin_id
    text: app.pizza[0]
    values: app.pizza

这样你就可以完全删除MainScreen构造函数:

class MainScreen(Screen):
    # def __init__(self, **kwargs):
    #     super(MainScreen, self).__init__(**kwargs)
    #     self.ids.pizza_sel.ids.spin_id.values = pizza
    #     self.ids.pizza_sel.ids.spin_id.text   = pizza[0]
cwdobuhd

cwdobuhd2#

谢谢你的回答。
但是使用自定义小部件的要点是使用与其他列表相同的微调器。如果我想用比如说汉堡列表来替换比萨饼列表呢?[鸡肉,美国,素食...]。我的目标是有一个KV文件:

BoxLayout:
    Selection:
     id: choose_pizza
     label_txt: "Choose a pizza"
     spin_values: app.pizza_list

    Selection:
     id: choose_burger
     label_txt: "Choose a burger"
     spin_values: app.burger_list

这是一个最简单的例子。但是想象一下,如果我有一长串的食物(薯条、饮料等),我想避免复制/粘贴完整的自定义小部件?控制“选择”只有3个参数?(标签_txt,值),初始微调器。文本总是值[0]?

相关问题